1 /**
2  * Semantic analysis of expressions.
3  *
4  * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5  *
6  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expressionsem.d, _expressionsem.d)
10  * Documentation:  https://dlang.org/phobos/dmd_expressionsem.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expressionsem.d
12  */
13 
14 module dmd.expressionsem;
15 
16 import core.stdc.stdio;
17 
18 import dmd.access;
19 import dmd.aggregate;
20 import dmd.aliasthis;
21 import dmd.arrayop;
22 import dmd.arraytypes;
23 import dmd.attrib;
24 import dmd.astcodegen;
25 import dmd.astenums;
26 import dmd.canthrow;
27 import dmd.chkformat;
28 import dmd.ctorflow;
29 import dmd.dscope;
30 import dmd.dsymbol;
31 import dmd.declaration;
32 import dmd.dclass;
33 import dmd.dcast;
34 import dmd.delegatize;
35 import dmd.denum;
36 import dmd.dimport;
37 import dmd.dinterpret;
38 import dmd.dmangle;
39 import dmd.dmodule;
40 import dmd.dstruct;
41 import dmd.dsymbolsem;
42 import dmd.dtemplate;
43 import dmd.errors;
44 import dmd.errorsink;
45 import dmd.escape;
46 import dmd.expression;
47 import dmd.file_manager;
48 import dmd.func;
49 import dmd.globals;
50 import dmd.hdrgen;
51 import dmd.id;
52 import dmd.identifier;
53 import dmd.imphint;
54 import dmd.importc;
55 import dmd.init;
56 import dmd.initsem;
57 import dmd.inline;
58 import dmd.intrange;
59 import dmd.location;
60 import dmd.mtype;
61 import dmd.mustuse;
62 import dmd.nspace;
63 import dmd.objc;
64 import dmd.opover;
65 import dmd.optimize;
66 import dmd.parse;
67 import dmd.printast;
68 import dmd.postordervisitor;
69 import dmd.root.array;
70 import dmd.root.ctfloat;
71 import dmd.root.filename;
72 import dmd.common.outbuffer;
73 import dmd.rootobject;
74 import dmd.root.string;
75 import dmd.root.utf;
76 import dmd.semantic2;
77 import dmd.semantic3;
78 import dmd.sideeffect;
79 import dmd.safe;
80 import dmd.target;
81 import dmd.tokens;
82 import dmd.traits;
83 import dmd.typesem;
84 import dmd.typinf;
85 import dmd.utils;
86 import dmd.visitor;
87 
88 enum LOGSEMANTIC = false;
89 
90 /********************************************************
91  * Perform semantic analysis and CTFE on expressions to produce
92  * a string.
93  * Params:
94  *      buf = append generated string to buffer
95  *      sc = context
96  *      exps = array of Expressions
97  * Returns:
98  *      true on error
99  */
100 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
101 {
102     if (!exps)
103         return false;
104 
105     foreach (ex; *exps)
106     {
107         if (!ex)
108             continue;
109         auto sc2 = sc.startCTFE();
110         sc2.tinst = null;
111         sc2.minst = null;       // prevents emission of any instantiated templates to object file
112         auto e2 = ex.expressionSemantic(sc2);
113         auto e3 = resolveProperties(sc2, e2);
114         sc2.endCTFE();
115 
116         // allowed to contain types as well as expressions
117         auto e4 = ctfeInterpretForPragmaMsg(e3);
118         if (!e4 || e4.op == EXP.error)
119             return true;
120 
121         // expand tuple
122         if (auto te = e4.isTupleExp())
123         {
124             if (expressionsToString(buf, sc, te.exps))
125                 return true;
126             continue;
127         }
128         // char literals exp `.toStringExp` return `null` but we cant override it
129         // because in most contexts we don't want the conversion to succeed.
130         IntegerExp ie = e4.isIntegerExp();
131         const ty = (ie && ie.type) ? ie.type.ty : Terror;
132         if (ty.isSomeChar)
133         {
134             auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
135             e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
136         }
137 
138         if (StringExp se = e4.toStringExp())
139             buf.writestring(se.toUTF8(sc).peekString());
140         else
141             buf.writestring(e4.toString());
142     }
143     return false;
144 }
145 
146 /*****************************************
147  * Determine if `this` is available by walking up the enclosing
148  * scopes until a function is found.
149  *
150  * Params:
151  *      sc = where to start looking for the enclosing function
152  * Returns:
153  *      Found function if it satisfies `isThis()`, otherwise `null`
154  */
155 FuncDeclaration hasThis(Scope* sc)
156 {
157     //printf("hasThis()\n");
158     Dsymbol p = sc.parent;
159     while (p && p.isTemplateMixin())
160         p = p.parent;
161     FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
162     //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
163 
164     // Go upwards until we find the enclosing member function
165     FuncDeclaration fd = fdthis;
166     while (1)
167     {
168         if (!fd)
169         {
170             return null;
171         }
172         if (!fd.isNested() || fd.isThis() || (fd.hasDualContext() && fd.isMember2()))
173             break;
174 
175         Dsymbol parent = fd.parent;
176         while (1)
177         {
178             if (!parent)
179                 return null;
180             TemplateInstance ti = parent.isTemplateInstance();
181             if (ti)
182                 parent = ti.parent;
183             else
184                 break;
185         }
186         fd = parent.isFuncDeclaration();
187     }
188 
189     if (!fd.isThis() && !(fd.hasDualContext() && fd.isMember2()))
190     {
191         return null;
192     }
193 
194     assert(fd.vthis);
195     return fd;
196 
197 }
198 
199 /***********************************************************
200  * Resolve `exp` as a compile-time known string.
201  * Params:
202  *  sc  = scope
203  *  exp = Expression which expected as a string
204  *  s   = What the string is expected for, will be used in error diagnostic.
205  * Returns:
206  *  String literal, or `null` if error happens.
207  */
208 StringExp semanticString(Scope *sc, Expression exp, const char* s)
209 {
210     sc = sc.startCTFE();
211     exp = exp.expressionSemantic(sc);
212     exp = resolveProperties(sc, exp);
213     sc = sc.endCTFE();
214 
215     if (exp.op == EXP.error)
216         return null;
217 
218     auto e = exp;
219     if (exp.type.isString())
220     {
221         e = e.ctfeInterpret();
222         if (e.op == EXP.error)
223             return null;
224     }
225 
226     auto se = e.toStringExp();
227     if (!se)
228     {
229         error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
230             s, exp.toChars(), exp.type.toChars());
231         return null;
232     }
233     return se;
234 }
235 
236 /****************************************
237  * Convert string to char[].
238  */
239 StringExp toUTF8(StringExp se, Scope* sc)
240 {
241     if (se.sz != 1)
242     {
243         // Convert to UTF-8 string
244         se.committed = false;
245         Expression e = castTo(se, sc, Type.tchar.arrayOf());
246         e = e.optimize(WANTvalue);
247         auto result = e.isStringExp();
248         assert(result.sz == 1);
249         return result;
250     }
251     return se;
252 }
253 
254 private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
255 {
256     BinExp be = exp;
257 
258     auto ie = be.e1.isIndexExp();
259     if (!ie)
260         return be;
261     if (ie.e1.type.toBasetype().ty != Taarray)
262         return be;
263 
264     /* Fix evaluation order of setting AA element
265      * https://issues.dlang.org/show_bug.cgi?id=3825
266      * Rewrite:
267      *     aa[k1][k2][k3] op= val;
268      * as:
269      *     auto ref __aatmp = aa;
270      *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
271      *     auto ref __aaval = val;
272      *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
273      */
274 
275     Expression e0;
276     while (1)
277     {
278         Expression de;
279         ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
280         e0 = Expression.combine(de, e0);
281 
282         auto ie1 = ie.e1.isIndexExp();
283         if (!ie1 ||
284             ie1.e1.type.toBasetype().ty != Taarray)
285         {
286             break;
287         }
288         ie = ie1;
289     }
290     assert(ie.e1.type.toBasetype().ty == Taarray);
291 
292     Expression de;
293     ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
294     e0 = Expression.combine(de, e0);
295 
296     be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
297 
298     //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
299     return Expression.combine(e0, be);
300 }
301 
302 
303 private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
304 {
305     auto e1 = binExp.e1;
306     auto e2 = binExp.e2;
307     auto op = binExp.op;
308     auto type = binExp.type;
309     auto loc = binExp.loc;
310 
311     // At that point t1 and t2 are the merged types. type is the original type of the lhs.
312     Type t1 = e1.type;
313     Type t2 = e2.type;
314 
315     // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
316     // See https://issues.dlang.org/show_bug.cgi?id=3841.
317     // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
318     if (op == EXP.addAssign || op == EXP.minAssign ||
319         op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
320         op == EXP.powAssign)
321     {
322         if ((type.isintegral() && t2.isfloating()))
323         {
324             warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
325         }
326     }
327 
328     // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
329     if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
330     {
331         // Any multiplication by an imaginary or complex number yields a complex result.
332         // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
333         const(char)* opstr = EXPtoString(op).ptr;
334         if (t1.isreal() && t2.iscomplex())
335         {
336             error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
337             return ErrorExp.get();
338         }
339         else if (t1.isimaginary() && t2.iscomplex())
340         {
341             error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
342             return ErrorExp.get();
343         }
344         else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
345         {
346             error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
347             return ErrorExp.get();
348         }
349     }
350 
351     // generate an error if this is a nonsensical += or -=, eg real += imaginary
352     if (op == EXP.addAssign || op == EXP.minAssign)
353     {
354         // Addition or subtraction of a real and an imaginary is a complex result.
355         // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
356         if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
357         {
358             error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
359             return ErrorExp.get();
360         }
361         if (type.isreal() || type.isimaginary())
362         {
363             assert(global.errors || t2.isfloating());
364             e2 = e2.castTo(sc, t1);
365         }
366     }
367     if (op == EXP.mulAssign)
368     {
369         if (t2.isfloating())
370         {
371             if (t1.isreal())
372             {
373                 if (t2.isimaginary() || t2.iscomplex())
374                 {
375                     e2 = e2.castTo(sc, t1);
376                 }
377             }
378             else if (t1.isimaginary())
379             {
380                 if (t2.isimaginary() || t2.iscomplex())
381                 {
382                     switch (t1.ty)
383                     {
384                     case Timaginary32:
385                         t2 = Type.tfloat32;
386                         break;
387 
388                     case Timaginary64:
389                         t2 = Type.tfloat64;
390                         break;
391 
392                     case Timaginary80:
393                         t2 = Type.tfloat80;
394                         break;
395 
396                     default:
397                         assert(0);
398                     }
399                     e2 = e2.castTo(sc, t2);
400                 }
401             }
402         }
403     }
404     else if (op == EXP.divAssign)
405     {
406         if (t2.isimaginary())
407         {
408             if (t1.isreal())
409             {
410                 // x/iv = i(-x/v)
411                 // Therefore, the result is 0
412                 e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
413                 e2.type = t1;
414                 Expression e = new AssignExp(loc, e1, e2);
415                 e.type = t1;
416                 return e;
417             }
418             else if (t1.isimaginary())
419             {
420                 Type t3;
421                 switch (t1.ty)
422                 {
423                 case Timaginary32:
424                     t3 = Type.tfloat32;
425                     break;
426 
427                 case Timaginary64:
428                     t3 = Type.tfloat64;
429                     break;
430 
431                 case Timaginary80:
432                     t3 = Type.tfloat80;
433                     break;
434 
435                 default:
436                     assert(0);
437                 }
438                 e2 = e2.castTo(sc, t3);
439                 Expression e = new AssignExp(loc, e1, e2);
440                 e.type = t1;
441                 return e;
442             }
443         }
444     }
445     else if (op == EXP.modAssign)
446     {
447         if (t2.iscomplex())
448         {
449             error(loc, "cannot perform modulo complex arithmetic");
450             return ErrorExp.get();
451         }
452     }
453     return binExp;
454 }
455 
456 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
457 {
458     Expression e0;
459     Expression e1 = Expression.extractLast(ue.e1, e0);
460     // https://issues.dlang.org/show_bug.cgi?id=12585
461     // Extract the side effect part if ue.e1 is comma.
462 
463     if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
464     {
465         /* Even if opDollar is needed, 'e1' should be evaluate only once. So
466          * Rewrite:
467          *      e1.opIndex( ... use of $ ... )
468          *      e1.opSlice( ... use of $ ... )
469          * as:
470          *      (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
471          *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
472          */
473         e1 = extractSideEffect(sc, "__dop", e0, e1, false);
474         assert(e1.isVarExp());
475         e1.isVarExp().var.storage_class |= STC.exptemp;     // lifetime limited to expression
476     }
477     ue.e1 = e1;
478     return e0;
479 }
480 
481 /**************************************
482  * Runs semantic on ae.arguments. Declares temporary variables
483  * if '$' was used.
484  */
485 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
486 {
487     assert(!ae.lengthVar);
488     *pe0 = null;
489     AggregateDeclaration ad = isAggregate(ae.e1.type);
490     Dsymbol slice = search_function(ad, Id.slice);
491     //printf("slice = %s %s\n", slice.kind(), slice.toChars());
492     foreach (i, e; *ae.arguments)
493     {
494         if (i == 0)
495             *pe0 = extractOpDollarSideEffect(sc, ae);
496 
497         if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
498         {
499         Lfallback:
500             if (ae.arguments.length == 1)
501                 return null;
502             error(ae.loc, "multi-dimensional slicing requires template `opSlice`");
503             return ErrorExp.get();
504         }
505         //printf("[%d] e = %s\n", i, e.toChars());
506 
507         // Create scope for '$' variable for this dimension
508         auto sym = new ArrayScopeSymbol(sc, ae);
509         sym.parent = sc.scopesym;
510         sc = sc.push(sym);
511         ae.lengthVar = null; // Create it only if required
512         ae.currentDimension = i; // Dimension for $, if required
513 
514         e = e.expressionSemantic(sc);
515         e = resolveProperties(sc, e);
516 
517         if (ae.lengthVar && sc.func)
518         {
519             // If $ was used, declare it now
520             Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
521             de = de.expressionSemantic(sc);
522             *pe0 = Expression.combine(*pe0, de);
523         }
524         sc = sc.pop();
525 
526         if (auto ie = e.isIntervalExp())
527         {
528             auto tiargs = new Objects();
529             Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
530             edim = edim.expressionSemantic(sc);
531             tiargs.push(edim);
532 
533             auto fargs = new Expressions(2);
534             (*fargs)[0] = ie.lwr;
535             (*fargs)[1] = ie.upr;
536 
537             uint xerrors = global.startGagging();
538             sc = sc.push();
539             FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
540             sc = sc.pop();
541             global.endGagging(xerrors);
542             if (!fslice)
543                 goto Lfallback;
544 
545             e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
546             e = new CallExp(ae.loc, e, fargs);
547             e = e.expressionSemantic(sc);
548         }
549 
550         if (!e.type)
551         {
552             error(ae.loc, "`%s` has no value", e.toChars());
553             e = ErrorExp.get();
554         }
555         if (e.op == EXP.error)
556             return e;
557 
558         (*ae.arguments)[i] = e;
559     }
560     return ae;
561 }
562 
563 /**************************************
564  * Runs semantic on se.lwr and se.upr. Declares a temporary variable
565  * if '$' was used.
566  * Returns:
567  *      ae, or ErrorExp if errors occurred
568  */
569 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
570 {
571     //assert(!ae.lengthVar);
572     if (!ie)
573         return ae;
574 
575     VarDeclaration lengthVar = ae.lengthVar;
576     bool errors = false;
577 
578     // create scope for '$'
579     auto sym = new ArrayScopeSymbol(sc, ae);
580     sym.parent = sc.scopesym;
581     sc = sc.push(sym);
582 
583     Expression sem(Expression e)
584     {
585         e = e.expressionSemantic(sc);
586         e = resolveProperties(sc, e);
587         if (!e.type)
588         {
589             error(ae.loc, "`%s` has no value", e.toChars());
590             errors = true;
591         }
592         return e;
593     }
594 
595     ie.lwr = sem(ie.lwr);
596     ie.upr = sem(ie.upr);
597 
598     if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
599         errors = true;
600 
601     if (lengthVar != ae.lengthVar && sc.func)
602     {
603         // If $ was used, declare it now
604         Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
605         de = de.expressionSemantic(sc);
606         *pe0 = Expression.combine(*pe0, de);
607     }
608 
609     sc = sc.pop();
610 
611     return errors ? ErrorExp.get() : ae;
612 }
613 
614 /******************************
615  * Perform semantic() on an array of Expressions.
616  */
617 extern(D) bool arrayExpressionSemantic(
618     Expression[] exps, Scope* sc, bool preserveErrors = false)
619 {
620     bool err = false;
621     foreach (ref e; exps)
622     {
623         if (e is null) continue;
624         auto e2 = e.expressionSemantic(sc);
625         if (e2.op == EXP.error)
626             err = true;
627         if (preserveErrors || e2.op != EXP.error)
628             e = e2;
629     }
630     return err;
631 }
632 
633 /************************************************
634  * Handle the postblit call on lvalue, or the move of rvalue.
635  *
636  * Params:
637  *   sc = the scope where the expression is encountered
638  *   e = the expression the needs to be moved or copied (source)
639  *   t = if the struct defines a copy constructor, the type of the destination
640  *
641  * Returns:
642  *  The expression that copy constructs or moves the value.
643  */
644 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
645 {
646     if (auto ce = e.isCondExp())
647     {
648         ce.e1 = doCopyOrMove(sc, ce.e1);
649         ce.e2 = doCopyOrMove(sc, ce.e2);
650     }
651     else
652     {
653         e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
654     }
655     return e;
656 }
657 
658 /*********************************************
659  * If e is an instance of a struct, and that struct has a copy constructor,
660  * rewrite e as:
661  *    (tmp = e),tmp
662  * Input:
663  *      sc = just used to specify the scope of created temporary variable
664  *      destinationType = the type of the object on which the copy constructor is called;
665  *                        may be null if the struct defines a postblit
666  */
667 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
668 {
669     if (auto ts = e.type.baseElemOf().isTypeStruct())
670     {
671         StructDeclaration sd = ts.sym;
672         if (sd.postblit || sd.hasCopyCtor)
673         {
674             /* Create a variable tmp, and replace the argument e with:
675              *      (tmp = e),tmp
676              * and let AssignExp() handle the construction.
677              * This is not the most efficient, ideally tmp would be constructed
678              * directly onto the stack.
679              */
680             auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
681             if (sd.hasCopyCtor && destinationType)
682             {
683                 // https://issues.dlang.org/show_bug.cgi?id=22619
684                 // If the destination type is inout we can preserve it
685                 // only if inside an inout function; if we are not inside
686                 // an inout function, then we will preserve the type of
687                 // the source
688                 if (destinationType.hasWild && !(sc.func.storage_class & STC.wild))
689                     tmp.type = e.type;
690                 else
691                     tmp.type = destinationType;
692             }
693             tmp.storage_class |= STC.nodtor;
694             tmp.dsymbolSemantic(sc);
695             Expression de = new DeclarationExp(e.loc, tmp);
696             Expression ve = new VarExp(e.loc, tmp);
697             de.type = Type.tvoid;
698             ve.type = e.type;
699             return Expression.combine(de, ve);
700         }
701     }
702     return e;
703 }
704 
705 /************************************************
706  * If we want the value of this expression, but do not want to call
707  * the destructor on it.
708  */
709 Expression valueNoDtor(Expression e)
710 {
711     auto ex = lastComma(e);
712 
713     if (auto ce = ex.isCallExp())
714     {
715         /* The struct value returned from the function is transferred
716          * so do not call the destructor on it.
717          * Recognize:
718          *       ((S _ctmp = S.init), _ctmp).this(...)
719          * and make sure the destructor is not called on _ctmp
720          * BUG: if ex is a CommaExp, we should go down the right side.
721          */
722         if (auto dve = ce.e1.isDotVarExp())
723         {
724             if (dve.var.isCtorDeclaration())
725             {
726                 // It's a constructor call
727                 if (auto comma = dve.e1.isCommaExp())
728                 {
729                     if (auto ve = comma.e2.isVarExp())
730                     {
731                         VarDeclaration ctmp = ve.var.isVarDeclaration();
732                         if (ctmp)
733                         {
734                             ctmp.storage_class |= STC.nodtor;
735                             assert(!ce.isLvalue());
736                         }
737                     }
738                 }
739             }
740         }
741     }
742     else if (auto ve = ex.isVarExp())
743     {
744         auto vtmp = ve.var.isVarDeclaration();
745         if (vtmp && (vtmp.storage_class & STC.rvalue))
746         {
747             vtmp.storage_class |= STC.nodtor;
748         }
749     }
750     return e;
751 }
752 
753 /*
754 Checks if `exp` contains a direct access to a `noreturn`
755 variable. If that is the case, an `assert(0)` expression
756 is generated and returned. This function should be called
757 only after semantic analysis has been performed on `exp`.
758 
759 Params:
760     exp = expression that is checked
761 
762 Returns:
763     An `assert(0)` expression if `exp` contains a `noreturn`
764     variable access, `exp` otherwise.
765 */
766 
767 Expression checkNoreturnVarAccess(Expression exp)
768 {
769     assert(exp.type);
770 
771     Expression result = exp;
772     if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
773         !exp.isThrowExp() && !exp.isCallExp())
774     {
775         auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
776         msg.type = Type.tstring;
777         result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
778         result.type = exp.type;
779     }
780 
781     return result;
782 }
783 
784 /******************************
785  * Find symbol in accordance with the UFCS name look up rule
786  */
787 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
788 {
789     //printf("searchUFCS(ident = %s)\n", ident.toChars());
790     Loc loc = ue.loc;
791 
792     // TODO: merge with Scope.search.searchScopes()
793     Dsymbol searchScopes(int flags)
794     {
795         Dsymbol s = null;
796         for (Scope* scx = sc; scx; scx = scx.enclosing)
797         {
798             if (!scx.scopesym)
799                 continue;
800             if (scx.scopesym.isModule())
801                 flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
802             s = scx.scopesym.search(loc, ident, flags);
803             if (s)
804             {
805                 // overload set contains only module scope symbols.
806                 if (s.isOverloadSet())
807                     break;
808                 // selective/renamed imports also be picked up
809                 if (AliasDeclaration ad = s.isAliasDeclaration())
810                 {
811                     if (ad._import)
812                         break;
813                 }
814                 // See only module scope symbols for UFCS target.
815                 Dsymbol p = s.toParent2();
816                 if (p && p.isModule())
817                     break;
818             }
819             s = null;
820 
821             // Stop when we hit a module, but keep going if that is not just under the global scope
822             if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
823                 break;
824         }
825         return s;
826     }
827 
828     int flags = 0;
829     Dsymbol s;
830 
831     if (sc.flags & SCOPE.ignoresymbolvisibility)
832         flags |= IgnoreSymbolVisibility;
833 
834     // First look in local scopes
835     s = searchScopes(flags | SearchLocalsOnly);
836     if (!s)
837     {
838         // Second look in imported modules
839         s = searchScopes(flags | SearchImportsOnly);
840     }
841 
842     if (!s)
843         return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
844 
845     FuncDeclaration f = s.isFuncDeclaration();
846     if (f)
847     {
848         TemplateDeclaration td = getFuncTemplateDecl(f);
849         if (td)
850         {
851             if (td.overroot)
852                 td = td.overroot;
853             s = td;
854         }
855     }
856 
857     if (auto dti = ue.isDotTemplateInstanceExp())
858     {
859         // https://issues.dlang.org/show_bug.cgi?id=23968
860         // Typically, deprecated alias declarations are caught
861         // when `TemplateInstance.findTempDecl` is called,
862         // however, in this case the tempdecl field is updated
863         // therefore `findTempDecl` will return immediately
864         // and not get the chance to issue the deprecation.
865         if (s.isAliasDeclaration())
866             s.checkDeprecated(ue.loc, sc);
867 
868         auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
869         if (!ti.updateTempDecl(sc, s))
870             return ErrorExp.get();
871         return new ScopeExp(loc, ti);
872     }
873     else
874     {
875         //printf("-searchUFCS() %s\n", s.toChars());
876         return new DsymbolExp(loc, s);
877     }
878 }
879 
880 /******************************
881  * check e is exp.opDispatch!(tiargs) or not
882  * It's used to switch to UFCS the semantic analysis path
883  */
884 private bool isDotOpDispatch(Expression e)
885 {
886     if (auto dtie = e.isDotTemplateInstanceExp())
887         return dtie.ti.name == Id.opDispatch;
888     return false;
889 }
890 
891 private void hookDtors(CondExp ce, Scope* sc)
892 {
893     extern (C++) final class DtorVisitor : StoppableVisitor
894     {
895         alias visit = typeof(super).visit;
896     public:
897         Scope* sc;
898         CondExp ce;
899         VarDeclaration vcond;
900         bool isThen;
901 
902         extern (D) this(Scope* sc, CondExp ce) @safe
903         {
904             this.sc = sc;
905             this.ce = ce;
906         }
907 
908         override void visit(Expression e)
909         {
910             //printf("(e = %s)\n", e.toChars());
911         }
912 
913         override void visit(DeclarationExp e)
914         {
915             auto v = e.declaration.isVarDeclaration();
916             if (v && !v.isDataseg())
917             {
918                 if (v._init)
919                 {
920                     if (auto ei = v._init.isExpInitializer())
921                         walkPostorder(ei.exp, this);
922                 }
923 
924                 if (v.edtor)
925                     walkPostorder(v.edtor, this);
926 
927                 if (v.needsScopeDtor())
928                 {
929                     if (!vcond)
930                     {
931                         vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
932                         vcond.dsymbolSemantic(sc);
933 
934                         Expression de = new DeclarationExp(ce.econd.loc, vcond);
935                         de = de.expressionSemantic(sc);
936 
937                         Expression ve = new VarExp(ce.econd.loc, vcond);
938                         ce.econd = Expression.combine(de, ve);
939                     }
940 
941                     //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
942                     Expression ve = new VarExp(vcond.loc, vcond);
943                     if (isThen)
944                         v.edtor = new LogicalExp(v.edtor.loc, EXP.andAnd, ve, v.edtor);
945                     else
946                         v.edtor = new LogicalExp(v.edtor.loc, EXP.orOr, ve, v.edtor);
947                     v.edtor = v.edtor.expressionSemantic(sc);
948                     //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
949                 }
950             }
951         }
952     }
953 
954     scope DtorVisitor v = new DtorVisitor(sc, ce);
955     //printf("+%s\n", toChars());
956     v.isThen = true;
957     walkPostorder(ce.e1, v);
958     v.isThen = false;
959     walkPostorder(ce.e2, v);
960     //printf("-%s\n", toChars());
961 }
962 
963 
964 /******************************
965  * Pull out callable entity with UFCS.
966  */
967 private Expression resolveUFCS(Scope* sc, CallExp ce)
968 {
969     Loc loc = ce.loc;
970     Expression eleft;
971     Expression e;
972 
973     if (auto die = ce.e1.isDotIdExp())
974     {
975         Identifier ident = die.ident;
976 
977         Expression ex = die.dotIdSemanticPropX(sc);
978         if (ex != die)
979         {
980             ce.e1 = ex;
981             return null;
982         }
983         eleft = die.e1;
984 
985         Type t = eleft.type.toBasetype();
986         if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
987         {
988             /* Built-in types and arrays have no callable properties, so do shortcut.
989              * It is necessary in: e.init()
990              */
991         }
992         else if (t.ty == Taarray)
993         {
994             if (ident == Id.remove)
995             {
996                 /* Transform:
997                  *  aa.remove(arg) into delete aa[arg]
998                  */
999                 if (!ce.arguments || ce.arguments.length != 1)
1000                 {
1001                     error(ce.loc, "expected key as argument to `aa.remove()`");
1002                     return ErrorExp.get();
1003                 }
1004                 if (!eleft.type.isMutable())
1005                 {
1006                     error(ce.loc, "cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
1007                     return ErrorExp.get();
1008                 }
1009                 Expression key = (*ce.arguments)[0];
1010                 key = key.expressionSemantic(sc);
1011                 key = resolveProperties(sc, key);
1012 
1013                 TypeAArray taa = t.isTypeAArray();
1014                 key = key.implicitCastTo(sc, taa.index);
1015 
1016                 if (key.checkValue() || key.checkSharedAccess(sc))
1017                     return ErrorExp.get();
1018 
1019                 semanticTypeInfo(sc, taa.index);
1020 
1021                 return new RemoveExp(loc, eleft, key);
1022             }
1023         }
1024         else
1025         {
1026             if (Expression ey = die.dotIdSemanticProp(sc, 1))
1027             {
1028                 if (ey.op == EXP.error)
1029                     return ey;
1030                 ce.e1 = ey;
1031                 if (isDotOpDispatch(ey))
1032                 {
1033                     // even opDispatch and UFCS must have valid arguments,
1034                     // so now that we've seen indication of a problem,
1035                     // check them for issues.
1036                     Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
1037 
1038                     uint errors = global.startGagging();
1039                     e = ce.expressionSemantic(sc);
1040                     if (!global.endGagging(errors))
1041                         return e;
1042 
1043                     if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
1044                         return ErrorExp.get();
1045 
1046                     /* fall down to UFCS */
1047                 }
1048                 else
1049                     return null;
1050             }
1051         }
1052 
1053         /* https://issues.dlang.org/show_bug.cgi?id=13953
1054          *
1055          * If a struct has an alias this to an associative array
1056          * and remove is used on a struct instance, we have to
1057          * check first if there is a remove function that can be called
1058          * on the struct. If not we must check the alias this.
1059          *
1060          * struct A
1061          * {
1062          *      string[string] a;
1063          *      alias a this;
1064          * }
1065          *
1066          * void fun()
1067          * {
1068          *      A s;
1069          *      s.remove("foo");
1070          * }
1071          */
1072         const errors = global.startGagging();
1073         e = searchUFCS(sc, die, ident);
1074         // if there were any errors and the identifier was remove
1075         if (global.endGagging(errors))
1076         {
1077             if (ident == Id.remove)
1078             {
1079                 // check alias this
1080                 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
1081                 if (alias_e && alias_e != die.e1)
1082                 {
1083                     die.e1 = alias_e;
1084                     CallExp ce2 = ce.syntaxCopy();
1085                     ce2.e1 = die;
1086                     e = ce2.isCallExp().trySemantic(sc);
1087                     if (e)
1088                         return e;
1089                 }
1090             }
1091             // if alias this did not work out, print the initial errors
1092             searchUFCS(sc, die, ident);
1093         }
1094     }
1095     else if (auto dti = ce.e1.isDotTemplateInstanceExp())
1096     {
1097         if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
1098         {
1099             ce.e1 = ey;
1100             return null;
1101         }
1102         eleft = dti.e1;
1103         e = searchUFCS(sc, dti, dti.ti.name);
1104     }
1105     else
1106         return null;
1107 
1108     // Rewrite
1109     ce.e1 = e;
1110     if (!ce.arguments)
1111         ce.arguments = new Expressions();
1112     ce.arguments.shift(eleft);
1113     if (!ce.names)
1114         ce.names = new Identifiers();
1115     ce.names.shift(null);
1116     ce.isUfcsRewrite = true;
1117     return null;
1118 }
1119 
1120 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
1121 {
1122     if (!exps || exps.length == 0)
1123         return -1;
1124 
1125     for (size_t u = starti; u < exps.length; u++)
1126     {
1127         Expression exp = (*exps)[u];
1128         if (TupleDeclaration td = exp.isAliasThisTuple)
1129         {
1130             exps.remove(u);
1131             size_t i;
1132             td.foreachVar((s)
1133             {
1134                 auto d = s.isDeclaration();
1135                 auto e = new DotVarExp(exp.loc, exp, d);
1136                 assert(d.type);
1137                 e.type = d.type;
1138                 exps.insert(u + i, e);
1139                 ++i;
1140             });
1141             version (none)
1142             {
1143                 printf("expansion ->\n");
1144                 foreach (e; exps)
1145                 {
1146                     printf("\texps[%d] e = %s %s\n", i, EXPtoString(e.op), e.toChars());
1147                 }
1148             }
1149             return cast(int)u;
1150         }
1151     }
1152     return -1;
1153 }
1154 
1155 /******************************
1156  * Pull out property with UFCS.
1157  */
1158 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
1159 {
1160     Loc loc = e1.loc;
1161     Expression eleft;
1162     Expression e;
1163 
1164     if (auto die = e1.isDotIdExp())
1165     {
1166         eleft = die.e1;
1167         e = searchUFCS(sc, die, die.ident);
1168     }
1169     else if (auto dti = e1.isDotTemplateInstanceExp())
1170     {
1171         eleft = dti.e1;
1172         e = searchUFCS(sc, dti, dti.ti.name);
1173     }
1174     else
1175         return null;
1176 
1177     if (e is null)
1178         return null;
1179 
1180     // Rewrite
1181     if (e2)
1182     {
1183         // run semantic without gagging
1184         e2 = e2.expressionSemantic(sc);
1185 
1186         /* f(e1) = e2
1187          */
1188         Expression ex = e.copy();
1189         auto a1 = new Expressions(1);
1190         (*a1)[0] = eleft;
1191         ex = new CallExp(loc, ex, a1);
1192         auto e1PassSemantic = ex.trySemantic(sc);
1193 
1194         /* f(e1, e2)
1195          */
1196         auto a2 = new Expressions(2);
1197         (*a2)[0] = eleft;
1198         (*a2)[1] = e2;
1199         e = new CallExp(loc, e, a2);
1200         e = e.trySemantic(sc);
1201         if (!e1PassSemantic && !e)
1202         {
1203             /* https://issues.dlang.org/show_bug.cgi?id=20448
1204              *
1205              * If both versions have failed to pass semantic,
1206              * f(e1) = e2 gets priority in error printing
1207              * because f might be a templated function that
1208              * failed to instantiate and we have to print
1209              * the instantiation errors.
1210              */
1211             return e1.expressionSemantic(sc);
1212         }
1213         else if (ex && !e)
1214         {
1215             ex = new AssignExp(loc, ex, e2);
1216             return ex.expressionSemantic(sc);
1217         }
1218         else
1219         {
1220             // strict setter prints errors if fails
1221             e = e.expressionSemantic(sc);
1222         }
1223         return e;
1224     }
1225     else
1226     {
1227         /* f(e1)
1228          */
1229         auto arguments = new Expressions(1);
1230         (*arguments)[0] = eleft;
1231         e = new CallExp(loc, e, arguments);
1232 
1233         // https://issues.dlang.org/show_bug.cgi?id=24017
1234         if (sc.flags & SCOPE.debug_)
1235             e.isCallExp().inDebugStatement = true;
1236 
1237         e = e.expressionSemantic(sc);
1238         return e;
1239     }
1240 }
1241 
1242 /******************************
1243  * If e1 is a property function (template), resolve it.
1244  */
1245 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
1246 {
1247     //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
1248 
1249     Expression handleOverloadSet(OverloadSet os)
1250     {
1251         assert(os);
1252         foreach (s; os.a)
1253         {
1254             auto fd = s.isFuncDeclaration();
1255             auto td = s.isTemplateDeclaration();
1256             if (fd)
1257             {
1258                 if (fd.type.isTypeFunction().isproperty)
1259                     return resolveProperties(sc, e1);
1260             }
1261             else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
1262             {
1263                 if (fd.type.isTypeFunction().isproperty ||
1264                     (fd.storage_class2 & STC.property) ||
1265                     (td._scope.stc & STC.property))
1266                     return resolveProperties(sc, e1);
1267             }
1268         }
1269         return e1;
1270     }
1271 
1272     Expression handleTemplateDecl(TemplateDeclaration td)
1273     {
1274         assert(td);
1275         if (td.onemember)
1276         {
1277             if (auto fd = td.onemember.isFuncDeclaration())
1278             {
1279                 if (fd.type.isTypeFunction().isproperty ||
1280                     (fd.storage_class2 & STC.property) ||
1281                     (td._scope.stc & STC.property))
1282                     return resolveProperties(sc, e1);
1283             }
1284         }
1285         return e1;
1286     }
1287 
1288     Expression handleFuncDecl(FuncDeclaration fd)
1289     {
1290         assert(fd);
1291         if (fd.type.isTypeFunction().isproperty)
1292             return resolveProperties(sc, e1);
1293         return e1;
1294     }
1295 
1296     if (auto de = e1.isDotExp())
1297     {
1298         if (auto os = de.e2.isOverExp())
1299             return handleOverloadSet(os.vars);
1300     }
1301     else if (auto oe = e1.isOverExp())
1302         return handleOverloadSet(oe.vars);
1303     else if (auto dti = e1.isDotTemplateInstanceExp())
1304     {
1305         if (dti.ti.tempdecl)
1306             if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
1307                 return handleTemplateDecl(td);
1308     }
1309     else if (auto dte = e1.isDotTemplateExp())
1310         return handleTemplateDecl(dte.td);
1311     else if (auto se = e1.isScopeExp())
1312     {
1313         Dsymbol s = se.sds;
1314         TemplateInstance ti = s.isTemplateInstance();
1315         if (ti && !ti.semanticRun && ti.tempdecl)
1316             if (auto td = ti.tempdecl.isTemplateDeclaration())
1317                 return handleTemplateDecl(td);
1318     }
1319     else if (auto et = e1.isTemplateExp())
1320         return handleTemplateDecl(et.td);
1321     else if (e1.isDotVarExp() && e1.type.isTypeFunction())
1322     {
1323         DotVarExp dve = e1.isDotVarExp();
1324         return handleFuncDecl(dve.var.isFuncDeclaration());
1325     }
1326     else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
1327         return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
1328     return e1;
1329 }
1330 
1331 /****************************************
1332  * Turn symbol `s` into the expression it represents.
1333  *
1334  * Params:
1335  *      s = symbol to resolve
1336  *      loc = location of use of `s`
1337  *      sc = context
1338  *      hasOverloads = applies if `s` represents a function.
1339  *          true means it's overloaded and will be resolved later,
1340  *          false means it's the exact function symbol.
1341  * Returns:
1342  *      `s` turned into an expression, `ErrorExp` if an error occurred
1343  */
1344 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
1345 {
1346     static if (LOGSEMANTIC)
1347     {
1348         printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
1349     }
1350 
1351 Lagain:
1352     Expression e;
1353 
1354     //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
1355     //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
1356     Dsymbol olds = s;
1357     Declaration d = s.isDeclaration();
1358     if (d && (d.storage_class & STC.templateparameter))
1359     {
1360         s = s.toAlias();
1361     }
1362     else
1363     {
1364         // functions are checked after overloading
1365         // templates are checked after matching constraints
1366         if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
1367         {
1368             s.checkDeprecated(loc, sc);
1369             if (d)
1370                 d.checkDisabled(loc, sc);
1371         }
1372 
1373         // https://issues.dlang.org/show_bug.cgi?id=12023
1374         // if 's' is a tuple variable, the tuple is returned.
1375         s = s.toAlias();
1376 
1377         //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
1378         if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
1379         {
1380             s.checkDeprecated(loc, sc);
1381             if (d)
1382                 d.checkDisabled(loc, sc);
1383         }
1384 
1385         if (auto sd = s.isDeclaration())
1386         {
1387             if (sd.isSystem())
1388             {
1389                 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
1390                     "cannot access `@system` variable `%s` in @safe code", sd))
1391                 {
1392                     if (auto v = sd.isVarDeclaration())
1393                     {
1394                         if (v.systemInferred)
1395                             errorSupplemental(v.loc, "`%s` is inferred to be `@system` from its initializer here", v.toChars());
1396                         else
1397                             errorSupplemental(v.loc, "`%s` is declared here", v.toChars());
1398                     }
1399                     return ErrorExp.get();
1400                 }
1401             }
1402         }
1403     }
1404 
1405     if (auto em = s.isEnumMember())
1406     {
1407         return em.getVarExp(loc, sc);
1408     }
1409     if (auto v = s.isVarDeclaration())
1410     {
1411         //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
1412         if (sc.intypeof == 1 && !v.inuse)
1413             v.dsymbolSemantic(sc);
1414         if (!v.type ||                  // during variable type inference
1415             !v.type.deco && v.inuse)    // during variable type semantic
1416         {
1417             if (v.inuse)    // variable type depends on the variable itself
1418                 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
1419             else            // variable type cannot be determined
1420                 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
1421             return ErrorExp.get();
1422         }
1423         if (v.type.ty == Terror)
1424             return ErrorExp.get();
1425 
1426         if ((v.storage_class & STC.manifest) && v._init)
1427         {
1428             if (v.inuse)
1429             {
1430                 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
1431                 return ErrorExp.get();
1432             }
1433             e = v.expandInitializer(loc);
1434             v.inuse++;
1435             e = e.expressionSemantic(sc);
1436             v.inuse--;
1437             return e;
1438         }
1439 
1440         // We need to run semantics to correctly set 'STC.field' if it is a member variable
1441         // that could be forward referenced. This is needed for 'v.needThis()' to work
1442         if (v.isThis())
1443             v.dsymbolSemantic(sc);
1444 
1445         // Change the ancestor lambdas to delegate before hasThis(sc) call.
1446         if (v.checkNestedReference(sc, loc))
1447             return ErrorExp.get();
1448 
1449         if (v.needThis() && hasThis(sc))
1450             e = new DotVarExp(loc, new ThisExp(loc), v);
1451         else
1452             e = new VarExp(loc, v);
1453         e = e.expressionSemantic(sc);
1454         return e;
1455     }
1456     if (auto fld = s.isFuncLiteralDeclaration())
1457     {
1458         //printf("'%s' is a function literal\n", fld.toChars());
1459         e = new FuncExp(loc, fld);
1460         return e.expressionSemantic(sc);
1461     }
1462     if (auto f = s.isFuncDeclaration())
1463     {
1464         f = f.toAliasFunc();
1465         if (!f.functionSemantic())
1466             return ErrorExp.get();
1467 
1468         if (!hasOverloads && f.checkForwardRef(loc))
1469             return ErrorExp.get();
1470 
1471         auto fd = s.isFuncDeclaration();
1472         fd.type = f.type;
1473         return new VarExp(loc, fd, hasOverloads);
1474     }
1475     if (OverDeclaration od = s.isOverDeclaration())
1476     {
1477         e = new VarExp(loc, od, true);
1478         e.type = Type.tvoid;
1479         return e;
1480     }
1481     if (OverloadSet o = s.isOverloadSet())
1482     {
1483         //printf("'%s' is an overload set\n", o.toChars());
1484         return new OverExp(loc, o);
1485     }
1486 
1487     if (Import imp = s.isImport())
1488     {
1489         if (!imp.pkg)
1490         {
1491             .error(loc, "forward reference of import `%s`", imp.toChars());
1492             return ErrorExp.get();
1493         }
1494         auto ie = new ScopeExp(loc, imp.pkg);
1495         return ie.expressionSemantic(sc);
1496     }
1497     if (Package pkg = s.isPackage())
1498     {
1499         auto ie = new ScopeExp(loc, pkg);
1500         return ie.expressionSemantic(sc);
1501     }
1502     if (Module mod = s.isModule())
1503     {
1504         auto ie = new ScopeExp(loc, mod);
1505         return ie.expressionSemantic(sc);
1506     }
1507     if (Nspace ns = s.isNspace())
1508     {
1509         auto ie = new ScopeExp(loc, ns);
1510         return ie.expressionSemantic(sc);
1511     }
1512 
1513     if (Type t = s.getType())
1514     {
1515         return (new TypeExp(loc, t)).expressionSemantic(sc);
1516     }
1517 
1518     if (TupleDeclaration tup = s.isTupleDeclaration())
1519     {
1520         if (tup.needThis() && hasThis(sc))
1521             e = new DotVarExp(loc, new ThisExp(loc), tup);
1522         else
1523             e = new TupleExp(loc, tup);
1524         e = e.expressionSemantic(sc);
1525         return e;
1526     }
1527 
1528     if (TemplateInstance ti = s.isTemplateInstance())
1529     {
1530         ti.dsymbolSemantic(sc);
1531         if (!ti.inst || ti.errors)
1532             return ErrorExp.get();
1533         s = ti.toAlias();
1534         if (!s.isTemplateInstance())
1535             goto Lagain;
1536         e = new ScopeExp(loc, ti);
1537         e = e.expressionSemantic(sc);
1538         return e;
1539     }
1540     if (TemplateDeclaration td = s.isTemplateDeclaration())
1541     {
1542         Dsymbol p = td.toParentLocal();
1543         FuncDeclaration fdthis = hasThis(sc);
1544         AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1545         if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1546         {
1547             e = new DotTemplateExp(loc, new ThisExp(loc), td);
1548         }
1549         else
1550             e = new TemplateExp(loc, td);
1551         e = e.expressionSemantic(sc);
1552         return e;
1553     }
1554 
1555     .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1556     return ErrorExp.get();
1557 }
1558 
1559 /*************************************************************
1560  * Given var, get the
1561  * right `this` pointer if var is in an outer class, but our
1562  * existing `this` pointer is in an inner class.
1563  * Params:
1564  *      loc = location to use for error messages
1565  *      sc = context
1566  *      ad = struct or class we need the correct `this` for
1567  *      e1 = existing `this`
1568  *      var = the specific member of ad we're accessing
1569  *      flag = if true, return `null` instead of throwing an error
1570  * Returns:
1571  *      Expression representing the `this` for the var
1572  */
1573 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1574 {
1575     //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1576 L1:
1577     Type t = e1.type.toBasetype();
1578     //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1579 
1580     if (e1.op == EXP.objcClassReference)
1581     {
1582         // We already have an Objective-C class reference, just use that as 'this'.
1583         return e1;
1584     }
1585     else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1586              var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1587              var.isFuncDeclaration.objc.selector)
1588     {
1589         auto cls = ad.isClassDeclaration();
1590         auto classObj = new ObjcClassReferenceExp(e1.loc, cls);
1591         classObj.type = objc.getRuntimeMetaclass(cls).getType();
1592         return classObj;
1593     }
1594 
1595     /* Access of a member which is a template parameter in dual-scope scenario
1596      * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1597      * class B {int m; inc() { new A().inc!m(); } }
1598      */
1599     if (e1.op == EXP.this_)
1600     {
1601         FuncDeclaration f = hasThis(sc);
1602         if (f && f.hasDualContext())
1603         {
1604             if (f.followInstantiationContext(ad))
1605             {
1606                 e1 = new VarExp(loc, f.vthis);
1607                 e1 = new PtrExp(loc, e1);
1608                 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1609                 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1610                 if (e1.op == EXP.error)
1611                     return e1;
1612                 goto L1;
1613             }
1614         }
1615     }
1616 
1617     /* If e1 is not the 'this' pointer for ad
1618      */
1619     if (ad &&
1620         !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1621         !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1622     {
1623         ClassDeclaration cd = ad.isClassDeclaration();
1624         ClassDeclaration tcd = t.isClassHandle();
1625 
1626         /* e1 is the right this if ad is a base class of e1
1627          */
1628         if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1629         {
1630             /* Only classes can be inner classes with an 'outer'
1631              * member pointing to the enclosing class instance
1632              */
1633             if (tcd && tcd.isNested())
1634             {
1635                 /* e1 is the 'this' pointer for an inner class: tcd.
1636                  * Rewrite it as the 'this' pointer for the outer class.
1637                  */
1638                 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1639                 e1 = new DotVarExp(loc, e1, vthis);
1640                 e1.type = vthis.type;
1641                 e1.type = e1.type.addMod(t.mod);
1642                 // Do not call ensureStaticLinkTo()
1643                 //e1 = e1.semantic(sc);
1644 
1645                 // Skip up over nested functions, and get the enclosing
1646                 // class type.
1647                 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1648                 if (e1.op == EXP.error)
1649                     return e1;
1650                 goto L1;
1651             }
1652 
1653             /* Can't find a path from e1 to ad
1654              */
1655             if (flag)
1656                 return null;
1657             error(e1.loc, "`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1658             return ErrorExp.get();
1659         }
1660     }
1661     return e1;
1662 }
1663 
1664 /*
1665  * Check whether `outerFunc` and `calledFunc` have the same `this`.
1666  * If `calledFunc` is the member of a base class of the class that contains
1667  * `outerFunc` we consider that they have the same this.
1668  *
1669  * This function is used to test whether `this` needs to be prepended to
1670  * a function call or function symbol. For example:
1671  *
1672  * struct X
1673  * {
1674  *    void gun() {}
1675  * }
1676  * struct A
1677  * {
1678  *      void fun() {}
1679  *      void sun()
1680  *      {
1681  *          fun();
1682  *          X.gun();  // error
1683  *      }
1684  * }
1685  *
1686  * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1687  * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1688  * `this` can be prepended to `fun`. When `gun` is called (it will result
1689  * in an error, but that is not relevant here), which is a member of `X`,
1690  * no `this` is needed because the outer function does not have the same
1691  * `this` as `gun`.
1692  *
1693  * Returns:
1694  *  `true` if outerFunc and calledFunc may use the same `this` pointer.
1695  * `false` otherwise.
1696  */
1697 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
1698 {
1699     // https://issues.dlang.org/show_bug.cgi?id=24013
1700     // traits(getOverloads) inserts an alias to select the overload.
1701     // When searching for the right this we need to use the aliased
1702     // overload/function, not the alias.
1703     outerFunc = outerFunc.toAliasFunc();
1704     calledFunc = calledFunc.toAliasFunc();
1705 
1706     auto thisAd = outerFunc.isMemberLocal();
1707     if (!thisAd)
1708         return false;
1709 
1710     auto requiredAd = calledFunc.isMemberLocal();
1711     if (!requiredAd)
1712         return false;
1713 
1714     if (thisAd == requiredAd)
1715         return true;
1716 
1717     // if outerfunc is the member of a nested aggregate, then let
1718     // getRightThis take care of this.
1719     if (thisAd.isNested())
1720         return true;
1721 
1722     // outerfunc is the member of a base class that contains calledFunc,
1723     // then we consider that they have the same this.
1724     auto cd = requiredAd.isClassDeclaration();
1725     if (!cd)
1726         return false;
1727 
1728     if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1729         return true;
1730 
1731     return false;
1732 }
1733 
1734 /***************************************
1735  * Pull out any properties.
1736  */
1737 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
1738 {
1739     //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1740     Loc loc = e1.loc;
1741 
1742     OverloadSet os;
1743     Dsymbol s;
1744     Objects* tiargs;
1745     Type tthis;
1746     if (auto de = e1.isDotExp())
1747     {
1748         if (auto oe = de.e2.isOverExp())
1749         {
1750             tiargs = null;
1751             tthis = de.e1.type;
1752             os = oe.vars;
1753             goto Los;
1754         }
1755     }
1756     else if (e1.isOverExp())
1757     {
1758         tiargs = null;
1759         tthis = null;
1760         os = e1.isOverExp().vars;
1761     Los:
1762         assert(os);
1763         FuncDeclaration fd = null;
1764         if (e2)
1765         {
1766             e2 = e2.expressionSemantic(sc);
1767             if (e2.op == EXP.error)
1768                 return ErrorExp.get();
1769             e2 = resolveProperties(sc, e2);
1770 
1771             Expressions* a = new Expressions();
1772             a.push(e2);
1773 
1774             for (size_t i = 0; i < os.a.length; i++)
1775             {
1776                 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet))
1777                 {
1778                     if (f.errors)
1779                         return ErrorExp.get();
1780                     fd = f;
1781                     assert(fd.type.ty == Tfunction);
1782                 }
1783             }
1784             if (fd)
1785             {
1786                 Expression e = new CallExp(loc, e1, e2);
1787                 return e.expressionSemantic(sc);
1788             }
1789         }
1790         {
1791             for (size_t i = 0; i < os.a.length; i++)
1792             {
1793                 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
1794                 {
1795                     if (f.errors)
1796                         return ErrorExp.get();
1797                     fd = f;
1798                     assert(fd.type.ty == Tfunction);
1799                     auto tf = fd.type.isTypeFunction();
1800                     if (!tf.isref && e2)
1801                     {
1802                         error(loc, "%s is not an lvalue", e1.toChars());
1803                         return ErrorExp.get();
1804                     }
1805                 }
1806             }
1807             if (fd)
1808             {
1809                 Expression e = new CallExp(loc, e1);
1810                 if (e2)
1811                 {
1812                     e = new AssignExp(loc, e, e2);
1813                     if (saveAtts)
1814                     {
1815                         (cast(BinExp)e).att1 = saveAtts.att1;
1816                         (cast(BinExp)e).att2 = saveAtts.att2;
1817                     }
1818                 }
1819                 return e.expressionSemantic(sc);
1820             }
1821         }
1822         if (e2)
1823             goto Leprop;
1824     }
1825     else if (auto dti = e1.isDotTemplateInstanceExp())
1826     {
1827         if (!dti.findTempDecl(sc))
1828             goto Leprop;
1829         if (!dti.ti.semanticTiargs(sc))
1830             goto Leprop;
1831         tiargs = dti.ti.tiargs;
1832         tthis = dti.e1.type;
1833         if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1834             goto Los;
1835         if ((s = dti.ti.tempdecl) !is null)
1836             goto Lfd;
1837     }
1838     else if (auto dte = e1.isDotTemplateExp())
1839     {
1840         s = dte.td;
1841         tiargs = null;
1842         tthis = dte.e1.type;
1843         goto Lfd;
1844     }
1845     else if (auto se = e1.isScopeExp())
1846     {
1847         s = se.sds;
1848         TemplateInstance ti = s.isTemplateInstance();
1849         if (ti && !ti.semanticRun && ti.tempdecl)
1850         {
1851             //assert(ti.needsTypeInference(sc));
1852             if (!ti.semanticTiargs(sc))
1853                 goto Leprop;
1854             tiargs = ti.tiargs;
1855             tthis = null;
1856             if ((os = ti.tempdecl.isOverloadSet()) !is null)
1857                 goto Los;
1858             if ((s = ti.tempdecl) !is null)
1859                 goto Lfd;
1860         }
1861     }
1862     else if (auto te = e1.isTemplateExp())
1863     {
1864         s = te.td;
1865         tiargs = null;
1866         tthis = null;
1867         goto Lfd;
1868     }
1869     else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
1870     {
1871         DotVarExp dve = e1.isDotVarExp();
1872         s = dve.var;
1873         tiargs = null;
1874         tthis = dve.e1.type;
1875         goto Lfd;
1876     }
1877     else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
1878     {
1879         // ImportC: do not implicitly call function if no ( ) are present
1880     }
1881     else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
1882     {
1883         s = e1.isVarExp().var;
1884         tiargs = null;
1885         tthis = null;
1886     Lfd:
1887         assert(s);
1888         if (e2)
1889         {
1890             e2 = e2.expressionSemantic(sc);
1891             if (e2.op == EXP.error)
1892                 return ErrorExp.get();
1893             e2 = resolveProperties(sc, e2);
1894 
1895             Expressions* a = new Expressions();
1896             a.push(e2);
1897 
1898             FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(a), FuncResolveFlag.quiet);
1899             if (fd && fd.type)
1900             {
1901                 if (fd.errors)
1902                     return ErrorExp.get();
1903                 assert(fd.type.ty == Tfunction);
1904                 Expression e = new CallExp(loc, e1, e2);
1905                 return e.expressionSemantic(sc);
1906             }
1907         }
1908         {
1909             FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
1910             if (fd && fd.type)
1911             {
1912                 if (fd.errors)
1913                     return ErrorExp.get();
1914                 TypeFunction tf = fd.type.isTypeFunction();
1915                 if (!e2 || tf.isref)
1916                 {
1917                     Expression e = new CallExp(loc, e1);
1918                     if (e2)
1919                     {
1920                         e = new AssignExp(loc, e, e2);
1921                         if (saveAtts)
1922                         {
1923                             (cast(BinExp)e).att1 = saveAtts.att1;
1924                             (cast(BinExp)e).att2 = saveAtts.att2;
1925                         }
1926                     }
1927                     return e.expressionSemantic(sc);
1928                 }
1929             }
1930         }
1931         if (FuncDeclaration fd = s.isFuncDeclaration())
1932         {
1933             // Keep better diagnostic message for invalid property usage of functions
1934             assert(fd.type.ty == Tfunction);
1935             Expression e = new CallExp(loc, e1, e2);
1936             return e.expressionSemantic(sc);
1937         }
1938         if (e2)
1939             goto Leprop;
1940     }
1941     if (auto ve = e1.isVarExp())
1942     {
1943         if (auto v = ve.var.isVarDeclaration())
1944         {
1945             if (ve.checkPurity(sc, v))
1946                 return ErrorExp.get();
1947         }
1948     }
1949     if (e2)
1950         return null;
1951 
1952     if (e1.type && !e1.isTypeExp()) // function type is not a property
1953     {
1954         /* Look for e1 being a lazy parameter; rewrite as delegate call
1955          * only if the symbol wasn't already treated as a delegate
1956          */
1957         auto ve = e1.isVarExp();
1958         if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1959         {
1960                 Expression e = new CallExp(loc, e1);
1961                 return e.expressionSemantic(sc);
1962         }
1963         else if (e1.isDotVarExp())
1964         {
1965             // Check for reading overlapped pointer field in @safe code.
1966             if (checkUnsafeAccess(sc, e1, true, true))
1967                 return ErrorExp.get();
1968         }
1969         else if (auto ce = e1.isCallExp())
1970         {
1971             // Check for reading overlapped pointer field in @safe code.
1972             if (checkUnsafeAccess(sc, ce.e1, true, true))
1973                 return ErrorExp.get();
1974         }
1975     }
1976 
1977     if (!e1.type)
1978     {
1979         error(loc, "cannot resolve type for %s", e1.toChars());
1980         e1 = ErrorExp.get();
1981     }
1982     return e1;
1983 
1984 Leprop:
1985     error(loc, "not a property %s", e1.toChars());
1986     return ErrorExp.get();
1987 }
1988 
1989 private bool checkRightThis(Expression e, Scope* sc)
1990 {
1991     if (e.op == EXP.error)
1992         return true;
1993     if (e.op == EXP.variable && e.type.ty != Terror)
1994     {
1995         VarExp ve = cast(VarExp)e;
1996         if (isNeedThisScope(sc, ve.var))
1997         {
1998             //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1999             //        sc.intypeof, sc.getStructClassScope(), func, fdthis);
2000             auto t = ve.var.isThis();
2001             assert(t);
2002             error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
2003             return true;
2004         }
2005     }
2006     return false;
2007 }
2008 
2009 extern (C++) Expression resolveProperties(Scope* sc, Expression e)
2010 {
2011     //printf("resolveProperties(%s)\n", e.toChars());
2012     e = resolvePropertiesX(sc, e);
2013     if (e.checkRightThis(sc))
2014         return ErrorExp.get();
2015     return e;
2016 }
2017 
2018 /****************************************
2019  * The common type is determined by applying ?: to each pair.
2020  * Output:
2021  *      exps[]  properties resolved, implicitly cast to common type, rewritten in place
2022  * Returns:
2023  *      The common type, or `null` if an error has occured
2024  */
2025 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
2026 {
2027     /* Still have a problem with:
2028      *  ubyte[][] = [ cast(ubyte[])"hello", [1]];
2029      * which works if the array literal is initialized top down with the ubyte[][]
2030      * type, but fails with this function doing bottom up typing.
2031      */
2032 
2033     //printf("arrayExpressionToCommonType()\n");
2034     scope IntegerExp integerexp = IntegerExp.literal!0;
2035     scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
2036 
2037     Type t0 = null;
2038     Expression e0 = null;
2039     bool foundType;
2040 
2041     for (size_t i = 0; i < exps.length; i++)
2042     {
2043         Expression e = exps[i];
2044         if (!e)
2045             continue;
2046 
2047         e = resolveProperties(sc, e);
2048         if (!e.type)
2049         {
2050             error(e.loc, "`%s` has no value", e.toChars());
2051             t0 = Type.terror;
2052             continue;
2053         }
2054         if (e.op == EXP.type)
2055         {
2056             foundType = true; // do not break immediately, there might be more errors
2057             e.checkValue(); // report an error "type T has no value"
2058             t0 = Type.terror;
2059             continue;
2060         }
2061         if (e.type.ty == Tvoid)
2062         {
2063             // void expressions do not concur to the determination of the common
2064             // type.
2065             continue;
2066         }
2067         if (checkNonAssignmentArrayOp(e))
2068         {
2069             t0 = Type.terror;
2070             continue;
2071         }
2072 
2073         e = doCopyOrMove(sc, e);
2074 
2075         if (!foundType && t0 && !t0.equals(e.type))
2076         {
2077             /* This applies ?: to merge the types. It's backwards;
2078              * ?: should call this function to merge types.
2079              */
2080             condexp.type = null;
2081             condexp.e1 = e0;
2082             condexp.e2 = e;
2083             condexp.loc = e.loc;
2084             Expression ex = condexp.expressionSemantic(sc);
2085             if (ex.op == EXP.error)
2086                 e = ex;
2087             else
2088             {
2089                 // Convert to common type
2090                 exps[i] = condexp.e1.castTo(sc, condexp.type);
2091                 e = condexp.e2.castTo(sc, condexp.type);
2092             }
2093         }
2094         e0 = e;
2095         t0 = e.type;
2096         if (e.op != EXP.error)
2097             exps[i] = e;
2098     }
2099 
2100     // [] is typed as void[]
2101     if (!t0)
2102         return Type.tvoid;
2103 
2104     // It's an error, don't do the cast
2105     if (t0.ty == Terror)
2106         return null;
2107 
2108     for (size_t i = 0; i < exps.length; i++)
2109     {
2110         Expression e = exps[i];
2111         if (!e)
2112             continue;
2113 
2114         e = e.implicitCastTo(sc, t0);
2115         if (e.op == EXP.error)
2116         {
2117             /* https://issues.dlang.org/show_bug.cgi?id=13024
2118              * a workaround for the bug in typeMerge -
2119              * it should paint e1 and e2 by deduced common type,
2120              * but doesn't in this particular case.
2121              */
2122             return null;
2123         }
2124         exps[i] = e;
2125     }
2126     return t0;
2127 }
2128 
2129 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2) @safe
2130 {
2131     Expression e;
2132     switch (op)
2133     {
2134     case EXP.addAssign:
2135         e = new AddExp(loc, e1, e2);
2136         break;
2137 
2138     case EXP.minAssign:
2139         e = new MinExp(loc, e1, e2);
2140         break;
2141 
2142     case EXP.mulAssign:
2143         e = new MulExp(loc, e1, e2);
2144         break;
2145 
2146     case EXP.divAssign:
2147         e = new DivExp(loc, e1, e2);
2148         break;
2149 
2150     case EXP.modAssign:
2151         e = new ModExp(loc, e1, e2);
2152         break;
2153 
2154     case EXP.andAssign:
2155         e = new AndExp(loc, e1, e2);
2156         break;
2157 
2158     case EXP.orAssign:
2159         e = new OrExp(loc, e1, e2);
2160         break;
2161 
2162     case EXP.xorAssign:
2163         e = new XorExp(loc, e1, e2);
2164         break;
2165 
2166     case EXP.leftShiftAssign:
2167         e = new ShlExp(loc, e1, e2);
2168         break;
2169 
2170     case EXP.rightShiftAssign:
2171         e = new ShrExp(loc, e1, e2);
2172         break;
2173 
2174     case EXP.unsignedRightShiftAssign:
2175         e = new UshrExp(loc, e1, e2);
2176         break;
2177 
2178     default:
2179         assert(0);
2180     }
2181     return e;
2182 }
2183 
2184 /*********************
2185  * Rewrite:
2186  *    array.length op= e2
2187  */
2188 private Expression rewriteOpAssign(BinExp exp)
2189 {
2190     ArrayLengthExp ale = exp.e1.isArrayLengthExp();
2191     if (ale.e1.isVarExp())
2192     {
2193         // array.length = array.length op e2
2194         Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
2195         e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
2196         return e;
2197     }
2198     else
2199     {
2200         // (ref tmp = array;), tmp.length = tmp.length op e2
2201         auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
2202         Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
2203         Expression elvalue = e1.syntaxCopy();
2204         Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
2205         e = new AssignExp(exp.loc, elvalue, e);
2206         e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
2207         return e;
2208     }
2209 }
2210 
2211 /****************************************
2212  * Preprocess arguments to function.
2213  *
2214  * Tuples in argumentList get expanded, properties resolved, rewritten in place
2215  *
2216  * Params:
2217  *     sc           =  scope
2218  *     argumentList =  arguments to function
2219  *     reportErrors =  whether or not to report errors here. Some callers are not
2220  *                      checking actual function params, so they'll do their own error reporting
2221  * Returns:
2222  *     `true` when a semantic error occurred
2223  */
2224 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
2225 {
2226     Expressions* exps = argumentList.arguments;
2227     bool err = false;
2228     if (exps)
2229     {
2230         expandTuples(exps, argumentList.names);
2231 
2232         for (size_t i = 0; i < exps.length; i++)
2233         {
2234             Expression arg = (*exps)[i];
2235             arg = resolveProperties(sc, arg);
2236             arg = arg.arrayFuncConv(sc);
2237             if (arg.op == EXP.type)
2238             {
2239                 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
2240                 arg = resolveAliasThis(sc, arg);
2241 
2242                 if (arg.op == EXP.type)
2243                 {
2244                     if (reportErrors)
2245                     {
2246                         error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
2247                         arg = ErrorExp.get();
2248                     }
2249                     err = true;
2250                 }
2251             }
2252             else if (arg.type.toBasetype().ty == Tfunction)
2253             {
2254                 if (reportErrors)
2255                 {
2256                     error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
2257                     arg = ErrorExp.get();
2258                 }
2259                 err = true;
2260             }
2261             else if (checkNonAssignmentArrayOp(arg))
2262             {
2263                 arg = ErrorExp.get();
2264                 err = true;
2265             }
2266             (*exps)[i] = arg;
2267         }
2268     }
2269     return err;
2270 }
2271 
2272 /********************************************
2273  * Issue an error if default construction is disabled for type t.
2274  * Default construction is required for arrays and 'out' parameters.
2275  * Returns:
2276  *      true    an error was issued
2277  */
2278 private bool checkDefCtor(Loc loc, Type t)
2279 {
2280     if (auto ts = t.baseElemOf().isTypeStruct())
2281     {
2282         StructDeclaration sd = ts.sym;
2283         if (sd.noDefaultCtor)
2284         {
2285             .error(loc, "%s `%s` default construction is disabled", sd.kind, sd.toPrettyChars);
2286             return true;
2287         }
2288     }
2289     return false;
2290 }
2291 
2292 /****************************************
2293  * Now that we know the exact type of the function we're calling,
2294  * the arguments[] need to be adjusted:
2295  *      1. implicitly convert argument to the corresponding parameter type
2296  *      2. add default arguments for any missing arguments
2297  *      3. do default promotions on arguments corresponding to ...
2298  *      4. add hidden _arguments[] argument
2299  *      5. call copy constructor for struct value arguments
2300  * Params:
2301  *      loc       = location of function call
2302  *      sc        = context
2303  *      tf        = type of the function
2304  *      ethis     = `this` argument, `null` if none or not known
2305  *      tthis     = type of `this` argument, `null` if no `this` argument
2306  *      argumentsList = array of actual arguments to function call
2307  *      fd        = the function being called, `null` if called indirectly
2308  *      prettype  = set to return type of function
2309  *      peprefix  = set to expression to execute before `arguments[]` are evaluated, `null` if none
2310  * Returns:
2311  *      true    errors happened
2312  */
2313 private bool functionParameters(const ref Loc loc, Scope* sc,
2314     TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
2315     Type* prettype, Expression* peprefix)
2316 {
2317     Expressions* arguments = argumentList.arguments;
2318     //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
2319     assert(arguments);
2320     assert(fd || tf.next);
2321     const size_t nparams = tf.parameterList.length;
2322     const olderrors = global.errors;
2323     bool err = false;
2324     Expression eprefix = null;
2325     *peprefix = null;
2326 
2327     if (argumentList.names)
2328     {
2329         const(char)* msg = null;
2330         auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
2331         if (!resolvedArgs)
2332         {
2333             // while errors are usually already caught by `tf.callMatch`,
2334             // this can happen when calling `typeof(freefunc)`
2335             if (msg)
2336                 error(loc, "%s", msg);
2337             return true;
2338         }
2339         // note: the argument list should be mutated with named arguments / default arguments,
2340         // so we can't simply change the pointer like `arguments = resolvedArgs;`
2341         arguments.setDim(0);
2342         arguments.pushSlice((*resolvedArgs)[]);
2343     }
2344     size_t nargs = arguments ? arguments.length : 0;
2345 
2346     if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
2347     {
2348         error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
2349         return true;
2350     }
2351 
2352     // If inferring return type, and semantic3() needs to be run if not already run
2353     if (!tf.next && fd.inferRetType)
2354     {
2355         fd.functionSemantic();
2356     }
2357     else if (fd && fd.parent)
2358     {
2359         TemplateInstance ti = fd.parent.isTemplateInstance();
2360         if (ti && ti.tempdecl)
2361         {
2362             fd.functionSemantic3();
2363         }
2364     }
2365 
2366     /* If calling a pragma(inline, true) function,
2367      * set flag to later scan for inlines.
2368      */
2369     if (fd && fd.inlining == PINLINE.always)
2370     {
2371         if (sc._module)
2372             sc._module.hasAlwaysInlines = true;
2373         if (sc.func)
2374             sc.func.hasAlwaysInlines = true;
2375     }
2376 
2377     const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
2378 
2379     const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
2380 
2381     /* If the function return type has wildcards in it, we'll need to figure out the actual type
2382      * based on the actual argument types.
2383      * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
2384      * of the arguments.
2385      */
2386     MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
2387 
2388     bool done = false;
2389     foreach (const i; 0 .. n)
2390     {
2391         Expression arg = (i < nargs) ? (*arguments)[i] : null;
2392 
2393         if (i < nparams)
2394         {
2395             bool errorArgs()
2396             {
2397                 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
2398                 return true;
2399             }
2400 
2401             Parameter p = tf.parameterList[i];
2402 
2403             if (!arg)
2404             {
2405                 if (!p.defaultArg)
2406                 {
2407                     if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
2408                         goto L2;
2409                     return errorArgs();
2410                 }
2411                 arg = p.defaultArg;
2412                 if (!arg.type)
2413                     arg = arg.expressionSemantic(sc);
2414                 arg = inlineCopy(arg, sc);
2415                 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
2416                 arg = arg.resolveLoc(loc, sc);
2417                 if (i >= nargs)
2418                 {
2419                     arguments.push(arg);
2420                     nargs++;
2421                 }
2422                 else
2423                     (*arguments)[i] = arg;
2424             }
2425             else
2426             {
2427                 if (arg.isDefaultInitExp())
2428                 {
2429                     arg = arg.resolveLoc(loc, sc);
2430                     (*arguments)[i] = arg;
2431                 }
2432             }
2433 
2434 
2435             if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
2436             {
2437                 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
2438                 {
2439                     MATCH m;
2440                     if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
2441                     {
2442                         if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
2443                             goto L2;
2444                         else if (nargs != nparams)
2445                             return errorArgs();
2446                         goto L1;
2447                     }
2448                 }
2449             L2:
2450                 Type tb = p.type.toBasetype();
2451                 switch (tb.ty)
2452                 {
2453                 case Tsarray:
2454                 case Tarray:
2455                     {
2456                         /* Create a static array variable v of type arg.type:
2457                          *  T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
2458                          *
2459                          * The array literal in the initializer of the hidden variable
2460                          * is now optimized.
2461                          * https://issues.dlang.org/show_bug.cgi?id=2356
2462                          */
2463                         Type tbn = (cast(TypeArray)tb).next;    // array element type
2464                         Type tret = p.isLazyArray();
2465 
2466                         auto elements = new Expressions(nargs - i);
2467                         foreach (u; 0 .. elements.length)
2468                         {
2469                             Expression a = (*arguments)[i + u];
2470                             if (tret && a.implicitConvTo(tret))
2471                             {
2472                                 // p is a lazy array of delegates, tret is return type of the delegates
2473                                 a = a.implicitCastTo(sc, tret)
2474                                      .optimize(WANTvalue)
2475                                      .toDelegate(tret, sc);
2476                             }
2477                             else
2478                                 a = a.implicitCastTo(sc, tbn);
2479                             a = a.addDtorHook(sc);
2480                             (*elements)[u] = a;
2481                         }
2482                         // https://issues.dlang.org/show_bug.cgi?id=14395
2483                         // Convert to a static array literal, or its slice.
2484                         arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
2485                         if (tb.ty == Tarray)
2486                         {
2487                             arg = new SliceExp(loc, arg, null, null);
2488                             arg.type = p.type;
2489                         }
2490                         break;
2491                     }
2492                 case Tclass:
2493                     {
2494                         /* Set arg to be:
2495                          *      new Tclass(arg0, arg1, ..., argn)
2496                          */
2497                         auto args = new Expressions(nargs - i);
2498                         foreach (u; i .. nargs)
2499                             (*args)[u - i] = (*arguments)[u];
2500                         arg = new NewExp(loc, null, p.type, args);
2501                         break;
2502                     }
2503                 default:
2504                     if (!arg)
2505                     {
2506                         error(loc, "not enough arguments");
2507                         return true;
2508                     }
2509                     break;
2510                 }
2511                 arg = arg.expressionSemantic(sc);
2512                 //printf("\targ = '%s'\n", arg.toChars());
2513                 arguments.setDim(i + 1);
2514                 (*arguments)[i] = arg;
2515                 nargs = i + 1;
2516                 done = true;
2517             }
2518 
2519         L1:
2520             if (!(p.isLazy() && p.type.ty == Tvoid))
2521             {
2522                 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
2523                 {
2524                     wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
2525                     //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
2526                 }
2527             }
2528         }
2529         if (done)
2530             break;
2531     }
2532     if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
2533         tf.next && tf.next.hasWild() &&
2534         (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
2535     {
2536         bool errorInout(MOD wildmatch)
2537         {
2538             const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
2539             error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
2540             return true;
2541         }
2542 
2543         if (fd)
2544         {
2545             /* If the called function may return the reference to
2546              * outer inout data, it should be rejected.
2547              *
2548              * void foo(ref inout(int) x) {
2549              *   ref inout(int) bar(inout(int)) { return x; }
2550              *   struct S {
2551              *      ref inout(int) bar() inout { return x; }
2552              *      ref inout(int) baz(alias a)() inout { return x; }
2553              *   }
2554              *   bar(int.init) = 1;  // bad!
2555              *   S().bar() = 1;      // bad!
2556              * }
2557              * void test() {
2558              *   int a;
2559              *   auto s = foo(a);
2560              *   s.baz!a() = 1;      // bad!
2561              * }
2562              *
2563              */
2564             bool checkEnclosingWild(Dsymbol s)
2565             {
2566                 bool checkWild(Dsymbol s)
2567                 {
2568                     if (!s)
2569                         return false;
2570                     if (auto ad = s.isAggregateDeclaration())
2571                     {
2572                         if (ad.isNested())
2573                             return checkEnclosingWild(s);
2574                     }
2575                     else if (auto ff = s.isFuncDeclaration())
2576                     {
2577                         if (ff.type.isTypeFunction().iswild)
2578                             return errorInout(wildmatch);
2579 
2580                         if (ff.isNested() || ff.isThis())
2581                             return checkEnclosingWild(s);
2582                     }
2583                     return false;
2584                 }
2585 
2586                 Dsymbol ctx0 = s.toParent2();
2587                 Dsymbol ctx1 = s.toParentLocal();
2588                 if (checkWild(ctx0))
2589                     return true;
2590                 if (ctx0 != ctx1)
2591                     return checkWild(ctx1);
2592                 return false;
2593             }
2594             if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
2595                 return true;
2596         }
2597         else if (tf.isWild())
2598             return errorInout(wildmatch);
2599     }
2600 
2601     Expression firstArg = null;
2602     final switch (returnParamDest(tf, tthis))
2603     {
2604         case ReturnParamDest.returnVal:
2605             break;
2606         case ReturnParamDest.firstArg:
2607             firstArg = nargs > 0 ? (*arguments)[0] : null;
2608             break;
2609         case ReturnParamDest.this_:
2610             firstArg = ethis;
2611             break;
2612     }
2613 
2614     assert(nargs >= nparams);
2615     foreach (const i, arg; (*arguments)[0 .. nargs])
2616     {
2617         assert(arg);
2618         if (i < nparams)
2619         {
2620             Parameter p = tf.parameterList[i];
2621             Type targ = arg.type;               // keep original type for isCopyable() because alias this
2622                                                 // resolution may hide an uncopyable type
2623 
2624             if (!(p.isLazy() && p.type.ty == Tvoid))
2625             {
2626                 Type tprm = p.type.hasWild()
2627                     ? p.type.substWildTo(wildmatch)
2628                     : p.type;
2629 
2630                 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
2631                 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
2632                 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
2633                 {
2634                     //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2635                     arg = arg.implicitCastTo(sc, tprm);
2636                     arg = arg.optimize(WANTvalue, p.isReference());
2637                 }
2638             }
2639 
2640             // Support passing rvalue to `in` parameters
2641             if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
2642             {
2643                 if (!arg.isLvalue())
2644                 {
2645                     auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
2646                     Expression ev = new DeclarationExp(arg.loc, v);
2647                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2648                     arg = ev.expressionSemantic(sc);
2649                 }
2650                 arg = arg.toLvalue(sc, arg);
2651 
2652                 // Look for mutable misaligned pointer, etc., in @safe mode
2653                 err |= checkUnsafeAccess(sc, arg, false, true);
2654             }
2655             else if (p.storageClass & STC.ref_)
2656             {
2657                 if (global.params.rvalueRefParam == FeatureState.enabled &&
2658                     !arg.isLvalue() &&
2659                     targ.isCopyable())
2660                 {   /* allow rvalues to be passed to ref parameters by copying
2661                      * them to a temp, then pass the temp as the argument
2662                      */
2663                     auto v = copyToTemp(0, "__rvalue", arg);
2664                     Expression ev = new DeclarationExp(arg.loc, v);
2665                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2666                     arg = ev.expressionSemantic(sc);
2667                 }
2668                 arg = arg.toLvalue(sc, arg);
2669 
2670                 // Look for mutable misaligned pointer, etc., in @safe mode
2671                 err |= checkUnsafeAccess(sc, arg, false, true);
2672             }
2673             else if (p.storageClass & STC.out_)
2674             {
2675                 Type t = arg.type;
2676                 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2677                 {
2678                     error(arg.loc, "cannot modify struct `%s` with immutable members", arg.toChars());
2679                     err = true;
2680                 }
2681                 else
2682                 {
2683                     // Look for misaligned pointer, etc., in @safe mode
2684                     err |= checkUnsafeAccess(sc, arg, false, true);
2685                     err |= checkDefCtor(arg.loc, t); // t must be default constructible
2686                 }
2687                 arg = arg.toLvalue(sc, arg);
2688             }
2689             else if (p.isLazy())
2690             {
2691                 // Convert lazy argument to a delegate
2692                 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2693                 arg = toDelegate(arg, t, sc);
2694             }
2695             //printf("arg: %s\n", arg.toChars());
2696             //printf("type: %s\n", arg.type.toChars());
2697             //printf("param: %s\n", p.toChars());
2698 
2699             const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal());
2700             const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect);
2701 
2702             if (firstArg && (pStc & STC.return_))
2703             {
2704                 /* Argument value can be assigned to firstArg.
2705                  * Check arg to see if it matters.
2706                  */
2707                 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
2708             }
2709             // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2710             // as lazy parameters to the next function, but that isn't escaping.
2711             // The arguments of `_d_arraycatnTX` are already handled in
2712             // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
2713             // check does not return an error, so the lowering of `a ~ b` to
2714             // `_d_arraycatnTX(a, b)` still occurs.
2715             else if (!(pStc & STC.lazy_) && (!fd ||  fd.ident != Id._d_arraycatnTX))
2716             {
2717                 /* Argument value can escape from the called function.
2718                  * Check arg to see if it matters.
2719                  */
2720                 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
2721                 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
2722             }
2723 
2724             // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2725             // may be unreliable when scope violations only manifest as deprecation warnings.
2726             // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
2727             const explicitScope = p.isLazy() ||
2728                 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
2729             if ((pStc & (STC.scope_ | STC.lazy_)) &&
2730                 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
2731                 !(pStc & STC.return_))
2732             {
2733                 /* Argument value cannot escape from the called function.
2734                  */
2735                 Expression a = arg;
2736                 if (auto ce = a.isCastExp())
2737                     a = ce.e1;
2738 
2739                 ArrayLiteralExp ale;
2740                 if (p.type.toBasetype().ty == Tarray &&
2741                     (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
2742                 {
2743                     // allocate the array literal as temporary static array on the stack
2744                     ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
2745                     auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2746                     tmp.storage_class |= STC.exptemp;
2747                     auto declareTmp = new DeclarationExp(ale.loc, tmp);
2748                     auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2749                         p.type.substWildTo(MODFlags.mutable));
2750                     arg = CommaExp.combine(declareTmp, castToSlice);
2751                     arg = arg.expressionSemantic(sc);
2752                 }
2753                 else if (auto fe = a.isFuncExp())
2754                 {
2755                     /* Function literals can only appear once, so if this
2756                      * appearance was scoped, there cannot be any others.
2757                      */
2758                     fe.fd.tookAddressOf = 0;
2759                 }
2760                 else if (auto de = a.isDelegateExp())
2761                 {
2762                     /* For passing a delegate to a scoped parameter,
2763                      * this doesn't count as taking the address of it.
2764                      * We only worry about 'escaping' references to the function.
2765                      */
2766                     if (auto ve = de.e1.isVarExp())
2767                     {
2768                         if (auto f = ve.var.isFuncDeclaration())
2769                         {
2770                             if (f.tookAddressOf)
2771                                 --f.tookAddressOf;
2772                             //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2773                         }
2774                     }
2775                 }
2776             }
2777             if (!p.isReference())
2778                 err |= arg.checkSharedAccess(sc);
2779 
2780             arg = arg.optimize(WANTvalue, p.isReference());
2781         }
2782         else
2783         {
2784             // These will be the trailing ... arguments
2785             // If not D linkage, do promotions
2786             if (tf.linkage != LINK.d)
2787             {
2788                 // Promote bytes, words, etc., to ints
2789                 arg = integralPromotions(arg, sc);
2790 
2791                 // Promote floats to doubles
2792                 switch (arg.type.ty)
2793                 {
2794                 case Tfloat32:
2795                     arg = arg.castTo(sc, Type.tfloat64);
2796                     break;
2797 
2798                 case Timaginary32:
2799                     arg = arg.castTo(sc, Type.timaginary64);
2800                     break;
2801 
2802                 default:
2803                     break;
2804                 }
2805                 if (tf.parameterList.varargs == VarArg.variadic ||
2806                     tf.parameterList.varargs == VarArg.KRvariadic)
2807                 {
2808                     const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2809                     if (arg.type.ty == Tarray)
2810                     {
2811                         error(arg.loc, "cannot pass dynamic arrays to `%s` vararg functions", p);
2812                         err = true;
2813                     }
2814                     if (arg.type.ty == Tsarray)
2815                     {
2816                         error(arg.loc, "cannot pass static arrays to `%s` vararg functions", p);
2817                         err = true;
2818                     }
2819                 }
2820             }
2821 
2822             // Do not allow types that need destructors or copy constructors.
2823             if (arg.type.needsDestruction())
2824             {
2825                 error(arg.loc, "cannot pass types that need destruction as variadic arguments");
2826                 err = true;
2827             }
2828             if (arg.type.needsCopyOrPostblit())
2829             {
2830                 error(arg.loc, "cannot pass types with postblits or copy constructors as variadic arguments");
2831                 err = true;
2832             }
2833 
2834             // Convert static arrays to dynamic arrays
2835             // BUG: I don't think this is right for D2
2836             Type tb = arg.type.toBasetype();
2837             if (auto ts = tb.isTypeSArray())
2838             {
2839                 Type ta = ts.next.arrayOf();
2840                 if (ts.size(arg.loc) == 0)
2841                     arg = new NullExp(arg.loc, ta);
2842                 else
2843                     arg = arg.castTo(sc, ta);
2844             }
2845             if (tb.ty == Tstruct)
2846             {
2847                 //arg = callCpCtor(sc, arg);
2848             }
2849             // Give error for overloaded function addresses
2850             if (auto se = arg.isSymOffExp())
2851             {
2852                 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2853                 {
2854                     error(arg.loc, "function `%s` is overloaded", arg.toChars());
2855                     err = true;
2856                 }
2857             }
2858             err |= arg.checkValue();
2859             err |= arg.checkSharedAccess(sc);
2860             err |= checkParamArgumentEscape(sc, fd, Id.dotdotdot, null, cast(STC) tf.parameterList.stc, arg, false, false);
2861             arg = arg.optimize(WANTvalue);
2862         }
2863         (*arguments)[i] = arg;
2864     }
2865 
2866     /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2867      */
2868     const isVa_list = tf.parameterList.varargs == VarArg.none;
2869     if (fd && fd.printf)
2870     {
2871         if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2872         {
2873             checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
2874         }
2875     }
2876     else if (fd && fd.scanf)
2877     {
2878         if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2879         {
2880             checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list, sc.eSink);
2881         }
2882     }
2883     else
2884     {
2885         // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2886     }
2887 
2888     /* Remaining problems:
2889      * 1. value structs (or static arrays of them) that need to be copy constructed
2890      * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2891      *    function gets called.
2892      * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2893      * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2894      * up properly. Pushing arguments on the stack then cannot fail.
2895      */
2896      {
2897         /* Does Problem (3) apply?
2898          */
2899         const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2900 
2901         /* Compute indices of last throwing argument and first arg needing destruction.
2902          * Used to not set up destructors unless an arg needs destruction on a throw
2903          * in a later argument.
2904          */
2905         ptrdiff_t lastthrow = -1;   // last argument that may throw
2906         ptrdiff_t firstdtor = -1;   // first argument that needs destruction
2907         ptrdiff_t lastdtor  = -1;   // last argument that needs destruction
2908         for (ptrdiff_t i = 0; i != nargs; i++)
2909         {
2910             Expression arg = (*arguments)[i];
2911             if (canThrow(arg, sc.func, null))
2912                 lastthrow = i;
2913             if (arg.type.needsDestruction())
2914             {
2915                 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
2916                 if (!(p && (p.isLazy() || p.isReference())))
2917                 {
2918                     if (firstdtor == -1)
2919                         firstdtor = i;
2920                     lastdtor = i;
2921                 }
2922             }
2923         }
2924 
2925         /* Do we need 'eprefix' for problems 2 or 3?
2926          */
2927         const bool needsPrefix = callerDestroysArgs
2928             ? firstdtor >= 0 // true if any argument needs destruction
2929             : firstdtor >= 0 && lastthrow >= 0 &&
2930               (lastthrow - firstdtor) > 0; // last throw after first destruction
2931         const ptrdiff_t lastPrefix = callerDestroysArgs
2932             ? lastdtor   // up to last argument requiring destruction
2933             : lastthrow; // up to last potentially throwing argument
2934 
2935         /* Problem 3: initialize 'eprefix' by declaring the gate
2936          */
2937         VarDeclaration gate;
2938         if (needsPrefix && !callerDestroysArgs)
2939         {
2940             // eprefix => bool __gate [= false]
2941             Identifier idtmp = Identifier.generateId("__gate");
2942             gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2943             gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2944             gate.dsymbolSemantic(sc);
2945 
2946             auto ae = new DeclarationExp(loc, gate);
2947             eprefix = ae.expressionSemantic(sc);
2948         }
2949 
2950         for (ptrdiff_t i = 0; i != nargs; i++)
2951         {
2952             Expression arg = (*arguments)[i];
2953             //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2954 
2955             Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2956             const bool isRef = parameter && parameter.isReference();
2957             const bool isLazy = parameter && parameter.isLazy();
2958 
2959             /* Skip lazy parameters
2960              */
2961             if (isLazy)
2962                 continue;
2963 
2964             /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2965              * Then declare a temporary variable for this arg and append that declaration
2966              * to 'eprefix', which will implicitly take care of potential problem 1) for
2967              * this arg.
2968              * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2969              * excluding all lazy parameters.
2970              */
2971             if (needsPrefix && (lastPrefix - i) >= 0)
2972             {
2973                 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2974                                        // Problem 3: last throwing arg doesn't require dtor patching
2975                                        (callerDestroysArgs || i != lastPrefix);
2976 
2977                 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2978                  */
2979                 auto tmp = copyToTemp(
2980                     (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2981                     needsDtor ? "__pfx" : "__pfy",
2982                     !isRef ? arg : arg.addressOf());
2983                 tmp.dsymbolSemantic(sc);
2984 
2985                 if (callerDestroysArgs)
2986                 {
2987                     /* Problem 4: Normal temporary, destructed after the call
2988                      */
2989                     if (needsDtor)
2990                         tmp.isArgDtorVar = true;   // mark it so that the backend passes it by ref to the function being called
2991                 }
2992                 else
2993                 {
2994                     /* Problem 2: Modify the destructor so it only runs if gate==false,
2995                      * i.e., only if there was a throw while constructing the args
2996                      */
2997                     if (!needsDtor)
2998                     {
2999                         if (tmp.edtor)
3000                         {
3001                             assert(i == lastPrefix);
3002                             tmp.edtor = null;
3003                         }
3004                     }
3005                     else
3006                     {
3007                         // edtor => (__gate || edtor)
3008                         assert(tmp.edtor);
3009                         Expression e = tmp.edtor;
3010                         e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
3011                         tmp.edtor = e.expressionSemantic(sc);
3012                         //printf("edtor: %s\n", tmp.edtor.toChars());
3013                     }
3014                 }
3015 
3016                 // eprefix => (eprefix, auto __pfx/y = arg)
3017                 auto ae = new DeclarationExp(loc, tmp);
3018                 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
3019 
3020                 // arg => __pfx/y
3021                 arg = new VarExp(loc, tmp);
3022                 arg = arg.expressionSemantic(sc);
3023                 if (isRef)
3024                 {
3025                     arg = new PtrExp(loc, arg);
3026                     arg = arg.expressionSemantic(sc);
3027                 }
3028 
3029                 /* Problem 2: Last throwing arg?
3030                  * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
3031                  * dtors right after constructing the last throwing arg.
3032                  * From now on, the callee will take care of destructing the args because
3033                  * the args are implicitly moved into function parameters.
3034                  */
3035                 if (!callerDestroysArgs && i == lastPrefix)
3036                 {
3037                     auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
3038                     eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
3039                 }
3040             }
3041             else // not part of 'eprefix'
3042             {
3043                 /* Handle problem 1) by calling the copy constructor for value structs
3044                  * (or static arrays of them) if appropriate.
3045                  */
3046                 Type tv = arg.type.baseElemOf();
3047                 if (!isRef && tv.ty == Tstruct)
3048                     arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
3049             }
3050 
3051             (*arguments)[i] = arg;
3052         }
3053     }
3054     //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
3055 
3056     /* Test compliance with DIP1021 Argument Ownership and Function Calls
3057      */
3058     if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
3059         tf.islive)
3060         err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
3061 
3062     // If D linkage and variadic, add _arguments[] as first argument
3063     if (tf.isDstyleVariadic())
3064     {
3065         assert(arguments.length >= nparams);
3066 
3067         auto args = new Parameters(arguments.length - nparams);
3068         for (size_t i = 0; i < arguments.length - nparams; i++)
3069         {
3070             Expression earg = (*arguments)[nparams + i];
3071             auto arg = new Parameter(earg.loc, STC.in_, earg.type, null, null, null);
3072             (*args)[i] = arg;
3073         }
3074         auto tup = new TypeTuple(args);
3075         Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
3076         arguments.insert(0, e);
3077     }
3078 
3079     /* Determine function return type: tret
3080      */
3081     Type tret = tf.next;
3082     if (isCtorCall)
3083     {
3084         //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
3085         //    wildmatch, tf.isWild(), fd.isReturnIsolated());
3086         if (!tthis)
3087         {
3088             assert(sc.intypeof || global.errors);
3089             tthis = fd.isThis().type.addMod(fd.type.mod);
3090         }
3091         if (tf.isWild() && !fd.isReturnIsolated())
3092         {
3093             if (wildmatch)
3094                 tret = tret.substWildTo(wildmatch);
3095             int offset;
3096             if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
3097             {
3098                 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
3099                 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
3100                 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
3101                 err = true;
3102             }
3103         }
3104         tret = tthis;
3105     }
3106     else if (wildmatch && tret)
3107     {
3108         /* Adjust function return type based on wildmatch
3109          */
3110         //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
3111         tret = tret.substWildTo(wildmatch);
3112     }
3113 
3114     *prettype = tret;
3115     *peprefix = eprefix;
3116     return (err || olderrors != global.errors);
3117 }
3118 
3119 /**
3120  * Determines whether a symbol represents a module or package
3121  * (Used as a helper for is(type == module) and is(type == package))
3122  *
3123  * Params:
3124  *  sym = the symbol to be checked
3125  *
3126  * Returns:
3127  *  the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
3128  */
3129 Package resolveIsPackage(Dsymbol sym)
3130 {
3131     Package pkg;
3132     if (Import imp = sym.isImport())
3133     {
3134         if (imp.pkg is null)
3135         {
3136             .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
3137                     imp.toChars());
3138             assert(0);
3139         }
3140         pkg = imp.pkg;
3141     }
3142     else if (auto mod = sym.isModule())
3143         pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
3144     else
3145         pkg = sym.isPackage();
3146     if (pkg)
3147         pkg.resolvePKGunknown();
3148     return pkg;
3149 }
3150 
3151 
3152 private extern (C++) final class ExpressionSemanticVisitor : Visitor
3153 {
3154     alias visit = Visitor.visit;
3155 
3156     Scope* sc;
3157     Expression result;
3158 
3159     this(Scope* sc) scope @safe
3160     {
3161         this.sc = sc;
3162     }
3163 
3164     private void setError()
3165     {
3166         result = ErrorExp.get();
3167     }
3168 
3169     private void needThisError(Loc loc, FuncDeclaration f)
3170     {
3171         auto t = f.isThis();
3172         assert(t);
3173         .error(loc, "calling non-static function `%s` requires an instance of type `%s`", f.toChars(), t.toChars());
3174         setError();
3175     }
3176 
3177     /**************************
3178      * Semantically analyze Expression.
3179      * Determine types, fold constants, etc.
3180      */
3181     override void visit(Expression e)
3182     {
3183         static if (LOGSEMANTIC)
3184         {
3185             printf("Expression::semantic() %s\n", e.toChars());
3186         }
3187         if (e.type)
3188             e.type = e.type.typeSemantic(e.loc, sc);
3189         else
3190             e.type = Type.tvoid;
3191         result = e;
3192     }
3193 
3194     override void visit(IntegerExp e)
3195     {
3196         assert(e.type);
3197         if (e.type.ty == Terror)
3198             return setError();
3199 
3200         assert(e.type.deco);
3201         e.setInteger(e.getInteger());
3202         result = e;
3203     }
3204 
3205     override void visit(RealExp e)
3206     {
3207         if (!e.type)
3208             e.type = Type.tfloat64;
3209         else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
3210         {
3211             /* Convert to core.stdc.config.complex
3212              */
3213             Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
3214             if (t.ty == Terror)
3215                 return setError();
3216 
3217             Type tf;
3218             switch (e.type.ty)
3219             {
3220                 case Timaginary32: tf = Type.tfloat32; break;
3221                 case Timaginary64: tf = Type.tfloat64; break;
3222                 case Timaginary80: tf = Type.tfloat80; break;
3223                 default:
3224                     assert(0);
3225             }
3226 
3227             /* Construct ts{re : 0.0, im : e}
3228              */
3229             TypeStruct ts = t.isTypeStruct;
3230             Expressions* elements = new Expressions(2);
3231             (*elements)[0] = new RealExp(e.loc,    CTFloat.zero, tf);
3232             (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
3233             Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
3234             result = sle.expressionSemantic(sc);
3235             return;
3236         }
3237         else
3238             e.type = e.type.typeSemantic(e.loc, sc);
3239         result = e;
3240     }
3241 
3242     override void visit(ComplexExp e)
3243     {
3244         if (!e.type)
3245             e.type = Type.tcomplex80;
3246         else
3247             e.type = e.type.typeSemantic(e.loc, sc);
3248         result = e;
3249     }
3250 
3251     override void visit(IdentifierExp exp)
3252     {
3253         static if (LOGSEMANTIC)
3254         {
3255             printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
3256         }
3257         if (exp.type) // This is used as the dummy expression
3258         {
3259             result = exp;
3260             return;
3261         }
3262 
3263         Dsymbol scopesym;
3264         Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
3265         if (s)
3266         {
3267             if (s.errors)
3268                 return setError();
3269 
3270             Expression e;
3271 
3272             /* See if the symbol was a member of an enclosing 'with'
3273              */
3274             WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
3275             if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
3276             {
3277                 /* Disallow shadowing
3278                  */
3279                 // First find the scope of the with
3280                 Scope* scwith = sc;
3281                 while (scwith.scopesym != scopesym)
3282                 {
3283                     scwith = scwith.enclosing;
3284                     assert(scwith);
3285                 }
3286                 // Look at enclosing scopes for symbols with the same name,
3287                 // in the same function
3288                 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
3289                 {
3290                     Dsymbol s2;
3291                     if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
3292                     {
3293                         error(exp.loc, "with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
3294                         return setError();
3295                     }
3296                 }
3297                 s = s.toAlias();
3298 
3299                 // Same as wthis.ident
3300                 //  TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
3301                 //  The redudancy should be removed.
3302                 e = new VarExp(exp.loc, withsym.withstate.wthis);
3303                 e = new DotIdExp(exp.loc, e, exp.ident);
3304                 e = e.expressionSemantic(sc);
3305             }
3306             else
3307             {
3308                 if (withsym)
3309                 {
3310                     if (withsym.withstate.exp.type.ty != Tvoid)
3311                     {
3312                         // 'with (exp)' is a type expression
3313                         // or 's' is not visible there (for error message)
3314                         e = new TypeExp(exp.loc, withsym.withstate.exp.type);
3315                     }
3316                     else
3317                     {
3318                         // 'with (exp)' is a Package/Module
3319                         e = withsym.withstate.exp;
3320                     }
3321                     e = new DotIdExp(exp.loc, e, exp.ident);
3322                     result = e.expressionSemantic(sc);
3323                     return;
3324                 }
3325 
3326                 /* If f is really a function template,
3327                  * then replace f with the function template declaration.
3328                  */
3329                 FuncDeclaration f = s.isFuncDeclaration();
3330                 if (f)
3331                 {
3332                     TemplateDeclaration td = getFuncTemplateDecl(f);
3333                     if (td)
3334                     {
3335                         if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
3336                             td = td.overroot; // then get the start
3337                         e = new TemplateExp(exp.loc, td, f);
3338                         e = e.expressionSemantic(sc);
3339                         result = e;
3340                         return;
3341                     }
3342                 }
3343 
3344                 if (global.params.fixAliasThis)
3345                 {
3346                     ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
3347                     if (expDsym)
3348                     {
3349                         //printf("expDsym = %s\n", expDsym.exp.toChars());
3350                         result = expDsym.exp.expressionSemantic(sc);
3351                         return;
3352                     }
3353                 }
3354                 // Haven't done overload resolution yet, so pass 1
3355                 e = symbolToExp(s, exp.loc, sc, true);
3356             }
3357             result = e;
3358             return;
3359         }
3360 
3361         if (!global.params.fixAliasThis && hasThis(sc))
3362         {
3363             for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
3364             {
3365                 if (ad.aliasthis)
3366                 {
3367                     Expression e;
3368                     e = new ThisExp(exp.loc);
3369                     e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
3370                     e = new DotIdExp(exp.loc, e, exp.ident);
3371                     e = e.trySemantic(sc);
3372                     if (e)
3373                     {
3374                         result = e;
3375                         return;
3376                     }
3377                 }
3378 
3379                 auto cd = ad.isClassDeclaration();
3380                 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
3381                 {
3382                     ad = cd.baseClass;
3383                     continue;
3384                 }
3385                 break;
3386             }
3387         }
3388 
3389         if (exp.ident == Id.ctfe)
3390         {
3391             if (sc.flags & SCOPE.ctfe)
3392             {
3393                 error(exp.loc, "variable `__ctfe` cannot be read at compile time");
3394                 return setError();
3395             }
3396 
3397             // Create the magic __ctfe bool variable
3398             auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
3399             vd.storage_class |= STC.temp;
3400             vd.semanticRun = PASS.semanticdone;
3401             Expression e = new VarExp(exp.loc, vd);
3402             e = e.expressionSemantic(sc);
3403             result = e;
3404             return;
3405         }
3406 
3407         // If we've reached this point and are inside a with() scope then we may
3408         // try one last attempt by checking whether the 'wthis' object supports
3409         // dynamic dispatching via opDispatch.
3410         // This is done by rewriting this expression as wthis.ident.
3411         // The innermost with() scope of the hierarchy to satisfy the condition
3412         // above wins.
3413         // https://issues.dlang.org/show_bug.cgi?id=6400
3414         for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
3415         {
3416             if (!sc2.scopesym)
3417                 continue;
3418 
3419             if (auto ss = sc2.scopesym.isWithScopeSymbol())
3420             {
3421                 if (ss.withstate.wthis)
3422                 {
3423                     Expression e;
3424                     e = new VarExp(exp.loc, ss.withstate.wthis);
3425                     e = new DotIdExp(exp.loc, e, exp.ident);
3426                     e = e.trySemantic(sc);
3427                     if (e)
3428                     {
3429                         result = e;
3430                         return;
3431                     }
3432                 }
3433                 // Try Type.opDispatch (so the static version)
3434                 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
3435                 {
3436                     if (Type t = ss.withstate.exp.isTypeExp().type)
3437                     {
3438                         Expression e;
3439                         e = new TypeExp(exp.loc, t);
3440                         e = new DotIdExp(exp.loc, e, exp.ident);
3441                         e = e.trySemantic(sc);
3442                         if (e)
3443                         {
3444                             result = e;
3445                             return;
3446                         }
3447                     }
3448                 }
3449             }
3450         }
3451 
3452         /* Look for what user might have meant
3453          */
3454         if (const n = importHint(exp.ident.toString()))
3455             error(exp.loc, "`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
3456         else if (auto s2 = sc.search_correct(exp.ident))
3457             error(exp.loc, "undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
3458         else if (const p = Scope.search_correct_C(exp.ident))
3459             error(exp.loc, "undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
3460         else if (exp.ident == Id.dollar)
3461             error(exp.loc, "undefined identifier `$`");
3462         else
3463             error(exp.loc, "undefined identifier `%s`", exp.ident.toChars());
3464 
3465         result = ErrorExp.get();
3466     }
3467 
3468     override void visit(DsymbolExp e)
3469     {
3470         result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
3471     }
3472 
3473     override void visit(ThisExp e)
3474     {
3475         static if (LOGSEMANTIC)
3476         {
3477             printf("ThisExp::semantic()\n");
3478         }
3479         if (e.type)
3480         {
3481             result = e;
3482             return;
3483         }
3484 
3485         FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
3486         AggregateDeclaration ad;
3487 
3488         /* Special case for typeof(this) and typeof(super) since both
3489          * should work even if they are not inside a non-static member function
3490          */
3491         if (!fd && sc.intypeof == 1)
3492         {
3493             // Find enclosing struct or class
3494             for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
3495             {
3496                 if (!s)
3497                 {
3498                     error(e.loc, "`%s` is not in a class or struct scope", e.toChars());
3499                     return setError();
3500                 }
3501                 ClassDeclaration cd = s.isClassDeclaration();
3502                 if (cd)
3503                 {
3504                     e.type = cd.type;
3505                     result = e;
3506                     return;
3507                 }
3508                 StructDeclaration sd = s.isStructDeclaration();
3509                 if (sd)
3510                 {
3511                     e.type = sd.type;
3512                     result = e;
3513                     return;
3514                 }
3515             }
3516         }
3517         if (!fd)
3518         {
3519             error(e.loc, "`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
3520             return setError();
3521         }
3522 
3523         assert(fd.vthis);
3524         e.var = fd.vthis;
3525         assert(e.var.parent);
3526         ad = fd.isMemberLocal();
3527         if (!ad)
3528             ad = fd.isMember2();
3529         assert(ad);
3530         e.type = ad.type.addMod(e.var.type.mod);
3531 
3532         if (e.var.checkNestedReference(sc, e.loc))
3533             return setError();
3534 
3535         result = e;
3536     }
3537 
3538     override void visit(SuperExp e)
3539     {
3540         static if (LOGSEMANTIC)
3541         {
3542             printf("SuperExp::semantic('%s')\n", e.toChars());
3543         }
3544         if (e.type)
3545         {
3546             result = e;
3547             return;
3548         }
3549 
3550         FuncDeclaration fd = hasThis(sc);
3551         ClassDeclaration cd;
3552         Dsymbol s;
3553 
3554         /* Special case for typeof(this) and typeof(super) since both
3555          * should work even if they are not inside a non-static member function
3556          */
3557         if (!fd && sc.intypeof == 1)
3558         {
3559             // Find enclosing class
3560             for (s = sc.getStructClassScope(); 1; s = s.parent)
3561             {
3562                 if (!s)
3563                 {
3564                     error(e.loc, "`%s` is not in a class scope", e.toChars());
3565                     return setError();
3566                 }
3567                 cd = s.isClassDeclaration();
3568                 if (cd)
3569                 {
3570                     cd = cd.baseClass;
3571                     if (!cd)
3572                     {
3573                         error(e.loc, "class `%s` has no `super`", s.toChars());
3574                         return setError();
3575                     }
3576                     e.type = cd.type;
3577                     result = e;
3578                     return;
3579                 }
3580             }
3581         }
3582         if (!fd)
3583             goto Lerr;
3584 
3585         e.var = fd.vthis;
3586         assert(e.var && e.var.parent);
3587 
3588         s = fd.toParentDecl();
3589         if (s.isTemplateDeclaration()) // allow inside template constraint
3590             s = s.toParent();
3591         assert(s);
3592         cd = s.isClassDeclaration();
3593         //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3594         if (!cd)
3595             goto Lerr;
3596         if (!cd.baseClass)
3597         {
3598             error(e.loc, "no base class for `%s`", cd.toChars());
3599             e.type = cd.type.addMod(e.var.type.mod);
3600         }
3601         else
3602         {
3603             e.type = cd.baseClass.type;
3604             e.type = e.type.castMod(e.var.type.mod);
3605         }
3606 
3607         if (e.var.checkNestedReference(sc, e.loc))
3608             return setError();
3609 
3610         result = e;
3611         return;
3612 
3613     Lerr:
3614         error(e.loc, "`super` is only allowed in non-static class member functions");
3615         result = ErrorExp.get();
3616     }
3617 
3618     override void visit(NullExp e)
3619     {
3620         static if (LOGSEMANTIC)
3621         {
3622             printf("NullExp::semantic('%s')\n", e.toChars());
3623         }
3624         // NULL is the same as (void *)0
3625         if (e.type)
3626         {
3627             result = e;
3628             return;
3629         }
3630         e.type = Type.tnull;
3631         result = e;
3632     }
3633 
3634     override void visit(StringExp e)
3635     {
3636         static if (LOGSEMANTIC)
3637         {
3638             printf("StringExp::semantic() %s\n", e.toChars());
3639         }
3640         if (e.type)
3641         {
3642             result = e;
3643             return;
3644         }
3645 
3646         OutBuffer buffer;
3647         size_t newlen = 0;
3648         size_t u;
3649         dchar c;
3650 
3651         switch (e.postfix)
3652         {
3653         case 'd':
3654             for (u = 0; u < e.len;)
3655             {
3656                 if (const p = utf_decodeChar(e.peekString(), u, c))
3657                 {
3658                     error(e.loc, "%.*s", cast(int)p.length, p.ptr);
3659                     return setError();
3660                 }
3661                 else
3662                 {
3663                     buffer.write4(c);
3664                     newlen++;
3665                 }
3666             }
3667             buffer.write4(0);
3668             e.setData(buffer.extractData(), newlen, 4);
3669             if (sc && sc.flags & SCOPE.Cfile)
3670                 e.type = Type.tuns32.sarrayOf(e.len + 1);
3671             else
3672                 e.type = Type.tdchar.immutableOf().arrayOf();
3673             e.committed = true;
3674             break;
3675 
3676         case 'w':
3677             for (u = 0; u < e.len;)
3678             {
3679                 if (const p = utf_decodeChar(e.peekString(), u, c))
3680                 {
3681                     error(e.loc, "%.*s", cast(int)p.length, p.ptr);
3682                     return setError();
3683                 }
3684                 else
3685                 {
3686                     buffer.writeUTF16(c);
3687                     newlen++;
3688                     if (c >= 0x10000)
3689                         newlen++;
3690                 }
3691             }
3692             buffer.writeUTF16(0);
3693             e.setData(buffer.extractData(), newlen, 2);
3694             if (sc && sc.flags & SCOPE.Cfile)
3695                 e.type = Type.tuns16.sarrayOf(e.len + 1);
3696             else
3697                 e.type = Type.twchar.immutableOf().arrayOf();
3698             e.committed = true;
3699             break;
3700 
3701         case 'c':
3702             e.committed = true;
3703             goto default;
3704 
3705         default:
3706             if (sc && sc.flags & SCOPE.Cfile)
3707                 e.type = Type.tchar.sarrayOf(e.len + 1);
3708             else
3709                 e.type = Type.tchar.immutableOf().arrayOf();
3710             break;
3711         }
3712         e.type = e.type.typeSemantic(e.loc, sc);
3713         //type = type.immutableOf();
3714         //printf("type = %s\n", type.toChars());
3715 
3716         result = e;
3717     }
3718 
3719     override void visit(TupleExp exp)
3720     {
3721         static if (LOGSEMANTIC)
3722         {
3723             printf("+TupleExp::semantic(%s)\n", exp.toChars());
3724         }
3725         if (exp.type)
3726         {
3727             result = exp;
3728             return;
3729         }
3730 
3731         if (exp.e0)
3732             exp.e0 = exp.e0.expressionSemantic(sc);
3733 
3734         // Run semantic() on each argument
3735         bool err = false;
3736         for (size_t i = 0; i < exp.exps.length; i++)
3737         {
3738             Expression e = (*exp.exps)[i];
3739             e = e.expressionSemantic(sc);
3740             if (!e.type)
3741             {
3742                 error(exp.loc, "`%s` has no value", e.toChars());
3743                 err = true;
3744             }
3745             else if (e.op == EXP.error)
3746                 err = true;
3747             else
3748                 (*exp.exps)[i] = e;
3749         }
3750         if (err)
3751             return setError();
3752 
3753         expandTuples(exp.exps);
3754 
3755         exp.type = new TypeTuple(exp.exps);
3756         exp.type = exp.type.typeSemantic(exp.loc, sc);
3757         //printf("-TupleExp::semantic(%s)\n", toChars());
3758         result = exp;
3759     }
3760 
3761     override void visit(ArrayLiteralExp e)
3762     {
3763         static if (LOGSEMANTIC)
3764         {
3765             printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3766         }
3767         if (e.type)
3768         {
3769             result = e;
3770             return;
3771         }
3772 
3773         /* Perhaps an empty array literal [ ] should be rewritten as null?
3774          */
3775 
3776         if (e.basis)
3777             e.basis = e.basis.expressionSemantic(sc);
3778         if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
3779             return setError();
3780 
3781         expandTuples(e.elements);
3782 
3783         if (e.basis)
3784             e.elements.push(e.basis);
3785         Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3786         if (e.basis)
3787             e.basis = e.elements.pop();
3788         if (t0 is null)
3789             return setError();
3790 
3791         e.type = t0.arrayOf();
3792         e.type = e.type.typeSemantic(e.loc, sc);
3793 
3794         /* Disallow array literals of type void being used.
3795          */
3796         if (e.elements.length > 0 && t0.ty == Tvoid)
3797         {
3798             error(e.loc, "`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
3799             return setError();
3800         }
3801 
3802         if (global.params.useTypeInfo && Type.dtypeinfo)
3803             semanticTypeInfo(sc, e.type);
3804 
3805         result = e;
3806     }
3807 
3808     override void visit(AssocArrayLiteralExp e)
3809     {
3810         static if (LOGSEMANTIC)
3811         {
3812             printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3813         }
3814         if (e.type)
3815         {
3816             result = e;
3817             return;
3818         }
3819 
3820         // Run semantic() on each element
3821         bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
3822         bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
3823         if (err_keys || err_vals)
3824             return setError();
3825 
3826         expandTuples(e.keys);
3827         expandTuples(e.values);
3828         if (e.keys.length != e.values.length)
3829         {
3830             error(e.loc, "number of keys is %llu, must match number of values %llu",
3831                         cast(ulong) e.keys.length, cast(ulong) e.values.length);
3832             return setError();
3833         }
3834 
3835         Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3836         Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3837         if (tkey is null || tvalue is null)
3838             return setError();
3839 
3840         e.type = new TypeAArray(tvalue, tkey);
3841         e.type = e.type.typeSemantic(e.loc, sc);
3842 
3843         semanticTypeInfo(sc, e.type);
3844 
3845         if (checkAssocArrayLiteralEscape(sc, e, false))
3846             return setError();
3847 
3848         result = e;
3849     }
3850 
3851     override void visit(StructLiteralExp e)
3852     {
3853         static if (LOGSEMANTIC)
3854         {
3855             printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3856         }
3857         if (e.type)
3858         {
3859             result = e;
3860             return;
3861         }
3862 
3863         e.sd.size(e.loc);
3864         if (e.sd.sizeok != Sizeok.done)
3865             return setError();
3866 
3867         // run semantic() on each element
3868         if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
3869             return setError();
3870 
3871         expandTuples(e.elements);
3872 
3873         /* Fit elements[] to the corresponding type of field[].
3874          */
3875         if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
3876             return setError();
3877 
3878         /* Fill out remainder of elements[] with default initializers for fields[]
3879          */
3880         if (!e.sd.fill(e.loc, *e.elements, false))
3881         {
3882             /* An error in the initializer needs to be recorded as an error
3883              * in the enclosing function or template, since the initializer
3884              * will be part of the stuct declaration.
3885              */
3886             global.increaseErrorCount();
3887             return setError();
3888         }
3889 
3890         if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
3891             return setError();
3892 
3893         e.type = e.stype ? e.stype : e.sd.type;
3894         result = e;
3895     }
3896 
3897     override void visit(CompoundLiteralExp cle)
3898     {
3899         static if (LOGSEMANTIC)
3900         {
3901             printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
3902         }
3903         Type t = cle.type.typeSemantic(cle.loc, sc);
3904         auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
3905         auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
3906         if (!e)
3907         {
3908             error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3909             return setError();
3910         }
3911         result = e;
3912         return;
3913     }
3914 
3915     override void visit(TypeExp exp)
3916     {
3917         if (exp.type.ty == Terror)
3918             return setError();
3919 
3920         //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3921         Expression e;
3922         Type t;
3923         Dsymbol s;
3924 
3925         dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3926         if (e)
3927         {
3928             // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3929             // then rewrite as `(this.var)` in case it would be followed by a DotVar
3930             // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3931             VarExp ve = e.isVarExp();
3932             if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
3933                 sc.func && sc.func.needThis && ve.var.isMember2())
3934             {
3935                 // printf("apply fix for bugzilla issue 9490: add `this.` to `%s`...\n", e.toChars());
3936                 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
3937             }
3938             //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3939             e = e.expressionSemantic(sc);
3940         }
3941         else if (t)
3942         {
3943             //printf("t = %d %s\n", t.ty, t.toChars());
3944             exp.type = t.typeSemantic(exp.loc, sc);
3945             e = exp;
3946         }
3947         else if (s)
3948         {
3949             //printf("s = %s %s\n", s.kind(), s.toChars());
3950             e = symbolToExp(s, exp.loc, sc, true);
3951         }
3952         else
3953             assert(0);
3954 
3955         exp.type.checkComplexTransition(exp.loc, sc);
3956 
3957         result = e;
3958     }
3959 
3960     override void visit(ScopeExp exp)
3961     {
3962         static if (LOGSEMANTIC)
3963         {
3964             printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3965         }
3966         if (exp.type)
3967         {
3968             result = exp;
3969             return;
3970         }
3971 
3972         ScopeDsymbol sds2 = exp.sds;
3973         TemplateInstance ti = sds2.isTemplateInstance();
3974         while (ti)
3975         {
3976             WithScopeSymbol withsym;
3977             if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3978                 return setError();
3979             if (withsym && withsym.withstate.wthis)
3980             {
3981                 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
3982                 e = new DotTemplateInstanceExp(exp.loc, e, ti);
3983                 result = e.expressionSemantic(sc);
3984                 return;
3985             }
3986             if (ti.needsTypeInference(sc))
3987             {
3988                 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
3989                 {
3990                     Dsymbol p = td.toParentLocal();
3991                     FuncDeclaration fdthis = hasThis(sc);
3992                     AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
3993                     if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
3994                     {
3995                         Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3996                         result = e.expressionSemantic(sc);
3997                         return;
3998                     }
3999                 }
4000                 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
4001                 {
4002                     FuncDeclaration fdthis = hasThis(sc);
4003                     AggregateDeclaration ad = os.parent.isAggregateDeclaration();
4004                     if (fdthis && ad && fdthis.isMemberLocal() == ad)
4005                     {
4006                         Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
4007                         result = e.expressionSemantic(sc);
4008                         return;
4009                     }
4010                 }
4011                 // ti is an instance which requires IFTI.
4012                 exp.sds = ti;
4013                 exp.type = Type.tvoid;
4014                 result = exp;
4015                 return;
4016             }
4017             ti.dsymbolSemantic(sc);
4018             if (!ti.inst || ti.errors)
4019                 return setError();
4020 
4021             Dsymbol s = ti.toAlias();
4022             if (s == ti)
4023             {
4024                 exp.sds = ti;
4025                 exp.type = Type.tvoid;
4026                 result = exp;
4027                 return;
4028             }
4029             sds2 = s.isScopeDsymbol();
4030             if (sds2)
4031             {
4032                 ti = sds2.isTemplateInstance();
4033                 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4034                 continue;
4035             }
4036 
4037             if (auto v = s.isVarDeclaration())
4038             {
4039                 if (!v.type)
4040                 {
4041                     error(exp.loc, "forward reference of %s `%s`", v.kind(), v.toChars());
4042                     return setError();
4043                 }
4044                 if ((v.storage_class & STC.manifest) && v._init)
4045                 {
4046                     /* When an instance that will be converted to a constant exists,
4047                      * the instance representation "foo!tiargs" is treated like a
4048                      * variable name, and its recursive appearance check (note that
4049                      * it's equivalent with a recursive instantiation of foo) is done
4050                      * separately from the circular initialization check for the
4051                      * eponymous enum variable declaration.
4052                      *
4053                      *  template foo(T) {
4054                      *    enum bool foo = foo;    // recursive definition check (v.inuse)
4055                      *  }
4056                      *  template bar(T) {
4057                      *    enum bool bar = bar!T;  // recursive instantiation check (ti.inuse)
4058                      *  }
4059                      */
4060                     if (ti.inuse)
4061                     {
4062                         error(exp.loc, "recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
4063                         return setError();
4064                     }
4065                     v.checkDeprecated(exp.loc, sc);
4066                     auto e = v.expandInitializer(exp.loc);
4067                     ti.inuse++;
4068                     e = e.expressionSemantic(sc);
4069                     ti.inuse--;
4070                     result = e;
4071                     return;
4072                 }
4073             }
4074 
4075             //printf("s = %s, '%s'\n", s.kind(), s.toChars());
4076             auto e = symbolToExp(s, exp.loc, sc, true);
4077             //printf("-1ScopeExp::semantic()\n");
4078             result = e;
4079             return;
4080         }
4081 
4082         //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
4083         //printf("\tparent = '%s'\n", sds2.parent.toChars());
4084         sds2.dsymbolSemantic(sc);
4085 
4086         // (Aggregate|Enum)Declaration
4087         if (auto t = sds2.getType())
4088         {
4089             result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
4090             return;
4091         }
4092 
4093         if (auto td = sds2.isTemplateDeclaration())
4094         {
4095             result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
4096             return;
4097         }
4098 
4099         exp.sds = sds2;
4100         exp.type = Type.tvoid;
4101         //printf("-2ScopeExp::semantic() %s\n", toChars());
4102         result = exp;
4103     }
4104 
4105     /**
4106      * Sets the `lowering` field of a `NewExp` to a call to `_d_newitemT` unless
4107      * compiling with `-betterC` or within `__traits(compiles)`.
4108      *
4109      * Params:
4110      *  ne = the `NewExp` to lower
4111      */
4112     private void tryLowerToNewItem(NewExp ne)
4113     {
4114         if (!global.params.useGC || !sc.needsCodegen())
4115             return;
4116 
4117         auto hook = global.params.tracegc ? Id._d_newitemTTrace : Id._d_newitemT;
4118         if (!verifyHookExist(ne.loc, *sc, hook, "new struct"))
4119             return;
4120 
4121         /* Lower the memory allocation and initialization of `new T()` to
4122          * `_d_newitemT!T()`.
4123          */
4124         Expression id = new IdentifierExp(ne.loc, Id.empty);
4125         id = new DotIdExp(ne.loc, id, Id.object);
4126         auto tiargs = new Objects();
4127         /*
4128          * Remove `inout`, `const`, `immutable` and `shared` to reduce the
4129          * number of generated `_d_newitemT` instances.
4130          */
4131         auto t = ne.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
4132             MODFlags.immutable_ | MODFlags.shared_);
4133         tiargs.push(t);
4134         id = new DotTemplateInstanceExp(ne.loc, id, hook, tiargs);
4135 
4136         auto arguments = new Expressions();
4137         if (global.params.tracegc)
4138         {
4139             auto funcname = (sc.callsc && sc.callsc.func) ?
4140                 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4141             arguments.push(new StringExp(ne.loc, ne.loc.filename.toDString()));
4142             arguments.push(new IntegerExp(ne.loc, ne.loc.linnum, Type.tint32));
4143             arguments.push(new StringExp(ne.loc, funcname.toDString()));
4144         }
4145         id = new CallExp(ne.loc, id, arguments);
4146 
4147         ne.lowering = id.expressionSemantic(sc);
4148     }
4149 
4150     override void visit(NewExp exp)
4151     {
4152         static if (LOGSEMANTIC)
4153         {
4154             printf("NewExp::semantic() %s\n", exp.toChars());
4155             if (exp.thisexp)
4156                 printf("\tthisexp = %s\n", exp.thisexp.toChars());
4157             printf("\tnewtype: %s\n", exp.newtype.toChars());
4158         }
4159         if (exp.type) // if semantic() already run
4160         {
4161             result = exp;
4162             return;
4163         }
4164 
4165         //for error messages if the argument in [] is not convertible to size_t
4166         const originalNewtype = exp.newtype;
4167 
4168         // https://issues.dlang.org/show_bug.cgi?id=11581
4169         // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
4170         // T should be analyzed first and edim should go into arguments iff it's
4171         // not a tuple.
4172         Expression edim = null;
4173         if (!exp.arguments && exp.newtype.isTypeSArray())
4174         {
4175             auto ts = exp.newtype.isTypeSArray();
4176             // check `new Value[Key]`
4177             ts.dim = ts.dim.expressionSemantic(sc);
4178             if (ts.dim.op == EXP.type)
4179             {
4180                 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
4181             }
4182             else
4183             {
4184                 edim = ts.dim;
4185                 exp.newtype = ts.next;
4186             }
4187         }
4188 
4189         ClassDeclaration cdthis = null;
4190         if (exp.thisexp)
4191         {
4192             exp.thisexp = exp.thisexp.expressionSemantic(sc);
4193             if (exp.thisexp.op == EXP.error)
4194                 return setError();
4195 
4196             cdthis = exp.thisexp.type.isClassHandle();
4197             if (!cdthis)
4198             {
4199                 error(exp.loc, "`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
4200                 return setError();
4201             }
4202 
4203             sc = sc.push(cdthis);
4204             exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4205             sc = sc.pop();
4206         }
4207         else
4208         {
4209             exp.type = exp.newtype.typeSemantic(exp.loc, sc);
4210         }
4211         if (exp.type.ty == Terror)
4212             return setError();
4213 
4214         if (edim)
4215         {
4216             if (exp.type.toBasetype().ty == Ttuple)
4217             {
4218                 // --> new T[edim]
4219                 exp.type = new TypeSArray(exp.type, edim);
4220                 exp.type = exp.type.typeSemantic(exp.loc, sc);
4221                 if (exp.type.ty == Terror)
4222                     return setError();
4223             }
4224             else
4225             {
4226                 // --> new T[](edim)
4227                 exp.arguments = new Expressions();
4228                 exp.arguments.push(edim);
4229                 exp.type = exp.type.arrayOf();
4230             }
4231         }
4232 
4233         exp.newtype = exp.type; // in case type gets cast to something else
4234         Type tb = exp.type.toBasetype();
4235         //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
4236         if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
4237         {
4238             return setError();
4239         }
4240         if (preFunctionParameters(sc, exp.argumentList))
4241         {
4242             return setError();
4243         }
4244 
4245         if (exp.thisexp && tb.ty != Tclass)
4246         {
4247             error(exp.loc, "`.new` is only for allocating nested classes, not `%s`", tb.toChars());
4248             return setError();
4249         }
4250 
4251         const size_t nargs = exp.arguments ? exp.arguments.length : 0;
4252         Expression newprefix = null;
4253 
4254         if (auto tc = tb.isTypeClass())
4255         {
4256             auto cd = tc.sym;
4257             if (cd.errors)
4258                 return setError();
4259             cd.size(exp.loc);
4260             if (cd.sizeok != Sizeok.done)
4261                 return setError();
4262             if (!cd.ctor)
4263                 cd.ctor = cd.searchCtor();
4264             if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
4265             {
4266                 error(exp.loc, "default construction is disabled for type `%s`", cd.type.toChars());
4267                 return setError();
4268             }
4269 
4270             if (cd.isInterfaceDeclaration())
4271             {
4272                 error(exp.loc, "cannot create instance of interface `%s`", cd.toChars());
4273                 return setError();
4274             }
4275 
4276             if (cd.isAbstract())
4277             {
4278                 error(exp.loc, "cannot create instance of abstract class `%s`", cd.toChars());
4279                 errorSupplemental(cd.loc, "class `%s` is declared here", cd.toChars());
4280                 for (size_t i = 0; i < cd.vtbl.length; i++)
4281                 {
4282                     FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
4283                     if (fd && fd.isAbstract())
4284                     {
4285                         errorSupplemental(fd.loc, "function `%s` is not implemented",
4286                             fd.toFullSignature());
4287                     }
4288                 }
4289                 return setError();
4290             }
4291             // checkDeprecated() is already done in newtype.typeSemantic().
4292 
4293             if (cd.isNested())
4294             {
4295                 /* We need a 'this' pointer for the nested class.
4296                  * Ensure we have the right one.
4297                  */
4298                 Dsymbol s = cd.toParentLocal();
4299 
4300                 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
4301                 if (auto cdn = s.isClassDeclaration())
4302                 {
4303                     if (!cdthis)
4304                     {
4305                         void noReferenceToOuterClass()
4306                         {
4307                             if (cd.isAnonymous)
4308                                 error(exp.loc, "cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
4309                             else
4310                                 error(exp.loc, "cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
4311                                     cd.toChars(), cdn.toChars());
4312                             return setError();
4313                         }
4314 
4315                         if (!sc.hasThis)
4316                             return noReferenceToOuterClass();
4317 
4318                         // Supply an implicit 'this' and try again
4319                         exp.thisexp = new ThisExp(exp.loc);
4320                         for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
4321                         {
4322                             if (!sp)
4323                                 return noReferenceToOuterClass();
4324                             ClassDeclaration cdp = sp.isClassDeclaration();
4325                             if (!cdp)
4326                                 continue;
4327                             if (cdp == cdn || cdn.isBaseOf(cdp, null))
4328                                 break;
4329                             // Add a '.outer' and try again
4330                             exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
4331                         }
4332 
4333                         exp.thisexp = exp.thisexp.expressionSemantic(sc);
4334                         if (exp.thisexp.op == EXP.error)
4335                             return setError();
4336                         cdthis = exp.thisexp.type.isClassHandle();
4337                     }
4338                     if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
4339                     {
4340                         //printf("cdthis = %s\n", cdthis.toChars());
4341                         error(exp.loc, "`this` for nested class must be of type `%s`, not `%s`",
4342                             cdn.toChars(), exp.thisexp.type.toChars());
4343                         return setError();
4344                     }
4345                     if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
4346                     {
4347                         error(exp.loc, "nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
4348                             exp.newtype.toChars(), exp.thisexp.type.toChars());
4349                         return setError();
4350                     }
4351                 }
4352                 else if (exp.thisexp)
4353                 {
4354                     error(exp.loc, "`.new` is only for allocating nested classes");
4355                     return setError();
4356                 }
4357                 else if (auto fdn = s.isFuncDeclaration())
4358                 {
4359                     // make sure the parent context fdn of cd is reachable from sc
4360                     if (!ensureStaticLinkTo(sc.parent, fdn))
4361                     {
4362                         error(exp.loc, "outer function context of `%s` is needed to `new` nested class `%s`",
4363                             fdn.toPrettyChars(), cd.toPrettyChars());
4364                         return setError();
4365                     }
4366                 }
4367                 else
4368                     assert(0);
4369             }
4370             else if (exp.thisexp)
4371             {
4372                 error(exp.loc, "`.new` is only for allocating nested classes");
4373                 return setError();
4374             }
4375 
4376             if (cd.vthis2)
4377             {
4378                 if (AggregateDeclaration ad2 = cd.isMember2())
4379                 {
4380                     Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
4381                     if (te.op != EXP.error)
4382                         te = getRightThis(exp.loc, sc, ad2, te, cd);
4383                     if (te.op == EXP.error)
4384                     {
4385                         error(exp.loc, "need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
4386                         return setError();
4387                     }
4388                 }
4389             }
4390 
4391             if (cd.disableNew && !exp.onstack)
4392             {
4393                 error(exp.loc, "cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
4394                           originalNewtype.toChars());
4395                 return setError();
4396             }
4397 
4398             if (cd.ctor)
4399             {
4400                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
4401                 if (!f || f.errors)
4402                     return setError();
4403 
4404                 checkFunctionAttributes(exp, sc, f);
4405                 checkAccess(cd, exp.loc, sc, f);
4406 
4407                 TypeFunction tf = f.type.isTypeFunction();
4408                 if (!exp.arguments)
4409                     exp.arguments = new Expressions();
4410                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
4411                     return setError();
4412 
4413                 exp.member = f.isCtorDeclaration();
4414                 assert(exp.member);
4415             }
4416             else
4417             {
4418                 if (nargs)
4419                 {
4420                     error(exp.loc, "no constructor for `%s`", cd.toChars());
4421                     return setError();
4422                 }
4423 
4424                 // https://issues.dlang.org/show_bug.cgi?id=19941
4425                 // Run semantic on all field initializers to resolve any forward
4426                 // references. This is the same as done for structs in sd.fill().
4427                 for (ClassDeclaration c = cd; c; c = c.baseClass)
4428                 {
4429                     foreach (v; c.fields)
4430                     {
4431                         if (v.inuse || v._scope is null || v._init is null ||
4432                             v._init.isVoidInitializer() || v.semanticRun >= PASS.semantic2done)
4433                             continue;
4434                         v.inuse++;
4435                         v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
4436                         import dmd.semantic2 : lowerStaticAAs;
4437                         lowerStaticAAs(v, sc);
4438                         v.inuse--;
4439                     }
4440                 }
4441             }
4442 
4443             // When using `@nogc` exception handling, lower `throw new E(args)` to
4444             // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
4445             if (global.params.ehnogc && exp.thrownew &&
4446                 !cd.isCOMclass() && !cd.isCPPclass())
4447             {
4448                 assert(cd.ctor);
4449 
4450                 Expression id = new IdentifierExp(exp.loc, Id.empty);
4451                 id = new DotIdExp(exp.loc, id, Id.object);
4452 
4453                 auto tiargs = new Objects();
4454                 tiargs.push(exp.newtype);
4455                 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
4456                 id = new CallExp(exp.loc, id).expressionSemantic(sc);
4457 
4458                 Expression idVal;
4459                 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
4460                 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
4461 
4462                 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
4463                 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
4464 
4465                 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
4466                 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
4467                 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
4468 
4469                 result = id.expressionSemantic(sc);
4470                 return;
4471             }
4472             else if (sc.needsCodegen() && // interpreter doesn't need this lowered
4473                      !exp.onstack && !exp.type.isscope()) // these won't use the GC
4474             {
4475                 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
4476                  * or `_d_newclassTTrace`
4477                  */
4478                 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
4479                 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
4480                     return setError();
4481 
4482                 Expression id = new IdentifierExp(exp.loc, Id.empty);
4483                 id = new DotIdExp(exp.loc, id, Id.object);
4484 
4485                 auto tiargs = new Objects();
4486                 auto t = exp.newtype.unqualify(MODFlags.wild);  // remove `inout`
4487                 tiargs.push(t);
4488                 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
4489                 auto arguments = new Expressions();
4490                 if (global.params.tracegc)
4491                 {
4492                     auto funcname = (sc.callsc && sc.callsc.func) ?
4493                         sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4494                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
4495                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
4496                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
4497                 }
4498                 id = new CallExp(exp.loc, id, arguments);
4499 
4500                 exp.lowering = id.expressionSemantic(sc);
4501             }
4502         }
4503         else if (auto ts = tb.isTypeStruct())
4504         {
4505             auto sd = ts.sym;
4506             sd.size(exp.loc);
4507             if (sd.sizeok != Sizeok.done)
4508                 return setError();
4509             if (!sd.ctor)
4510                 sd.ctor = sd.searchCtor();
4511             if (sd.noDefaultCtor && !nargs)
4512             {
4513                 error(exp.loc, "default construction is disabled for type `%s`", sd.type.toChars());
4514                 return setError();
4515             }
4516             // checkDeprecated() is already done in newtype.typeSemantic().
4517 
4518             if (sd.disableNew)
4519             {
4520                 error(exp.loc, "cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
4521                           originalNewtype.toChars());
4522                 return setError();
4523             }
4524 
4525             // https://issues.dlang.org/show_bug.cgi?id=22639
4526             // If the new expression has arguments, we either should call a
4527             // regular constructor of a copy constructor if the first argument
4528             // is the same type as the struct
4529             if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
4530             {
4531                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
4532                 if (!f || f.errors)
4533                     return setError();
4534 
4535                 checkFunctionAttributes(exp, sc, f);
4536                 checkAccess(sd, exp.loc, sc, f);
4537 
4538                 TypeFunction tf = f.type.isTypeFunction();
4539                 if (!exp.arguments)
4540                     exp.arguments = new Expressions();
4541                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
4542                     return setError();
4543 
4544                 exp.member = f.isCtorDeclaration();
4545                 assert(exp.member);
4546 
4547                 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
4548                     return setError();
4549             }
4550             else
4551             {
4552                 if (exp.names)
4553                 {
4554                     exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
4555                         exp.names ? (*exp.names)[] : null,
4556                         (size_t i, Type t) => (*exp.arguments)[i],
4557                         i => (*exp.arguments)[i].loc
4558                     );
4559                     if (!exp.arguments)
4560                         return setError();
4561                 }
4562                 else if (!exp.arguments)
4563                 {
4564                     exp.arguments = new Expressions();
4565                 }
4566 
4567                 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
4568                     return setError();
4569 
4570                 if (!sd.fill(exp.loc, *exp.arguments, false))
4571                     return setError();
4572 
4573                 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
4574                     return setError();
4575 
4576                 /* Since a `new` allocation may escape, check each of the arguments for escaping
4577                  */
4578                 foreach (arg; *exp.arguments)
4579                 {
4580                     if (arg && checkNewEscape(sc, arg, false))
4581                         return setError();
4582                 }
4583             }
4584 
4585             exp.type = exp.type.pointerTo();
4586             tryLowerToNewItem(exp);
4587         }
4588         else if (tb.ty == Tarray)
4589         {
4590             if (!nargs)
4591             {
4592                 // https://issues.dlang.org/show_bug.cgi?id=20422
4593                 // Without this check the compiler would give a misleading error
4594                 error(exp.loc, "missing length argument for array");
4595                 return setError();
4596             }
4597 
4598             Type tn = tb.nextOf().baseElemOf();
4599             Dsymbol s = tn.toDsymbol(sc);
4600             AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
4601             if (ad && ad.noDefaultCtor)
4602             {
4603                 error(exp.loc, "default construction is disabled for type `%s`", tb.nextOf().toChars());
4604                 return setError();
4605             }
4606             for (size_t i = 0; i < nargs; i++)
4607             {
4608                 if (tb.ty != Tarray)
4609                 {
4610                     error(exp.loc, "too many arguments for array");
4611                     return setError();
4612                 }
4613 
4614                 Expression arg = (*exp.arguments)[i];
4615                 if (exp.names && (*exp.names)[i])
4616                 {
4617                     error(exp.loc, "no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
4618                     return setError();
4619                 }
4620 
4621                 arg = resolveProperties(sc, arg);
4622                 arg = arg.implicitCastTo(sc, Type.tsize_t);
4623                 if (arg.op == EXP.error)
4624                     return setError();
4625                 arg = arg.optimize(WANTvalue);
4626                 if (arg.op == EXP.int64 && (target.isLP64 ?
4627                     cast(sinteger_t)arg.toInteger() : cast(int)arg.toInteger()) < 0)
4628                 {
4629                     error(exp.loc, "negative array dimension `%s`", (*exp.arguments)[i].toChars());
4630                     return setError();
4631                 }
4632                 (*exp.arguments)[i] = arg;
4633                 tb = tb.isTypeDArray().next.toBasetype();
4634             }
4635 
4636             if (nargs == 1)
4637             {
4638                 if (global.params.betterC || !sc.needsCodegen())
4639                     goto LskipNewArrayLowering;
4640 
4641                 /* Class types may inherit base classes that have errors.
4642                  * This may leak errors from the base class to the derived one
4643                  * and then to the hook. Semantic analysis is performed eagerly
4644                  * to a void this.
4645                  */
4646                 if (auto tc = exp.type.nextOf.isTypeClass())
4647                 {
4648                     tc.sym.dsymbolSemantic(sc);
4649                     if (tc.sym.errors)
4650                         goto LskipNewArrayLowering;
4651                 }
4652 
4653                 auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
4654                 if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
4655                     goto LskipNewArrayLowering;
4656 
4657                 /* Lower the memory allocation and initialization of `new T[n]`
4658                  * to `_d_newarrayT!T(n)`.
4659                  */
4660                 Expression lowering = new IdentifierExp(exp.loc, Id.empty);
4661                 lowering = new DotIdExp(exp.loc, lowering, Id.object);
4662                 auto tiargs = new Objects();
4663                 /* Remove `inout`, `const`, `immutable` and `shared` to reduce
4664                  * the number of generated `_d_newarrayT` instances.
4665                  */
4666                 const isShared = exp.type.nextOf.isShared();
4667                 auto t = exp.type.nextOf.unqualify(MODFlags.wild | MODFlags.const_ |
4668                     MODFlags.immutable_ | MODFlags.shared_);
4669                 tiargs.push(t);
4670                 lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
4671 
4672                 auto arguments = new Expressions();
4673                 if (global.params.tracegc)
4674                 {
4675                     auto funcname = (sc.callsc && sc.callsc.func) ?
4676                         sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
4677                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
4678                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
4679                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
4680                 }
4681                 arguments.push((*exp.arguments)[0]);
4682                 arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
4683 
4684                 lowering = new CallExp(exp.loc, lowering, arguments);
4685                 exp.lowering = lowering.expressionSemantic(sc);
4686             }
4687         }
4688         else if (tb.isscalar())
4689         {
4690             if (!nargs)
4691             {
4692             }
4693             else if (nargs == 1)
4694             {
4695                 if (exp.names && (*exp.names)[0])
4696                 {
4697                     error(exp.loc, "no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
4698                     return setError();
4699                 }
4700                 Expression e = (*exp.arguments)[0];
4701                 e = e.implicitCastTo(sc, tb);
4702                 (*exp.arguments)[0] = e;
4703             }
4704             else
4705             {
4706                 error(exp.loc, "more than one argument for construction of `%s`", exp.type.toChars());
4707                 return setError();
4708             }
4709 
4710             exp.type = exp.type.pointerTo();
4711             tryLowerToNewItem(exp);
4712         }
4713         else if (tb.ty == Taarray)
4714         {
4715             // e.g. `new Alias(args)`
4716             if (nargs)
4717             {
4718                 error(exp.loc, "`new` cannot take arguments for an associative array");
4719                 return setError();
4720             }
4721         }
4722         else
4723         {
4724             error(exp.loc, "cannot create a `%s` with `new`", exp.type.toChars());
4725             return setError();
4726         }
4727 
4728     LskipNewArrayLowering:
4729         //printf("NewExp: '%s'\n", toChars());
4730         //printf("NewExp:type '%s'\n", type.toChars());
4731         semanticTypeInfo(sc, exp.type);
4732 
4733         if (newprefix)
4734         {
4735             result = Expression.combine(newprefix, exp);
4736             return;
4737         }
4738         result = exp;
4739     }
4740 
4741     override void visit(NewAnonClassExp e)
4742     {
4743         static if (LOGSEMANTIC)
4744         {
4745             printf("NewAnonClassExp::semantic() %s\n", e.toChars());
4746             //printf("thisexp = %p\n", thisexp);
4747             //printf("type: %s\n", type.toChars());
4748         }
4749 
4750         Expression d = new DeclarationExp(e.loc, e.cd);
4751         sc = sc.push(); // just create new scope
4752         sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4753         d = d.expressionSemantic(sc);
4754         sc = sc.pop();
4755 
4756         if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
4757         {
4758             ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
4759             if (!sds.members)
4760                 sds.members = new Dsymbols();
4761             sds.members.push(e.cd);
4762         }
4763 
4764         Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
4765 
4766         Expression c = new CommaExp(e.loc, d, n);
4767         result = c.expressionSemantic(sc);
4768     }
4769 
4770     override void visit(SymOffExp e)
4771     {
4772         static if (LOGSEMANTIC)
4773         {
4774             printf("SymOffExp::semantic('%s')\n", e.toChars());
4775         }
4776         //var.dsymbolSemantic(sc);
4777         if (!e.type)
4778             e.type = e.var.type.pointerTo();
4779 
4780         if (auto v = e.var.isVarDeclaration())
4781         {
4782             if (v.checkNestedReference(sc, e.loc))
4783                 return setError();
4784         }
4785         else if (auto f = e.var.isFuncDeclaration())
4786         {
4787             if (f.checkNestedReference(sc, e.loc))
4788                 return setError();
4789         }
4790 
4791         result = e;
4792     }
4793 
4794     override void visit(VarExp e)
4795     {
4796         static if (LOGSEMANTIC)
4797         {
4798             printf("VarExp::semantic(%s)\n", e.toChars());
4799         }
4800 
4801         auto vd = e.var.isVarDeclaration();
4802         auto fd = e.var.isFuncDeclaration();
4803 
4804         if (fd)
4805         {
4806             //printf("L%d fd = %s\n", __LINE__, f.toChars());
4807             if (!fd.functionSemantic())
4808                 return setError();
4809         }
4810 
4811         if (!e.type)
4812             e.type = e.var.type;
4813         if (e.type && !e.type.deco)
4814         {
4815             auto decl = e.var.isDeclaration();
4816             if (decl)
4817                 decl.inuse++;
4818             e.type = e.type.typeSemantic(e.loc, sc);
4819             if (decl)
4820                 decl.inuse--;
4821         }
4822 
4823         /* Fix for 1161 doesn't work because it causes visibility
4824          * problems when instantiating imported templates passing private
4825          * variables as alias template parameters.
4826          */
4827         //checkAccess(loc, sc, NULL, var);
4828 
4829         if (vd)
4830         {
4831             if (vd.checkNestedReference(sc, e.loc))
4832                 return setError();
4833 
4834             // https://issues.dlang.org/show_bug.cgi?id=12025
4835             // If the variable is not actually used in runtime code,
4836             // the purity violation error is redundant.
4837             //checkPurity(sc, vd);
4838         }
4839         else if (fd)
4840         {
4841             // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4842             // call would cause incorrect validation.
4843             // Maybe here should be moved in CallExp, or AddrExp for functions.
4844             if (fd.checkNestedReference(sc, e.loc))
4845                 return setError();
4846         }
4847         else if (auto od = e.var.isOverDeclaration())
4848         {
4849             e.type = Type.tvoid; // ambiguous type?
4850         }
4851 
4852         result = e;
4853     }
4854 
4855     override void visit(FuncExp exp)
4856     {
4857         static if (LOGSEMANTIC)
4858         {
4859             printf("FuncExp::semantic(%s)\n", exp.toChars());
4860             if (exp.fd.treq)
4861                 printf("  treq = %s\n", exp.fd.treq.toChars());
4862         }
4863 
4864         if (exp.type)
4865         {
4866             result = exp;
4867             return;
4868         }
4869 
4870         Expression e = exp;
4871         uint olderrors;
4872 
4873         sc = sc.push(); // just create new scope
4874         sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4875         sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4876 
4877         /* fd.treq might be incomplete type,
4878             * so should not semantic it.
4879             * void foo(T)(T delegate(int) dg){}
4880             * foo(a=>a); // in IFTI, treq == T delegate(int)
4881             */
4882         //if (fd.treq)
4883         //    fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4884 
4885         exp.genIdent(sc);
4886 
4887         // Set target of return type inference
4888         if (exp.fd.treq && !exp.fd.type.nextOf())
4889         {
4890             TypeFunction tfv = null;
4891             if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4892                 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4893             if (tfv)
4894             {
4895                 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4896                 tfl.next = tfv.nextOf();
4897             }
4898         }
4899 
4900         //printf("td = %p, treq = %p\n", td, fd.treq);
4901         if (exp.td)
4902         {
4903             assert(exp.td.parameters && exp.td.parameters.length);
4904             exp.td.dsymbolSemantic(sc);
4905             exp.type = Type.tvoid; // temporary type
4906 
4907             if (exp.fd.treq) // defer type determination
4908             {
4909                 FuncExp fe;
4910                 if (exp.matchType(exp.fd.treq, sc, &fe, sc.eSink) > MATCH.nomatch)
4911                     e = fe;
4912                 else
4913                     e = ErrorExp.get();
4914             }
4915             goto Ldone;
4916         }
4917 
4918         olderrors = global.errors;
4919         exp.fd.dsymbolSemantic(sc);
4920         if (olderrors == global.errors)
4921         {
4922             exp.fd.semantic2(sc);
4923             if (olderrors == global.errors)
4924                 exp.fd.semantic3(sc);
4925         }
4926         if (olderrors != global.errors)
4927         {
4928             if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4929                 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4930             e = ErrorExp.get();
4931             goto Ldone;
4932         }
4933 
4934         // Type is a "delegate to" or "pointer to" the function literal
4935         if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4936         {
4937             // https://issues.dlang.org/show_bug.cgi?id=22686
4938             // if the delegate return type is an error
4939             // abort semantic of the FuncExp and propagate
4940             // the error
4941             if (exp.fd.type.isTypeError())
4942             {
4943                 e = ErrorExp.get();
4944                 goto Ldone;
4945             }
4946             exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4947             exp.type = exp.type.typeSemantic(exp.loc, sc);
4948 
4949             exp.fd.tok = TOK.delegate_;
4950         }
4951         else
4952         {
4953             exp.type = new TypePointer(exp.fd.type);
4954             exp.type = exp.type.typeSemantic(exp.loc, sc);
4955             //type = fd.type.pointerTo();
4956 
4957             /* A lambda expression deduced to function pointer might become
4958                 * to a delegate literal implicitly.
4959                 *
4960                 *   auto foo(void function() fp) { return 1; }
4961                 *   assert(foo({}) == 1);
4962                 *
4963                 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4964                 */
4965             if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4966             {
4967                 // change to non-nested
4968                 exp.fd.tok = TOK.function_;
4969                 exp.fd.vthis = null;
4970             }
4971         }
4972         exp.fd.tookAddressOf++;
4973 
4974     Ldone:
4975         sc = sc.pop();
4976         result = e;
4977     }
4978 
4979     /**
4980      * Perform semantic analysis on function literals
4981      *
4982      * Test the following construct:
4983      * ---
4984      * (x, y, z) { return x + y + z; }(42, 84, 1992);
4985      * ---
4986      */
4987     Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4988     {
4989         if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
4990         {
4991             for (size_t k = 0; k < arguments.length; k++)
4992             {
4993                 Expression checkarg = (*arguments)[k];
4994                 if (checkarg.op == EXP.error)
4995                     return checkarg;
4996             }
4997 
4998             exp.genIdent(sc);
4999 
5000             assert(exp.td.parameters && exp.td.parameters.length);
5001             exp.td.dsymbolSemantic(sc);
5002 
5003             TypeFunction tfl = cast(TypeFunction)exp.fd.type;
5004             size_t dim = tfl.parameterList.length;
5005             if (arguments.length < dim)
5006             {
5007                 // Default arguments are always typed, so they don't need inference.
5008                 Parameter p = tfl.parameterList[arguments.length];
5009                 if (p.defaultArg)
5010                     dim = arguments.length;
5011             }
5012 
5013             if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
5014                 arguments.length < dim)
5015             {
5016                 OutBuffer buf;
5017                 foreach (idx, ref arg; *arguments)
5018                     buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
5019                 error(exp.loc, "function literal `%s%s` is not callable using argument types `(%s)`",
5020                           exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
5021                           buf.peekChars());
5022                 errorSupplemental(exp.loc, "too %s arguments, expected %d, got %d",
5023                                       arguments.length < dim ? "few".ptr : "many".ptr,
5024                                       cast(int)dim, cast(int)arguments.length);
5025                 return ErrorExp.get();
5026             }
5027 
5028             auto tiargs = new Objects();
5029             tiargs.reserve(exp.td.parameters.length);
5030 
5031             for (size_t i = 0; i < exp.td.parameters.length; i++)
5032             {
5033                 TemplateParameter tp = (*exp.td.parameters)[i];
5034                 assert(dim <= tfl.parameterList.length);
5035                 foreach (u, p; tfl.parameterList)
5036                 {
5037                     if (u == dim)
5038                         break;
5039 
5040                     if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
5041                     {
5042                         Expression e = (*arguments)[u];
5043                         tiargs.push(e.type);
5044                         break;
5045                     }
5046                 }
5047             }
5048 
5049             auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
5050             return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
5051         }
5052         return exp.expressionSemantic(sc);
5053     }
5054 
5055     override void visit(CallExp exp)
5056     {
5057         static if (LOGSEMANTIC)
5058         {
5059             printf("CallExp::semantic() %s\n", exp.toChars());
5060         }
5061         if (exp.type)
5062         {
5063             result = exp;
5064             return; // semantic() already run
5065         }
5066 
5067         Objects* tiargs = null; // initial list of template arguments
5068         Expression ethis = null;
5069         Type tthis = null;
5070         Expression e1org = exp.e1;
5071 
5072         if (auto ce = exp.e1.isCommaExp())
5073         {
5074             /* Rewrite (a,b)(args) as (a,(b(args)))
5075              */
5076             exp.e1 = ce.e2;
5077             ce.e2 = exp;
5078             result = ce.expressionSemantic(sc);
5079             return;
5080         }
5081         if (DelegateExp de = exp.e1.isDelegateExp())
5082         {
5083             exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
5084             visit(exp);
5085             return;
5086         }
5087         if (FuncExp fe = exp.e1.isFuncExp())
5088         {
5089             if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
5090                 preFunctionParameters(sc, exp.argumentList))
5091                 return setError();
5092 
5093             // Run e1 semantic even if arguments have any errors
5094             exp.e1 = callExpSemantic(fe, sc, exp.arguments);
5095             if (exp.e1.op == EXP.error)
5096             {
5097                 result = exp.e1;
5098                 return;
5099             }
5100         }
5101         if (sc.flags & SCOPE.Cfile)
5102         {
5103             /* See if need to rewrite the AST because of cast/call ambiguity
5104              */
5105             if (auto e = castCallAmbiguity(exp, sc))
5106             {
5107                 result = expressionSemantic(e, sc);
5108                 return;
5109             }
5110         }
5111 
5112         if (Expression ex = resolveUFCS(sc, exp))
5113         {
5114             result = ex;
5115             return;
5116         }
5117 
5118         /* This recognizes:
5119          *  foo!(tiargs)(funcargs)
5120          */
5121         if (ScopeExp se = exp.e1.isScopeExp())
5122         {
5123             TemplateInstance ti = se.sds.isTemplateInstance();
5124             if (ti)
5125             {
5126                 /* Attempt to instantiate ti. If that works, go with it.
5127                  * If not, go with partial explicit specialization.
5128                  */
5129                 WithScopeSymbol withsym;
5130                 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
5131                     return setError();
5132                 if (withsym && withsym.withstate.wthis)
5133                 {
5134                     exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
5135                     exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
5136                     goto Ldotti;
5137                 }
5138                 if (ti.needsTypeInference(sc, 1))
5139                 {
5140                     /* Go with partial explicit specialization
5141                      */
5142                     tiargs = ti.tiargs;
5143                     assert(ti.tempdecl);
5144                     if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5145                         exp.e1 = new TemplateExp(exp.loc, td);
5146                     else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5147                         exp.e1 = new VarExp(exp.loc, od);
5148                     else
5149                         exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
5150                 }
5151                 else
5152                 {
5153                     Expression e1x = exp.e1.expressionSemantic(sc);
5154                     if (e1x.op == EXP.error)
5155                     {
5156                         result = e1x;
5157                         return;
5158                     }
5159                     exp.e1 = e1x;
5160                 }
5161             }
5162         }
5163 
5164         /* This recognizes:
5165          *  expr.foo!(tiargs)(funcargs)
5166          */
5167     Ldotti:
5168         if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
5169         {
5170             TemplateInstance ti = se.ti;
5171             {
5172                 /* Attempt to instantiate ti. If that works, go with it.
5173                  * If not, go with partial explicit specialization.
5174                  */
5175                 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
5176                     return setError();
5177                 if (ti.needsTypeInference(sc, 1))
5178                 {
5179                     /* Go with partial explicit specialization
5180                      */
5181                     tiargs = ti.tiargs;
5182                     assert(ti.tempdecl);
5183                     if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
5184                         exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
5185                     else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
5186                     {
5187                         exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
5188                     }
5189                     else
5190                         exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
5191                 }
5192                 else
5193                 {
5194                     Expression e1x = exp.e1.expressionSemantic(sc);
5195                     if (e1x.op == EXP.error)
5196                     {
5197                         result = e1x;
5198                         return;
5199                     }
5200                     exp.e1 = e1x;
5201                 }
5202             }
5203         }
5204 
5205         Type att = null;
5206     Lagain:
5207         //printf("Lagain: %s\n", toChars());
5208         exp.f = null;
5209         if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
5210         {
5211             // semantic() run later for these
5212         }
5213         else
5214         {
5215             if (DotIdExp die = exp.e1.isDotIdExp())
5216             {
5217                 exp.e1 = die.expressionSemantic(sc);
5218                 /* Look for e1 having been rewritten to expr.opDispatch!(string)
5219                  * We handle such earlier, so go back.
5220                  * Note that in the rewrite, we carefully did not run semantic() on e1
5221                  */
5222                 if (exp.e1.op == EXP.dotTemplateInstance)
5223                 {
5224                     goto Ldotti;
5225                 }
5226             }
5227             else
5228             {
5229                 __gshared int nest;
5230                 if (++nest > global.recursionLimit)
5231                 {
5232                     error(exp.loc, "recursive evaluation of `%s`", exp.toChars());
5233                     --nest;
5234                     return setError();
5235                 }
5236                 Expression ex = unaSemantic(exp, sc);
5237                 --nest;
5238                 if (ex)
5239                 {
5240                     result = ex;
5241                     return;
5242                 }
5243             }
5244 
5245             /* Look for e1 being a lazy parameter
5246              */
5247             if (VarExp ve = exp.e1.isVarExp())
5248             {
5249                 if (ve.var.storage_class & STC.lazy_)
5250                 {
5251                     // lazy parameters can be called without violating purity and safety
5252                     Type tw = ve.var.type;
5253                     Type tc = ve.var.type.substWildTo(MODFlags.const_);
5254                     auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
5255                     (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
5256                     auto t = new TypeDelegate(tf);
5257                     ve.type = t.typeSemantic(exp.loc, sc);
5258                 }
5259                 VarDeclaration v = ve.var.isVarDeclaration();
5260                 if (v && ve.checkPurity(sc, v))
5261                     return setError();
5262             }
5263 
5264             if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
5265             {
5266                 SymOffExp se = cast(SymOffExp)exp.e1;
5267                 exp.e1 = new VarExp(se.loc, se.var, true);
5268                 exp.e1 = exp.e1.expressionSemantic(sc);
5269             }
5270             else if (DotExp de = exp.e1.isDotExp())
5271             {
5272                 if (de.e2.op == EXP.overloadSet)
5273                 {
5274                     ethis = de.e1;
5275                     tthis = de.e1.type;
5276                     exp.e1 = de.e2;
5277                 }
5278             }
5279             else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
5280             {
5281                 // Rewrite (*fp)(arguments) to fp(arguments)
5282                 exp.e1 = (cast(PtrExp)exp.e1).e1;
5283             }
5284             else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
5285             {
5286                 const numArgs = exp.arguments ? exp.arguments.length : 0;
5287 
5288                 /* Ambiguous cases arise from CParser where there is not enough
5289                  * information to determine if we have a function call or declaration.
5290                  *   type-name ( identifier ) ;
5291                  *   identifier ( identifier ) ;
5292                  * If exp.e1 is a type-name, then this is a declaration. C11 does not
5293                  * have type construction syntax, so don't convert this to a cast().
5294                  */
5295                 if (numArgs == 1)
5296                 {
5297                     Expression arg = (*exp.arguments)[0];
5298                     if (auto ie = (*exp.arguments)[0].isIdentifierExp())
5299                     {
5300                         TypeExp te = cast(TypeExp)exp.e1;
5301                         auto initializer = new VoidInitializer(ie.loc);
5302                         Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
5303                         auto decls = new Dsymbols(1);
5304                         (*decls)[0] = s;
5305                         s = new LinkDeclaration(s.loc, LINK.c, decls);
5306                         result = new DeclarationExp(exp.loc, s);
5307                         result = result.expressionSemantic(sc);
5308                     }
5309                     else
5310                     {
5311                         error(arg.loc, "identifier or `(` expected");
5312                         result = ErrorExp.get();
5313                     }
5314                     return;
5315                 }
5316                 error(exp.loc, "identifier or `(` expected before `)`");
5317                 result = ErrorExp.get();
5318                 return;
5319             }
5320         }
5321 
5322         Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
5323 
5324         if (exp.e1.op == EXP.error)
5325         {
5326             result = exp.e1;
5327             return;
5328         }
5329         if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
5330             preFunctionParameters(sc, exp.argumentList))
5331             return setError();
5332 
5333         // Check for call operator overload
5334         if (t1)
5335         {
5336             if (t1.ty == Tstruct)
5337             {
5338                 auto sd = (cast(TypeStruct)t1).sym;
5339                 sd.size(exp.loc); // Resolve forward references to construct object
5340                 if (sd.sizeok != Sizeok.done)
5341                     return setError();
5342                 if (!sd.ctor)
5343                     sd.ctor = sd.searchCtor();
5344                 /* If `sd.ctor` is a generated copy constructor, this means that it
5345                    is the single constructor that this struct has. In order to not
5346                    disable default construction, the ctor is nullified. The side effect
5347                    of this is that the generated copy constructor cannot be called
5348                    explicitly, but that is ok, because when calling a constructor the
5349                    default constructor should have priority over the generated copy
5350                    constructor.
5351                 */
5352                 if (sd.ctor)
5353                 {
5354                     auto ctor = sd.ctor.isCtorDeclaration();
5355                     if (ctor && ctor.isCpCtor && ctor.isGenerated())
5356                         sd.ctor = null;
5357                 }
5358 
5359                 // First look for constructor
5360                 if (exp.e1.op == EXP.type && sd.ctor)
5361                 {
5362                     if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
5363                         goto Lx;
5364 
5365                     /* https://issues.dlang.org/show_bug.cgi?id=20695
5366                        If all constructors are copy constructors, then
5367                        try default construction.
5368                      */
5369                     if (!sd.hasRegularCtor &&
5370                         // https://issues.dlang.org/show_bug.cgi?id=22639
5371                         // we might still have a copy constructor that could be called
5372                         (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
5373                         goto Lx;
5374 
5375                     auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
5376                     if (!sd.fill(exp.loc, *sle.elements, true))
5377                         return setError();
5378                     if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
5379                         return setError();
5380 
5381                     // https://issues.dlang.org/show_bug.cgi?id=14556
5382                     // Set concrete type to avoid further redundant semantic().
5383                     sle.type = exp.e1.type;
5384 
5385                     /* Constructor takes a mutable object, so don't use
5386                      * the immutable initializer symbol.
5387                      */
5388                     sle.useStaticInit = false;
5389 
5390                     Expression e = sle;
5391                     if (auto cf = sd.ctor.isCtorDeclaration())
5392                     {
5393                         e = new DotVarExp(exp.loc, e, cf, true);
5394                     }
5395                     else if (auto td = sd.ctor.isTemplateDeclaration())
5396                     {
5397                         e = new DotIdExp(exp.loc, e, td.ident);
5398                     }
5399                     else if (auto os = sd.ctor.isOverloadSet())
5400                     {
5401                         e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
5402                     }
5403                     else
5404                         assert(0);
5405                     e = new CallExp(exp.loc, e, exp.arguments);
5406                     e = e.expressionSemantic(sc);
5407                     result = e;
5408                     return;
5409                 }
5410                 // No constructor, look for overload of opCall
5411                 if (search_function(sd, Id.call))
5412                     goto L1;
5413                 // overload of opCall, therefore it's a call
5414                 if (exp.e1.op != EXP.type)
5415                 {
5416                     if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
5417                     {
5418                         exp.e1 = resolveAliasThis(sc, exp.e1);
5419                         goto Lagain;
5420                     }
5421                     error(exp.loc, "%s `%s` does not overload ()", sd.kind(), sd.toChars());
5422                     return setError();
5423                 }
5424 
5425                 /* It's a struct literal
5426                  */
5427             Lx:
5428                 Expressions* resolvedArgs = exp.arguments;
5429                 if (exp.names)
5430                 {
5431                     resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
5432                         (*exp.names)[],
5433                         (size_t i, Type t) => (*exp.arguments)[i],
5434                         i => (*exp.arguments)[i].loc
5435                     );
5436                     if (!resolvedArgs)
5437                     {
5438                         result = ErrorExp.get();
5439                         return;
5440                     }
5441                 }
5442 
5443                 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
5444                 e = e.expressionSemantic(sc);
5445                 result = e;
5446                 return;
5447             }
5448             else if (t1.ty == Tclass)
5449             {
5450             L1:
5451                 // Rewrite as e1.call(arguments)
5452                 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
5453                 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
5454                 e = e.expressionSemantic(sc);
5455                 result = e;
5456                 return;
5457             }
5458             else if (exp.e1.op == EXP.type && t1.isscalar())
5459             {
5460                 Expression e;
5461 
5462                 // Make sure to use the enum type itself rather than its
5463                 // base type
5464                 // https://issues.dlang.org/show_bug.cgi?id=16346
5465                 if (exp.e1.type.ty == Tenum)
5466                 {
5467                     t1 = exp.e1.type;
5468                 }
5469 
5470                 if (!exp.arguments || exp.arguments.length == 0)
5471                 {
5472                     e = t1.defaultInitLiteral(exp.loc);
5473                 }
5474                 else if (exp.arguments.length == 1)
5475                 {
5476                     e = (*exp.arguments)[0];
5477                     e = e.implicitCastTo(sc, t1);
5478                     e = new CastExp(exp.loc, e, t1);
5479                 }
5480                 else
5481                 {
5482                     error(exp.loc, "more than one argument for construction of `%s`", t1.toChars());
5483                     return setError();
5484                 }
5485                 e = e.expressionSemantic(sc);
5486                 result = e;
5487                 return;
5488             }
5489         }
5490 
5491         FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
5492             OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
5493         {
5494             FuncDeclaration f = null;
5495             foreach (s; os.a)
5496             {
5497                 if (tiargs && s.isFuncDeclaration())
5498                     continue;
5499                 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
5500                 {
5501                     if (f2.errors)
5502                         return null;
5503                     if (f)
5504                     {
5505                         /* Match in more than one overload set,
5506                          * even if one is a 'better' match than the other.
5507                          */
5508                         if (f.isCsymbol() && f2.isCsymbol())
5509                         {
5510                             /* C has global name space, so just pick one, such as f.
5511                              * If f and f2 are not compatible, that's how C rolls.
5512                              */
5513                         }
5514                         else
5515                             ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
5516                     }
5517                     else
5518                         f = f2;
5519                 }
5520             }
5521             if (!f)
5522             {
5523                 .error(loc, "no overload matches for `%s`", exp.toChars());
5524                 errorSupplemental(loc, "Candidates are:");
5525                 foreach (s; os.a)
5526                 {
5527                     overloadApply(s, (ds){
5528                         if (auto fd = ds.isFuncDeclaration())
5529                             .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
5530                                 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
5531                         else
5532                             .errorSupplemental(ds.loc, "%s", ds.toChars());
5533                         return 0;
5534                     });
5535                 }
5536             }
5537             else if (f.errors)
5538                 f = null;
5539             return f;
5540         }
5541 
5542         bool isSuper = false;
5543         if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
5544         {
5545             UnaExp ue = cast(UnaExp)exp.e1;
5546 
5547             Expression ue1old = ue.e1; // need for 'right this' check
5548             DotVarExp dve;
5549             DotTemplateExp dte;
5550             Dsymbol s;
5551             if (exp.e1.op == EXP.dotVariable)
5552             {
5553                 dve = cast(DotVarExp)exp.e1;
5554                 dte = null;
5555                 s = dve.var;
5556                 tiargs = null;
5557             }
5558             else
5559             {
5560                 dve = null;
5561                 dte = cast(DotTemplateExp)exp.e1;
5562                 s = dte.td;
5563             }
5564 
5565             // Do overload resolution
5566             exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
5567             if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
5568                 return setError();
5569 
5570             if (exp.f.interfaceVirtual)
5571             {
5572                 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
5573                  */
5574                 auto b = exp.f.interfaceVirtual;
5575                 auto ad2 = b.sym;
5576                 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
5577                 ue.e1 = ue.e1.expressionSemantic(sc);
5578                 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length);
5579                 assert(vi >= 0);
5580                 exp.f = ad2.vtbl[vi].isFuncDeclaration();
5581                 assert(exp.f);
5582             }
5583             if (exp.f.needThis())
5584             {
5585                 AggregateDeclaration ad = exp.f.isMemberLocal();
5586                 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
5587                 if (ue.e1.op == EXP.error)
5588                 {
5589                     result = ue.e1;
5590                     return;
5591                 }
5592                 ethis = ue.e1;
5593                 tthis = ue.e1.type;
5594                 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
5595                 {
5596                     if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
5597                         return setError();
5598                 }
5599             }
5600 
5601             /* Cannot call public functions from inside invariant
5602              * (because then the invariant would have infinite recursion)
5603              */
5604             if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
5605             {
5606                 error(exp.loc, "cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
5607                 return setError();
5608             }
5609 
5610             if (!exp.ignoreAttributes)
5611                 checkFunctionAttributes(exp, sc, exp.f);
5612 
5613             // Cut-down version of checkAccess() that doesn't use the "most visible" version of exp.f.
5614             // We've already selected an overload here.
5615             const parent = exp.f.toParent();
5616             if (parent && parent.isTemplateInstance())
5617             {
5618                 // already a deprecation
5619             }
5620             else if (!checkSymbolAccess(sc, exp.f))
5621             {
5622                 error(exp.loc, "%s `%s` of type `%s` is not accessible from module `%s`",
5623                     exp.f.kind(), exp.f.toPrettyChars(), exp.f.type.toChars(), sc._module.toChars);
5624                 return setError();
5625             }
5626 
5627             if (!exp.f.needThis())
5628             {
5629                 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
5630             }
5631             else
5632             {
5633                 if (ue1old.checkRightThis(sc))
5634                     return setError();
5635                 if (exp.e1.op == EXP.dotVariable)
5636                 {
5637                     dve.var = exp.f;
5638                     exp.e1.type = exp.f.type;
5639                 }
5640                 else
5641                 {
5642                     exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
5643                     exp.e1 = exp.e1.expressionSemantic(sc);
5644                     if (exp.e1.op == EXP.error)
5645                         return setError();
5646                     ue = cast(UnaExp)exp.e1;
5647                 }
5648                 version (none)
5649                 {
5650                     printf("ue.e1 = %s\n", ue.e1.toChars());
5651                     printf("f = %s\n", exp.f.toChars());
5652                     printf("t1 = %s\n", t1.toChars());
5653                     printf("e1 = %s\n", exp.e1.toChars());
5654                     printf("e1.type = %s\n", exp.e1.type.toChars());
5655                 }
5656 
5657                 // See if we need to adjust the 'this' pointer
5658                 AggregateDeclaration ad = exp.f.isThis();
5659                 ClassDeclaration cd = ue.e1.type.isClassHandle();
5660                 if (ad && cd && ad.isClassDeclaration())
5661                 {
5662                     if (ue.e1.op == EXP.dotType)
5663                     {
5664                         ue.e1 = (cast(DotTypeExp)ue.e1).e1;
5665                         exp.directcall = true;
5666                     }
5667                     else if (ue.e1.op == EXP.super_)
5668                         exp.directcall = true;
5669                     else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
5670                         exp.directcall = true;
5671 
5672                     if (ad != cd)
5673                     {
5674                         ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
5675                         ue.e1 = ue.e1.expressionSemantic(sc);
5676                     }
5677                 }
5678             }
5679             // If we've got a pointer to a function then deference it
5680             // https://issues.dlang.org/show_bug.cgi?id=16483
5681             if (exp.e1.type.isPtrToFunction())
5682             {
5683                 Expression e = new PtrExp(exp.loc, exp.e1);
5684                 e.type = exp.e1.type.nextOf();
5685                 exp.e1 = e;
5686             }
5687             t1 = exp.e1.type;
5688         }
5689         else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
5690         {
5691             auto ad = sc.func ? sc.func.isThis() : null;
5692             auto cd = ad ? ad.isClassDeclaration() : null;
5693 
5694             isSuper = exp.e1.op == EXP.super_;
5695             if (isSuper)
5696             {
5697                 // Base class constructor call
5698                 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
5699                 {
5700                     error(exp.loc, "super class constructor call must be in a constructor");
5701                     return setError();
5702                 }
5703                 if (!cd.baseClass.ctor)
5704                 {
5705                     error(exp.loc, "no super class constructor for `%s`", cd.baseClass.toChars());
5706                     return setError();
5707                 }
5708             }
5709             else
5710             {
5711                 // `this` call expression must be inside a
5712                 // constructor
5713                 if (!ad || !sc.func.isCtorDeclaration())
5714                 {
5715                     error(exp.loc, "constructor call must be in a constructor");
5716                     return setError();
5717                 }
5718 
5719                 // https://issues.dlang.org/show_bug.cgi?id=18719
5720                 // If `exp` is a call expression to another constructor
5721                 // then it means that all struct/class fields will be
5722                 // initialized after this call.
5723                 foreach (ref field; sc.ctorflow.fieldinit)
5724                 {
5725                     field.csx |= CSX.this_ctor;
5726                 }
5727             }
5728 
5729             if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
5730             {
5731                 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
5732                     error(exp.loc, "constructor calls not allowed in loops or after labels");
5733                 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
5734                     error(exp.loc, "multiple constructor calls");
5735                 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
5736                     error(exp.loc, "an earlier `return` statement skips constructor");
5737                 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
5738             }
5739 
5740             tthis = ad.type.addMod(sc.func.type.mod);
5741             auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
5742             if (auto os = ctor.isOverloadSet())
5743                 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
5744             else
5745                 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
5746 
5747             if (!exp.f || exp.f.errors)
5748                 return setError();
5749 
5750             checkFunctionAttributes(exp, sc, exp.f);
5751             checkAccess(exp.loc, sc, null, exp.f);
5752 
5753             exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
5754             exp.e1 = exp.e1.expressionSemantic(sc);
5755             // https://issues.dlang.org/show_bug.cgi?id=21095
5756             if (exp.e1.op == EXP.error)
5757                 return setError();
5758             t1 = exp.e1.type;
5759 
5760             // BUG: this should really be done by checking the static
5761             // call graph
5762             if (exp.f == sc.func)
5763             {
5764                 error(exp.loc, "cyclic constructor call");
5765                 return setError();
5766             }
5767         }
5768         else if (auto oe = exp.e1.isOverExp())
5769         {
5770             exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
5771             if (!exp.f)
5772                 return setError();
5773             if (ethis)
5774                 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
5775             else
5776                 exp.e1 = new VarExp(exp.loc, exp.f, false);
5777             goto Lagain;
5778         }
5779         else if (!t1)
5780         {
5781             error(exp.loc, "function expected before `()`, not `%s`", exp.e1.toChars());
5782             return setError();
5783         }
5784         else if (t1.ty == Terror)
5785         {
5786             return setError();
5787         }
5788         else if (t1.ty != Tfunction)
5789         {
5790             TypeFunction tf;
5791             const(char)* p;
5792             Dsymbol s;
5793             exp.f = null;
5794             if (auto fe = exp.e1.isFuncExp())
5795             {
5796                 // function literal that direct called is always inferred.
5797                 assert(fe.fd);
5798                 exp.f = fe.fd;
5799                 tf = cast(TypeFunction)exp.f.type;
5800                 p = "function literal";
5801             }
5802             else if (t1.ty == Tdelegate)
5803             {
5804                 TypeDelegate td = cast(TypeDelegate)t1;
5805                 assert(td.next.ty == Tfunction);
5806                 tf = cast(TypeFunction)td.next;
5807                 p = "delegate";
5808             }
5809             else if (auto tfx = t1.isPtrToFunction())
5810             {
5811                 tf = tfx;
5812                 p = "function pointer";
5813             }
5814             else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
5815             {
5816                 DotVarExp dve = cast(DotVarExp)exp.e1;
5817                 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
5818                 if (!exp.f)
5819                     return setError();
5820                 if (exp.f.needThis())
5821                 {
5822                     dve.var = exp.f;
5823                     dve.type = exp.f.type;
5824                     dve.hasOverloads = false;
5825                     goto Lagain;
5826                 }
5827                 exp.e1 = new VarExp(dve.loc, exp.f, false);
5828                 Expression e = new CommaExp(exp.loc, dve.e1, exp);
5829                 result = e.expressionSemantic(sc);
5830                 return;
5831             }
5832             else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
5833             {
5834                 s = (cast(VarExp)exp.e1).var;
5835                 goto L2;
5836             }
5837             else if (exp.e1.op == EXP.template_)
5838             {
5839                 s = (cast(TemplateExp)exp.e1).td;
5840             L2:
5841                 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList,
5842                     exp.isUfcsRewrite ? FuncResolveFlag.ufcs : FuncResolveFlag.standard);
5843                 if (!exp.f || exp.f.errors)
5844                     return setError();
5845                 if (exp.f.needThis())
5846                 {
5847                     if (hasThis(sc))
5848                     {
5849                         // Supply an implicit 'this', as in
5850                         //    this.ident
5851                         exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5852                         goto Lagain;
5853                     }
5854                     else if (isNeedThisScope(sc, exp.f))
5855                     {
5856                         return needThisError(exp.loc, exp.f);
5857                     }
5858                 }
5859                 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
5860                 goto Lagain;
5861             }
5862             else
5863             {
5864                 error(exp.loc, "function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5865                 return setError();
5866             }
5867 
5868             const(char)* failMessage;
5869             if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5870             {
5871                 OutBuffer buf;
5872                 buf.writeByte('(');
5873                 argExpTypesToCBuffer(buf, exp.arguments);
5874                 buf.writeByte(')');
5875                 if (tthis)
5876                     tthis.modToBuffer(buf);
5877 
5878                 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5879                 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5880                     p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5881                 if (failMessage)
5882                     errorSupplemental(exp.loc, "%s", failMessage);
5883                 return setError();
5884             }
5885             // Purity and safety check should run after testing arguments matching
5886             if (exp.f)
5887             {
5888                 exp.checkPurity(sc, exp.f);
5889                 exp.checkSafety(sc, exp.f);
5890                 exp.checkNogc(sc, exp.f);
5891                 if (exp.f.checkNestedReference(sc, exp.loc))
5892                     return setError();
5893             }
5894             else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5895             {
5896                 bool err = false;
5897                 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
5898                 {
5899                     error(exp.loc, "`pure` %s `%s` cannot call impure %s `%s`",
5900                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5901                     err = true;
5902                 }
5903                 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
5904                 {
5905                     error(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5906                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5907                     err = true;
5908                 }
5909                 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
5910                     "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
5911                 {
5912                     error(exp.loc, "`@safe` %s `%s` cannot call `@system` %s `%s`",
5913                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5914                     err = true;
5915                 }
5916                 if (err)
5917                     return setError();
5918             }
5919 
5920             if (t1.ty == Tpointer)
5921             {
5922                 Expression e = new PtrExp(exp.loc, exp.e1);
5923                 e.type = tf;
5924                 exp.e1 = e;
5925             }
5926             t1 = tf;
5927         }
5928         else if (VarExp ve = exp.e1.isVarExp())
5929         {
5930             // Do overload resolution
5931             exp.f = ve.var.isFuncDeclaration();
5932             assert(exp.f);
5933             tiargs = null;
5934 
5935             if (exp.f.overnext)
5936                 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
5937             else
5938             {
5939                 exp.f = exp.f.toAliasFunc();
5940                 TypeFunction tf = cast(TypeFunction)exp.f.type;
5941                 const(char)* failMessage;
5942                 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5943                 {
5944                     OutBuffer buf;
5945                     buf.writeByte('(');
5946                     argExpTypesToCBuffer(buf, exp.arguments);
5947                     buf.writeByte(')');
5948 
5949                     //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5950                     if (exp.isUfcsRewrite)
5951                     {
5952                         const arg = (*exp.argumentList.arguments)[0];
5953                         .error(exp.loc, "no property `%s` for `%s` of type `%s`", exp.f.ident.toChars(), arg.toChars(), arg.type.toChars());
5954                         .errorSupplemental(exp.loc, "the following error occured while looking for a UFCS match");
5955                     }
5956 
5957                     .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5958                         exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5959                     if (failMessage)
5960                         errorSupplemental(exp.loc, "%s", failMessage);
5961                     exp.f = null;
5962                 }
5963             }
5964             if (!exp.f || exp.f.errors)
5965                 return setError();
5966 
5967             if (exp.f.needThis())
5968             {
5969                 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5970                 if (exp.f.checkNestedReference(sc, exp.loc))
5971                     return setError();
5972 
5973                 auto memberFunc = hasThis(sc);
5974                 if (memberFunc && haveSameThis(memberFunc, exp.f))
5975                 {
5976                     // Supply an implicit 'this', as in
5977                     //    this.ident
5978                     exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5979                     // Note: we cannot use f directly, because further overload resolution
5980                     // through the supplied 'this' may cause different result.
5981                     goto Lagain;
5982                 }
5983                 else if (isNeedThisScope(sc, exp.f))
5984                 {
5985                     // At this point it is possible that `exp.f` had an ambiguity error that was
5986                     // silenced because the previous call to `resolveFuncCall` was done using
5987                     // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5988                     // is printed, redo the call with `FuncResolveFlag.standard`.
5989                     //
5990                     // https://issues.dlang.org/show_bug.cgi?id=22157
5991                     if (exp.f.overnext)
5992                         exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5993 
5994                     if (!exp.f || exp.f.errors)
5995                         return setError();
5996 
5997                     // If no error is printed, it means that `f` is the single matching overload
5998                     // and it needs `this`.
5999                     return needThisError(exp.loc, exp.f);
6000                 }
6001             }
6002 
6003             checkFunctionAttributes(exp, sc, exp.f);
6004             checkAccess(exp.loc, sc, null, exp.f);
6005             if (exp.f.checkNestedReference(sc, exp.loc))
6006                 return setError();
6007 
6008             ethis = null;
6009             tthis = null;
6010 
6011             if (ve.hasOverloads)
6012             {
6013                 exp.e1 = new VarExp(ve.loc, exp.f, false);
6014                 exp.e1.type = exp.f.type;
6015             }
6016             t1 = exp.f.type;
6017         }
6018         assert(t1.ty == Tfunction);
6019 
6020         Expression argprefix;
6021         if (!exp.arguments)
6022             exp.arguments = new Expressions();
6023         if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
6024             return setError();
6025 
6026         if (!exp.type)
6027         {
6028             exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
6029                         // avoid recursive expression printing
6030             error(exp.loc, "forward reference to inferred return type of function call `%s`", exp.toChars());
6031             return setError();
6032         }
6033 
6034         if (exp.f && exp.f.tintro)
6035         {
6036             Type t = exp.type;
6037             int offset = 0;
6038             TypeFunction tf = cast(TypeFunction)exp.f.tintro;
6039             if (tf.next.isBaseOf(t, &offset) && offset)
6040             {
6041                 exp.type = tf.next;
6042                 result = Expression.combine(argprefix, exp.castTo(sc, t));
6043                 return;
6044             }
6045         }
6046 
6047         // Handle the case of a direct lambda call
6048         if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
6049         {
6050             exp.f.tookAddressOf = 0;
6051         }
6052 
6053         result = Expression.combine(argprefix, exp);
6054 
6055         if (isSuper)
6056         {
6057             auto ad = sc.func ? sc.func.isThis() : null;
6058             auto cd = ad ? ad.isClassDeclaration() : null;
6059             if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
6060             {
6061                 // if super is defined in C++, it sets the vtable pointer to the base class
6062                 // so we have to restore it, but still return 'this' from super() call:
6063                 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
6064                 Loc loc = exp.loc;
6065 
6066                 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
6067                 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
6068                 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
6069 
6070                 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
6071                 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
6072 
6073                 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
6074 
6075                 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
6076 
6077                 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
6078                 result = e.expressionSemantic(sc);
6079             }
6080         }
6081 
6082         // `super.fun()` with fun being abstract and unimplemented
6083         auto supDotFun = exp.e1.isDotVarExp();
6084         if (supDotFun && supDotFun.e1.isSuperExp() && exp.f && exp.f.isAbstract() && !exp.f.fbody)
6085         {
6086             error(exp.loc, "call to unimplemented abstract function `%s`", exp.f.toFullSignature());
6087             errorSupplemental(exp.loc, "declared here: %s", exp.f.loc.toChars());
6088         }
6089 
6090         // declare dual-context container
6091         if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
6092         {
6093             // check access to second `this`
6094             if (AggregateDeclaration ad2 = exp.f.isMember2())
6095             {
6096                 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
6097                 if (te.op != EXP.error)
6098                     te = getRightThis(exp.loc, sc, ad2, te, exp.f);
6099                 if (te.op == EXP.error)
6100                 {
6101                     error(exp.loc, "need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
6102                     return setError();
6103                 }
6104             }
6105             exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
6106             Expression de = new DeclarationExp(exp.loc, exp.vthis2);
6107             result = Expression.combine(de, result);
6108             result = result.expressionSemantic(sc);
6109         }
6110     }
6111 
6112     override void visit(DeclarationExp e)
6113     {
6114         if (e.type)
6115         {
6116             result = e;
6117             return;
6118         }
6119         static if (LOGSEMANTIC)
6120         {
6121             printf("DeclarationExp::semantic() %s\n", e.toChars());
6122         }
6123 
6124         uint olderrors = global.errors;
6125 
6126         /* This is here to support extern(linkage) declaration,
6127          * where the extern(linkage) winds up being an AttribDeclaration
6128          * wrapper.
6129          */
6130         Dsymbol s = e.declaration;
6131 
6132         while (1)
6133         {
6134             AttribDeclaration ad = s.isAttribDeclaration();
6135             if (ad)
6136             {
6137                 if (ad.decl && ad.decl.length == 1)
6138                 {
6139                     s = (*ad.decl)[0];
6140                     continue;
6141                 }
6142             }
6143             break;
6144         }
6145 
6146         //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
6147         // Insert into both local scope and function scope.
6148         // Must be unique in both.
6149         if (s.ident)
6150         {
6151             VarDeclaration v = s.isVarDeclaration();
6152             if (v)
6153             {
6154                 if (sc.flags & SCOPE.Cfile)
6155                 {
6156                     /* Do semantic() on the type before inserting v into the symbol table
6157                      */
6158                     if (!v.originalType)
6159                         v.originalType = v.type.syntaxCopy();
6160                     Scope* sc2 = sc.push();
6161                     sc2.stc |= v.storage_class & STC.FUNCATTR;
6162                     sc2.linkage = LINK.c;       // account for the extern(C) in front of the declaration
6163                     v.inuse++;
6164                     v.type = v.type.typeSemantic(v.loc, sc2);
6165                     v.inuse--;
6166                     sc2.pop();
6167                 }
6168                 else
6169                 {
6170                     /* Do semantic() on initializer first so this will be illegal:
6171                      *      int a = a;
6172                      */
6173                     e.declaration.dsymbolSemantic(sc);
6174                     s.parent = sc.parent;
6175                 }
6176             }
6177 
6178             if (!sc.insert(s))
6179             {
6180                 auto conflict = sc.search(Loc.initial, s.ident, null);
6181                 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6182                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6183                                   conflict.kind(), conflict.toChars());
6184                 return setError();
6185             }
6186 
6187             if (v && (sc.flags & SCOPE.Cfile))
6188             {
6189                 /* Do semantic() on initializer last so this will be legal:
6190                  *      int a = a;
6191                  */
6192                 e.declaration.dsymbolSemantic(sc);
6193                 s.parent = sc.parent;
6194             }
6195 
6196             if (sc.func)
6197             {
6198                 // https://issues.dlang.org/show_bug.cgi?id=11720
6199                 if ((s.isFuncDeclaration() ||
6200                      s.isAggregateDeclaration() ||
6201                      s.isEnumDeclaration() ||
6202                      s.isTemplateDeclaration() ||
6203                      v
6204                     ) && !sc.func.localsymtab.insert(s))
6205                 {
6206                     // Get the previous symbol
6207                     Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
6208 
6209                     // Perturb the name mangling so that the symbols can co-exist
6210                     // instead of colliding
6211                     s.localNum = cast(ushort)(originalSymbol.localNum + 1);
6212                     // 65535 should be enough for anyone
6213                     if (!s.localNum)
6214                     {
6215                         error(e.loc, "more than 65535 symbols with name `%s` generated", s.ident.toChars());
6216                         return setError();
6217                     }
6218 
6219                     // Replace originalSymbol with s, which updates the localCount
6220                     sc.func.localsymtab.update(s);
6221 
6222                     // The mangling change only works for D mangling
6223                 }
6224 
6225                 if (!(sc.flags & SCOPE.Cfile))
6226                 {
6227                     /* https://issues.dlang.org/show_bug.cgi?id=21272
6228                      * If we are in a foreach body we need to extract the
6229                      * function containing the foreach
6230                      */
6231                     FuncDeclaration fes_enclosing_func;
6232                     if (sc.func && sc.func.fes)
6233                         fes_enclosing_func = sc.enclosing.enclosing.func;
6234 
6235                     // Disallow shadowing
6236                     for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
6237                     {
6238                         Dsymbol s2;
6239                         if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
6240                         {
6241                             // allow STC.local symbols to be shadowed
6242                             // TODO: not really an optimal design
6243                             auto decl = s2.isDeclaration();
6244                             if (!decl || !(decl.storage_class & STC.local))
6245                             {
6246                                 if (sc.func.fes)
6247                                 {
6248                                     deprecation(e.loc, "%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6249                                 }
6250                                 else
6251                                 {
6252                                     error(e.loc, "%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
6253                                     return setError();
6254                                 }
6255                             }
6256                         }
6257                     }
6258                 }
6259             }
6260         }
6261         if (!s.isVarDeclaration())
6262         {
6263             Scope* sc2 = sc;
6264             if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
6265                 sc2 = sc.push();
6266             sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
6267             e.declaration.dsymbolSemantic(sc2);
6268             if (sc2 != sc)
6269                 sc2.pop();
6270             s.parent = sc.parent;
6271         }
6272         if (global.errors == olderrors)
6273         {
6274             e.declaration.semantic2(sc);
6275             if (global.errors == olderrors)
6276             {
6277                 e.declaration.semantic3(sc);
6278             }
6279         }
6280         // todo: error in declaration should be propagated.
6281 
6282         e.type = Type.tvoid;
6283         result = e;
6284     }
6285 
6286     override void visit(TypeidExp exp)
6287     {
6288         static if (LOGSEMANTIC)
6289         {
6290             printf("TypeidExp::semantic() %s\n", exp.toChars());
6291         }
6292         Type ta = isType(exp.obj);
6293         Expression ea = isExpression(exp.obj);
6294         Dsymbol sa = isDsymbol(exp.obj);
6295         //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6296 
6297         if (ta)
6298         {
6299             dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
6300         }
6301 
6302         if (ea)
6303         {
6304             if (auto sym = getDsymbol(ea))
6305                 ea = symbolToExp(sym, exp.loc, sc, false);
6306             else
6307                 ea = ea.expressionSemantic(sc);
6308             ea = resolveProperties(sc, ea);
6309             ta = ea.type;
6310             if (ea.op == EXP.type)
6311                 ea = null;
6312         }
6313 
6314         if (!ta)
6315         {
6316             //printf("ta %p ea %p sa %p\n", ta, ea, sa);
6317             error(exp.loc, "no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
6318             return setError();
6319         }
6320 
6321         ta.checkComplexTransition(exp.loc, sc);
6322 
6323         Expression e;
6324         auto tb = ta.toBasetype();
6325         if (ea && tb.ty == Tclass)
6326         {
6327             if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
6328             {
6329                 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
6330                 e = ErrorExp.get();
6331             }
6332             else if (!Type.typeinfoclass)
6333             {
6334                 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
6335                 e = ErrorExp.get();
6336             }
6337             else
6338             {
6339                 /* Get the dynamic type, which is .classinfo
6340                 */
6341                 ea = ea.expressionSemantic(sc);
6342                 e = new TypeidExp(ea.loc, ea);
6343                 e.type = Type.typeinfoclass.type;
6344             }
6345         }
6346         else if (ta.ty == Terror)
6347         {
6348             e = ErrorExp.get();
6349         }
6350         else
6351         {
6352             // Handle this in the glue layer
6353             e = new TypeidExp(exp.loc, ta);
6354 
6355             bool genObjCode = true;
6356 
6357             // https://issues.dlang.org/show_bug.cgi?id=23650
6358             // We generate object code for typeinfo, required
6359             // by typeid, only if in non-speculative context
6360             if (sc.flags & SCOPE.compile)
6361             {
6362                 genObjCode = false;
6363             }
6364 
6365             e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
6366             semanticTypeInfo(sc, ta);
6367 
6368             if (ea)
6369             {
6370                 e = new CommaExp(exp.loc, ea, e); // execute ea
6371                 e = e.expressionSemantic(sc);
6372             }
6373         }
6374         result = e;
6375     }
6376 
6377     override void visit(TraitsExp e)
6378     {
6379         result = semanticTraits(e, sc);
6380     }
6381 
6382     override void visit(HaltExp e)
6383     {
6384         static if (LOGSEMANTIC)
6385         {
6386             printf("HaltExp::semantic()\n");
6387         }
6388         e.type = Type.tnoreturn;
6389         result = e;
6390     }
6391 
6392     override void visit(IsExp e)
6393     {
6394         /* is(targ id tok tspec)
6395          * is(targ id :  tok2)
6396          * is(targ id == tok2)
6397          */
6398         Type tded = null;
6399 
6400         void yes()
6401         {
6402             //printf("yes\n");
6403             if (!e.id)
6404             {
6405                 result = IntegerExp.createBool(true);
6406                 return;
6407             }
6408 
6409             Dsymbol s;
6410             Tuple tup = isTuple(tded);
6411             if (tup)
6412                 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
6413             else
6414                 s = new AliasDeclaration(e.loc, e.id, tded);
6415             s.dsymbolSemantic(sc);
6416 
6417             /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
6418              * More investigation is needed.
6419              */
6420             if (!tup && !sc.insert(s))
6421             {
6422                 auto conflict = sc.search(Loc.initial, s.ident, null);
6423                 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6424                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6425                                   conflict.kind(), conflict.toChars());
6426             }
6427 
6428             unSpeculative(sc, s);
6429 
6430             result = IntegerExp.createBool(true);
6431         }
6432         void no()
6433         {
6434             result = IntegerExp.createBool(false);
6435             //printf("no\n");
6436         }
6437 
6438         static if (LOGSEMANTIC)
6439         {
6440             printf("IsExp::semantic(%s)\n", e.toChars());
6441         }
6442         if (e.id && !(sc.flags & SCOPE.condition))
6443         {
6444             error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
6445             return setError();
6446         }
6447 
6448         if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
6449         {
6450             const oldErrors = global.startGagging();
6451             Dsymbol sym = e.targ.toDsymbol(sc);
6452             global.endGagging(oldErrors);
6453 
6454             if (sym is null)
6455                 return no();
6456             Package p = resolveIsPackage(sym);
6457             if (p is null)
6458                 return no();
6459             if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
6460                 return no();
6461             else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
6462                 return no();
6463             tded = e.targ;
6464             return yes();
6465         }
6466 
6467         {
6468             Scope* sc2 = sc.copy(); // keep sc.flags
6469             sc2.tinst = null;
6470             sc2.minst = null;
6471             sc2.flags |= SCOPE.fullinst;
6472             Type t = e.targ.trySemantic(e.loc, sc2);
6473             sc2.pop();
6474             if (!t) // errors, so condition is false
6475                 return no();
6476             e.targ = t;
6477         }
6478 
6479         if (e.tok2 != TOK.reserved)
6480         {
6481             switch (e.tok2)
6482             {
6483             case TOK.struct_:
6484                 if (e.targ.ty != Tstruct)
6485                     return no();
6486                 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
6487                     return no();
6488                 tded = e.targ;
6489                 break;
6490 
6491             case TOK.union_:
6492                 if (e.targ.ty != Tstruct)
6493                     return no();
6494                 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
6495                     return no();
6496                 tded = e.targ;
6497                 break;
6498 
6499             case TOK.class_:
6500                 if (e.targ.ty != Tclass)
6501                     return no();
6502                 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
6503                     return no();
6504                 tded = e.targ;
6505                 break;
6506 
6507             case TOK.interface_:
6508                 if (e.targ.ty != Tclass)
6509                     return no();
6510                 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
6511                     return no();
6512                 tded = e.targ;
6513                 break;
6514 
6515             case TOK.const_:
6516                 if (!e.targ.isConst())
6517                     return no();
6518                 tded = e.targ;
6519                 break;
6520 
6521             case TOK.immutable_:
6522                 if (!e.targ.isImmutable())
6523                     return no();
6524                 tded = e.targ;
6525                 break;
6526 
6527             case TOK.shared_:
6528                 if (!e.targ.isShared())
6529                     return no();
6530                 tded = e.targ;
6531                 break;
6532 
6533             case TOK.inout_:
6534                 if (!e.targ.isWild())
6535                     return no();
6536                 tded = e.targ;
6537                 break;
6538 
6539             case TOK.super_:
6540                 // If class or interface, get the base class and interfaces
6541                 if (e.targ.ty != Tclass)
6542                     return no();
6543                 else
6544                 {
6545                     ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
6546                     auto args = new Parameters();
6547                     args.reserve(cd.baseclasses.length);
6548                     if (cd.semanticRun < PASS.semanticdone)
6549                         cd.dsymbolSemantic(null);
6550                     for (size_t i = 0; i < cd.baseclasses.length; i++)
6551                     {
6552                         BaseClass* b = (*cd.baseclasses)[i];
6553                         args.push(new Parameter(Loc.initial, STC.in_, b.type, null, null, null));
6554                     }
6555                     tded = new TypeTuple(args);
6556                 }
6557                 break;
6558 
6559             case TOK.enum_:
6560                 if (e.targ.ty != Tenum)
6561                     return no();
6562                 if (e.id)
6563                     tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
6564                 else
6565                     tded = e.targ;
6566 
6567                 if (tded.ty == Terror)
6568                     return setError();
6569                 break;
6570 
6571             case TOK.delegate_:
6572                 if (e.targ.ty != Tdelegate)
6573                     return no();
6574                 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
6575                 break;
6576 
6577             case TOK.function_:
6578                 if (e.targ.ty != Tfunction)
6579                     return no();
6580                 goto case;
6581             case TOK.parameters:
6582                 {
6583                     if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
6584                         tded = tf;
6585                     else
6586                         return no();
6587 
6588                     /* Generate tuple from function parameter types.
6589                      */
6590                     auto args = new Parameters();
6591                     foreach (i, arg; tded.isTypeFunction().parameterList)
6592                     {
6593                         assert(arg && arg.type);
6594                         /* If one of the default arguments was an error,
6595                            don't return an invalid tuple
6596                          */
6597                         if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
6598                             return setError();
6599                         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));
6600                     }
6601                     tded = new TypeTuple(args);
6602                     break;
6603                 }
6604             case TOK.return_:
6605                 /* Get the 'return type' for the function,
6606                  * delegate, or pointer to function.
6607                  */
6608                 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
6609                     tded = tf.next;
6610                 else
6611                     return no();
6612                 break;
6613 
6614             case TOK.argumentTypes:
6615                 /* Generate a type tuple of the equivalent types used to determine if a
6616                  * function argument of this type can be passed in registers.
6617                  * The results of this are highly platform dependent, and intended
6618                  * primarly for use in implementing va_arg().
6619                  */
6620                 tded = target.toArgTypes(e.targ);
6621                 if (!tded)
6622                     return no();
6623                 // not valid for a parameter
6624                 break;
6625 
6626             case TOK.vector:
6627                 if (e.targ.ty != Tvector)
6628                     return no();
6629                 tded = (cast(TypeVector)e.targ).basetype;
6630                 break;
6631 
6632             default:
6633                 assert(0);
6634             }
6635 
6636             // https://issues.dlang.org/show_bug.cgi?id=18753
6637             if (tded)
6638                 return yes();
6639             return no();
6640         }
6641         else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
6642         {
6643             /* Evaluate to true if targ matches tspec
6644              * is(targ == tspec)
6645              * is(targ : tspec)
6646              */
6647             e.tspec = e.tspec.typeSemantic(e.loc, sc);
6648             //printf("targ  = %s, %s\n", e.targ.toChars(), e.targ.deco);
6649             //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
6650 
6651             if (e.tok == TOK.colon)
6652             {
6653                 // current scope is itself deprecated, or deprecations are not errors
6654                 const bool deprecationAllowed = sc.isDeprecated
6655                     || global.params.useDeprecated != DiagnosticReporting.error;
6656                 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
6657 
6658                 if (preventAliasThis && e.targ.ty == Tstruct)
6659                 {
6660                     if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6661                         return yes();
6662                     else
6663                         return no();
6664                 }
6665                 else if (preventAliasThis && e.targ.ty == Tclass)
6666                 {
6667                     if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6668                         return yes();
6669                     else
6670                         return no();
6671                 }
6672                 else if (e.targ.implicitConvTo(e.tspec))
6673                     return yes();
6674                 else
6675                     return no();
6676             }
6677             else /* == */
6678             {
6679                 if (e.targ.equals(e.tspec))
6680                     return yes();
6681                 else
6682                     return no();
6683             }
6684         }
6685         else if (e.tspec)
6686         {
6687             /* Evaluate to true if targ matches tspec.
6688              * If true, declare id as an alias for the specialized type.
6689              * is(targ == tspec, tpl)
6690              * is(targ : tspec, tpl)
6691              * is(targ id == tspec)
6692              * is(targ id : tspec)
6693              * is(targ id == tspec, tpl)
6694              * is(targ id : tspec, tpl)
6695              */
6696             Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
6697             e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
6698 
6699             Objects dedtypes = Objects(e.parameters.length);
6700             dedtypes.zero();
6701 
6702             MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
6703 
6704             if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
6705             {
6706                 return no();
6707             }
6708             else
6709             {
6710                 tded = cast(Type)dedtypes[0];
6711                 if (!tded)
6712                     tded = e.targ;
6713                 Objects tiargs = Objects(1);
6714                 tiargs[0] = e.targ;
6715 
6716                 /* Declare trailing parameters
6717                  */
6718                 for (size_t i = 1; i < e.parameters.length; i++)
6719                 {
6720                     TemplateParameter tp = (*e.parameters)[i];
6721                     Declaration s = null;
6722 
6723                     m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
6724                     if (m == MATCH.nomatch)
6725                         return no();
6726                     s.dsymbolSemantic(sc);
6727                     if (!sc.insert(s))
6728                     {
6729                         auto conflict = sc.search(Loc.initial, s.ident, null);
6730                         error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
6731                         errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6732                                           conflict.kind(), conflict.toChars());
6733                     }
6734 
6735                     unSpeculative(sc, s);
6736                 }
6737                 return yes();
6738             }
6739         }
6740         else if (e.id)
6741         {
6742             /* Declare id as an alias for type targ. Evaluate to true
6743              * is(targ id)
6744              */
6745             tded = e.targ;
6746         }
6747         return yes();
6748     }
6749 
6750     override void visit(BinAssignExp exp)
6751     {
6752         if (exp.type)
6753         {
6754             result = exp;
6755             return;
6756         }
6757 
6758         Expression e = exp.op_overload(sc);
6759         if (e)
6760         {
6761             result = e;
6762             return;
6763         }
6764 
6765         if (exp.e1.op == EXP.arrayLength)
6766         {
6767             // arr.length op= e2;
6768             e = rewriteOpAssign(exp);
6769             e = e.expressionSemantic(sc);
6770             result = e;
6771             return;
6772         }
6773         if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
6774         {
6775             if (checkNonAssignmentArrayOp(exp.e1))
6776                 return setError();
6777 
6778             if (exp.e1.op == EXP.slice)
6779                 (cast(SliceExp)exp.e1).arrayop = true;
6780 
6781             // T[] op= ...
6782             if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
6783             {
6784                 // T[] op= T
6785                 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
6786             }
6787             else if (Expression ex = typeCombine(exp, sc))
6788             {
6789                 result = ex;
6790                 return;
6791             }
6792             exp.type = exp.e1.type;
6793             result = arrayOp(exp, sc);
6794             return;
6795         }
6796 
6797         exp.e1 = exp.e1.expressionSemantic(sc);
6798         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
6799         exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
6800         exp.type = exp.e1.type;
6801 
6802         if (auto ad = isAggregate(exp.e1.type))
6803         {
6804             if (const s = search_function(ad, Id.opOpAssign))
6805             {
6806                 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());
6807                 return setError();
6808             }
6809         }
6810         if (exp.e1.checkScalar() ||
6811             exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
6812             exp.e1.checkSharedAccess(sc))
6813             return setError();
6814 
6815         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);
6816         int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
6817         int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
6818 
6819         if (bitwise && exp.type.toBasetype().ty == Tbool)
6820             exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
6821         else if (exp.checkNoBool())
6822             return setError();
6823 
6824         if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
6825         {
6826             result = scaleFactor(exp, sc);
6827             return;
6828         }
6829 
6830         if (Expression ex = typeCombine(exp, sc))
6831         {
6832             result = ex;
6833             return;
6834         }
6835 
6836         if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
6837             return setError();
6838         if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
6839             return setError();
6840 
6841         if (shift)
6842         {
6843             if (exp.e2.type.toBasetype().ty != Tvector)
6844                 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
6845         }
6846 
6847         if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
6848         {
6849             result = exp.incompatibleTypes();
6850             return;
6851         }
6852 
6853         if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
6854             return setError();
6855 
6856         e = exp.checkOpAssignTypes(sc);
6857         if (e.op == EXP.error)
6858         {
6859             result = e;
6860             return;
6861         }
6862 
6863         assert(e.op == EXP.assign || e == exp);
6864         result = (cast(BinExp)e).reorderSettingAAElem(sc);
6865     }
6866 
6867     private Expression compileIt(MixinExp exp)
6868     {
6869         OutBuffer buf;
6870         if (expressionsToString(buf, sc, exp.exps))
6871             return null;
6872 
6873         uint errors = global.errors;
6874         const len = buf.length;
6875         const str = buf.extractChars()[0 .. len];
6876         const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
6877         auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
6878         scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
6879         p.transitionIn = global.params.v.vin;
6880         p.nextToken();
6881         //printf("p.loc.linnum = %d\n", p.loc.linnum);
6882 
6883         Expression e = p.parseExpression();
6884         if (global.errors != errors)
6885             return null;
6886 
6887         if (p.token.value != TOK.endOfFile)
6888         {
6889             error(e.loc, "unexpected token `%s` after %s expression",
6890                 p.token.toChars(), EXPtoString(e.op).ptr);
6891             errorSupplemental(e.loc, "while parsing string mixin expression `%s`",
6892                 str.ptr);
6893             return null;
6894         }
6895         return e;
6896     }
6897 
6898     override void visit(MixinExp exp)
6899     {
6900         /* https://dlang.org/spec/expression.html#mixin_expressions
6901          */
6902 
6903         static if (LOGSEMANTIC)
6904         {
6905             printf("MixinExp::semantic('%s')\n", exp.toChars());
6906         }
6907 
6908         auto e = compileIt(exp);
6909         if (!e)
6910             return setError();
6911         result = e.expressionSemantic(sc);
6912     }
6913 
6914     override void visit(ImportExp e)
6915     {
6916         static if (LOGSEMANTIC)
6917         {
6918             printf("ImportExp::semantic('%s')\n", e.toChars());
6919         }
6920 
6921         auto se = semanticString(sc, e.e1, "file name argument");
6922         if (!se)
6923             return setError();
6924         se = se.toUTF8(sc);
6925 
6926         auto namez = se.toStringz();
6927         if (!global.filePath)
6928         {
6929             error(e.loc, "need `-J` switch to import text file `%s`", namez.ptr);
6930             return setError();
6931         }
6932 
6933         /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6934          * ('Path Traversal') attacks.
6935          * https://cwe.mitre.org/data/definitions/22.html
6936          */
6937 
6938         if (FileName.absolute(namez))
6939         {
6940             error(e.loc, "absolute path is not allowed in import expression: `%s`", se.toChars());
6941             return setError();
6942         }
6943 
6944         auto idxReserved = FileName.findReservedChar(namez);
6945         if (idxReserved != size_t.max)
6946         {
6947             error(e.loc, "`%s` is not a valid filename on this platform", se.toChars());
6948             errorSupplemental(e.loc, "Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6949             return setError();
6950         }
6951 
6952         if (FileName.refersToParentDir(namez))
6953         {
6954             error(e.loc, "path refers to parent (`..`) directory: `%s`", se.toChars());
6955             return setError();
6956         }
6957 
6958         auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6959         if (!resolvedNamez)
6960         {
6961             error(e.loc, "file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6962             errorSupplemental(e.loc, "Path(s) searched (as provided by `-J`):");
6963             foreach (idx, path; *global.filePath)
6964             {
6965                 const attr = FileName.exists(path);
6966                 const(char)* err = attr == 2 ? "" :
6967                     (attr == 1 ? " (not a directory)" : " (path not found)");
6968                 errorSupplemental(e.loc, "[%llu]: `%s`%s", cast(ulong)idx, path, err);
6969             }
6970             return setError();
6971         }
6972 
6973         sc._module.contentImportedFiles.push(resolvedNamez.ptr);
6974         if (global.params.v.verbose)
6975         {
6976             const slice = se.peekString();
6977             message("file      %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
6978         }
6979         if (global.params.moduleDeps.buffer !is null)
6980         {
6981             OutBuffer* ob = global.params.moduleDeps.buffer;
6982             Module imod = sc._module;
6983 
6984             if (!global.params.moduleDeps.name)
6985                 ob.writestring("depsFile ");
6986             ob.writestring(imod.toPrettyChars());
6987             ob.writestring(" (");
6988             escapePath(ob, imod.srcfile.toChars());
6989             ob.writestring(") : ");
6990             if (global.params.moduleDeps.name)
6991                 ob.writestring("string : ");
6992             ob.write(se.peekString());
6993             ob.writestring(" (");
6994             escapePath(ob, resolvedNamez.ptr);
6995             ob.writestring(")");
6996             ob.writenl();
6997         }
6998         if (global.params.makeDeps.doOutput)
6999         {
7000             global.params.makeDeps.files.push(resolvedNamez.ptr);
7001         }
7002 
7003         {
7004             auto fileName = FileName(resolvedNamez);
7005             if (auto fmResult = global.fileManager.lookup(fileName))
7006             {
7007                 se = new StringExp(e.loc, fmResult);
7008             }
7009             else
7010             {
7011                 error(e.loc, "cannot read file `%s`", resolvedNamez.ptr);
7012                 return setError();
7013             }
7014         }
7015         result = se.expressionSemantic(sc);
7016     }
7017 
7018     override void visit(AssertExp exp)
7019     {
7020         // https://dlang.org/spec/expression.html#assert_expressions
7021         static if (LOGSEMANTIC)
7022         {
7023             printf("AssertExp::semantic('%s')\n", exp.toChars());
7024         }
7025 
7026         const generateMsg = !exp.msg &&
7027                             sc.needsCodegen() && // let ctfe interpreter handle the error message
7028                             global.params.checkAction == CHECKACTION.context &&
7029                             global.params.useAssert == CHECKENABLE.on &&
7030                             !((exp.e1.isIntegerExp() && (exp.e1.toInteger() == 0)) ||
7031                                exp.e1.isNullExp());
7032         Expression temporariesPrefix;
7033 
7034         if (generateMsg)
7035         // no message - use assert expression as msg
7036         {
7037             if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
7038                 return setError();
7039 
7040             /*
7041             {
7042               auto a = e1, b = e2;
7043               assert(a == b, _d_assert_fail!"=="(a, b));
7044             }()
7045             */
7046 
7047             /*
7048             Stores the result of an operand expression into a temporary
7049             if necessary, e.g. if it is an impure fuction call containing side
7050             effects as in https://issues.dlang.org/show_bug.cgi?id=20114
7051 
7052             Params:
7053                 op = an expression which may require a temporary (added to
7054                      `temporariesPrefix`: `auto tmp = op`) and will be replaced
7055                      by `tmp` if necessary
7056 
7057             Returns: (possibly replaced) `op`
7058             */
7059             Expression maybePromoteToTmp(ref Expression op)
7060             {
7061                 // https://issues.dlang.org/show_bug.cgi?id=20989
7062                 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
7063                 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
7064                 {
7065                     auto die = op.isDotIdExp();
7066                     if (die && die.ident == Id.ptr)
7067                         die.noderef = true;
7068                 }
7069 
7070                 op = op.expressionSemantic(sc);
7071                 op = resolveProperties(sc, op);
7072 
7073                 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
7074                 if (auto te = op.isTypeExp())
7075                 {
7076                     // Replace the TypeExp with it's textual representation
7077                     // Including "..." in the error message isn't quite right but
7078                     // proper solutions require more drastic changes, e.g. directly
7079                     // using miniFormat and combine instead of calling _d_assert_fail
7080                     auto name = new StringExp(te.loc, te.toString());
7081                     return name.expressionSemantic(sc);
7082                 }
7083 
7084                 // Create a temporary for expressions with side effects
7085                 // Defensively assume that function calls may have side effects even
7086                 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
7087                 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
7088                 if (op.hasSideEffect(true))
7089                 {
7090                     // Don't create an invalid temporary for void-expressions
7091                     // Further semantic will issue an appropriate error
7092                     if (op.type.ty == Tvoid)
7093                         return op;
7094 
7095                     // https://issues.dlang.org/show_bug.cgi?id=21590
7096                     // Don't create unnecessary temporaries and detect `assert(a = b)`
7097                     if (op.isAssignExp() || op.isBinAssignExp())
7098                     {
7099                         auto left = (cast(BinExp) op).e1;
7100 
7101                         // Find leftmost expression to handle other rewrites,
7102                         // e.g. --(++a) => a += 1 -= 1
7103                         while (left.isAssignExp() || left.isBinAssignExp())
7104                             left = (cast(BinExp) left).e1;
7105 
7106                         // Only use the assignee if it's a variable and skip
7107                         // other lvalues (e.g. ref's returned by functions)
7108                         if (left.isVarExp())
7109                             return left;
7110 
7111                         // Sanity check that `op` can be converted to boolean
7112                         // But don't raise errors for assignments enclosed in another expression
7113                         if (op is exp.e1)
7114                             op.toBoolean(sc);
7115                     }
7116 
7117                     // Tuples with side-effects already receive a temporary during semantic
7118                     if (op.type.isTypeTuple())
7119                     {
7120                         auto te = op.isTupleExp();
7121                         assert(te);
7122 
7123                         // Create a new tuple without the associated temporary
7124                         auto res = new TupleExp(op.loc, te.exps);
7125                         return res.expressionSemantic(sc);
7126                     }
7127 
7128                     const stc = op.isLvalue() ? STC.ref_ : 0;
7129                     auto tmp = copyToTemp(stc, "__assertOp", op);
7130                     tmp.dsymbolSemantic(sc);
7131 
7132                     auto decl = new DeclarationExp(op.loc, tmp);
7133                     temporariesPrefix = Expression.combine(temporariesPrefix, decl);
7134 
7135                     op = new VarExp(op.loc, tmp);
7136                     op = op.expressionSemantic(sc);
7137                 }
7138                 return op;
7139             }
7140 
7141             // if the assert condition is a mixin expression, try to compile it
7142             if (auto ce = exp.e1.isMixinExp())
7143             {
7144                 if (auto e1 = compileIt(ce))
7145                     exp.e1 = e1;
7146             }
7147 
7148             Expressions* es;
7149             Objects* tiargs;
7150             Loc loc = exp.e1.loc;
7151 
7152             const op = exp.e1.op;
7153             bool isEqualsCallExpression;
7154             if (const callExp = exp.e1.isCallExp())
7155             {
7156                 // https://issues.dlang.org/show_bug.cgi?id=20331
7157                 // callExp.f may be null if the assert contains a call to
7158                 // a function pointer or literal
7159                 if (const callExpFunc = callExp.f)
7160                 {
7161                     const callExpIdent = callExpFunc.ident;
7162                     isEqualsCallExpression = callExpIdent == Id.__equals ||
7163                                              callExpIdent == Id.eq;
7164                 }
7165             }
7166             if (op == EXP.equal || op == EXP.notEqual ||
7167                 op == EXP.lessThan || op == EXP.greaterThan ||
7168                 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
7169                 op == EXP.identity || op == EXP.notIdentity ||
7170                 op == EXP.in_ ||
7171                 isEqualsCallExpression)
7172             {
7173                 es = new Expressions(3);
7174                 tiargs = new Objects(1);
7175 
7176                 if (isEqualsCallExpression)
7177                 {
7178                     auto callExp = cast(CallExp) exp.e1;
7179                     auto args = callExp.arguments;
7180 
7181                     // structs with opEquals get rewritten to a DotVarExp:
7182                     // a.opEquals(b)
7183                     // https://issues.dlang.org/show_bug.cgi?id=20100
7184                     if (args.length == 1)
7185                     {
7186                         auto dv = callExp.e1.isDotVarExp();
7187                         assert(dv);
7188 
7189                         // runtime args
7190                         (*es)[1] = maybePromoteToTmp(dv.e1);
7191                         (*es)[2] = maybePromoteToTmp((*args)[0]);
7192                     }
7193                     else
7194                     {
7195                         // runtime args
7196                         (*es)[1] = maybePromoteToTmp((*args)[0]);
7197                         (*es)[2] = maybePromoteToTmp((*args)[1]);
7198                     }
7199                 }
7200                 else
7201                 {
7202                     auto binExp = cast(EqualExp) exp.e1;
7203 
7204                     // runtime args
7205                     (*es)[1] = maybePromoteToTmp(binExp.e1);
7206                     (*es)[2] = maybePromoteToTmp(binExp.e2);
7207                 }
7208 
7209                 // template args
7210                 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
7211                 comp = comp.expressionSemantic(sc);
7212                 (*es)[0] = comp;
7213                 (*tiargs)[0] = (*es)[1].type;
7214             }
7215 
7216             // Format exp.e1 before any additional boolean conversion
7217             // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
7218             else if (op != EXP.andAnd && op != EXP.orOr)
7219             {
7220                 es = new Expressions(2);
7221                 tiargs = new Objects(1);
7222 
7223                 if (auto ne = exp.e1.isNotExp())
7224                 {
7225                     // Fetch the (potential non-bool) expression and fold
7226                     // (n) negations into (n % 2) negations, e.g. !!a => a
7227                     for (bool neg = true; ; neg = !neg)
7228                     {
7229                         if (auto ne2 = ne.e1.isNotExp())
7230                             ne = ne2;
7231                         else
7232                         {
7233                             (*es)[0] = new StringExp(loc, neg ? "!" : "");
7234                             (*es)[1] = maybePromoteToTmp(ne.e1);
7235                             break;
7236                         }
7237                     }
7238                 }
7239                 else
7240                 {   // Simply format exp.e1
7241                     (*es)[0] = new StringExp(loc, "");
7242                     (*es)[1] = maybePromoteToTmp(exp.e1);
7243                 }
7244 
7245                 (*tiargs)[0] = (*es)[1].type;
7246 
7247                 // Passing __ctfe to auto ref infers ref and aborts compilation:
7248                 // "cannot modify compiler-generated variable __ctfe"
7249                 auto ve = (*es)[1].isVarExp();
7250                 if (ve && ve.var.ident == Id.ctfe)
7251                 {
7252                     exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
7253                     goto LSkip;
7254                 }
7255             }
7256             else
7257             {
7258                 OutBuffer buf;
7259                 buf.printf("`%s` failed", exp.toChars());
7260                 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
7261                 goto LSkip;
7262             }
7263 
7264             Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
7265             auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
7266 
7267             auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
7268             auto ec = CallExp.create(loc, dt, es);
7269             exp.msg = ec;
7270         }
7271 
7272         LSkip:
7273         if (Expression ex = unaSemantic(exp, sc))
7274         {
7275             result = ex;
7276             return;
7277         }
7278 
7279         exp.e1 = resolveProperties(sc, exp.e1);
7280         // BUG: see if we can do compile time elimination of the Assert
7281         exp.e1 = exp.e1.optimize(WANTvalue);
7282         exp.e1 = exp.e1.toBoolean(sc);
7283 
7284         if (exp.e1.op == EXP.error)
7285         {
7286             result = exp.e1;
7287             return;
7288         }
7289 
7290         if (exp.msg)
7291         {
7292             exp.msg = expressionSemantic(exp.msg, sc);
7293             exp.msg = resolveProperties(sc, exp.msg);
7294             exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
7295             exp.msg = exp.msg.optimize(WANTvalue);
7296             checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
7297         }
7298 
7299         if (exp.msg && exp.msg.op == EXP.error)
7300         {
7301             result = exp.msg;
7302             return;
7303         }
7304 
7305         auto f1 = checkNonAssignmentArrayOp(exp.e1);
7306         auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
7307         if (f1 || f2)
7308             return setError();
7309 
7310         if (exp.e1.toBool().hasValue(false))
7311         {
7312             /* This is an `assert(0)` which means halt program execution
7313              */
7314             FuncDeclaration fd = sc.parent.isFuncDeclaration();
7315             if (fd)
7316                 fd.hasReturnExp |= 4;
7317             sc.ctorflow.orCSX(CSX.halt);
7318 
7319             if (global.params.useAssert == CHECKENABLE.off)
7320             {
7321                 Expression e = new HaltExp(exp.loc);
7322                 e = e.expressionSemantic(sc);
7323                 result = e;
7324                 return;
7325             }
7326 
7327             // Only override the type when it isn't already some flavour of noreturn,
7328             // e.g. when this assert was generated by defaultInitLiteral
7329             if (!exp.type || !exp.type.isTypeNoreturn())
7330                 exp.type = Type.tnoreturn;
7331         }
7332         else
7333             exp.type = Type.tvoid;
7334 
7335         result = !temporariesPrefix
7336             ? exp
7337             : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
7338     }
7339 
7340     override void visit(ThrowExp te)
7341     {
7342         import dmd.statementsem;
7343 
7344         if (throwSemantic(te.loc, te.e1, sc))
7345             result = te;
7346         else
7347             setError();
7348     }
7349 
7350     override void visit(DotIdExp exp)
7351     {
7352         static if (LOGSEMANTIC)
7353         {
7354             printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
7355             //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
7356         }
7357 
7358         if (sc.flags & SCOPE.Cfile)
7359         {
7360             /* See if need to rewrite the AST because of cast/call ambiguity
7361              */
7362             if (auto e = castCallAmbiguity(exp, sc))
7363             {
7364                 result = expressionSemantic(e, sc);
7365                 return;
7366             }
7367 
7368             if (exp.arrow) // ImportC only
7369                 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
7370 
7371             if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
7372             {
7373                 // C11 6.5.3 says _Alignof only applies to types
7374                 Expression e;
7375                 Type t;
7376                 Dsymbol s;
7377                 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
7378                 if (e)
7379                 {
7380                     error(exp.e1.loc, "argument to `_Alignof` must be a type");
7381                     return setError();
7382                 }
7383                 else if (t)
7384                 {
7385                     // Note similarity to getProperty() implementation of __xalignof
7386                     const explicitAlignment = t.alignment();
7387                     const naturalAlignment = t.alignsize();
7388                     const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
7389                     result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
7390                 }
7391                 else if (s)
7392                 {
7393                     error(exp.e1.loc, "argument to `_Alignof` must be a type");
7394                     return setError();
7395                 }
7396                 else
7397                     assert(0);
7398                 return;
7399             }
7400 
7401             if (exp.ident != Id.__sizeof)
7402             {
7403                 result = fieldLookup(exp.e1, sc, exp.ident, exp.arrow);
7404                 return;
7405             }
7406         }
7407 
7408         Expression e = exp.dotIdSemanticProp(sc, 1);
7409 
7410         if (e && isDotOpDispatch(e))
7411         {
7412             auto ode = e;
7413             uint errors = global.startGagging();
7414             e = resolvePropertiesX(sc, e);
7415             // Any error or if 'e' is not resolved, go to UFCS
7416             if (global.endGagging(errors) || e is ode)
7417                 e = null; /* fall down to UFCS */
7418             else
7419             {
7420                 result = e;
7421                 return;
7422             }
7423         }
7424         if (!e) // if failed to find the property
7425         {
7426             /* If ident is not a valid property, rewrite:
7427              *   e1.ident
7428              * as:
7429              *   .ident(e1)
7430              */
7431             e = resolveUFCSProperties(sc, exp);
7432         }
7433         result = e;
7434     }
7435 
7436     override void visit(DotTemplateExp e)
7437     {
7438         if (e.type)
7439         {
7440             result = e;
7441             return;
7442         }
7443         if (Expression ex = unaSemantic(e, sc))
7444         {
7445             result = ex;
7446             return;
7447         }
7448         // 'void' like TemplateExp
7449         e.type = Type.tvoid;
7450         result = e;
7451     }
7452 
7453     override void visit(DotVarExp exp)
7454     {
7455         static if (LOGSEMANTIC)
7456         {
7457             printf("DotVarExp::semantic('%s')\n", exp.toChars());
7458         }
7459         if (exp.type)
7460         {
7461             result = exp;
7462             return;
7463         }
7464 
7465         exp.var = exp.var.toAlias().isDeclaration();
7466 
7467         exp.e1 = exp.e1.expressionSemantic(sc);
7468 
7469         if (auto tup = exp.var.isTupleDeclaration())
7470         {
7471             /* Replace:
7472              *  e1.tuple(a, b, c)
7473              * with:
7474              *  tuple(e1.a, e1.b, e1.c)
7475              */
7476             Expression e0;
7477             Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
7478 
7479             auto exps = new Expressions();
7480             exps.reserve(tup.objects.length);
7481             for (size_t i = 0; i < tup.objects.length; i++)
7482             {
7483                 RootObject o = (*tup.objects)[i];
7484                 Expression e;
7485                 Declaration var;
7486                 switch (o.dyncast()) with (DYNCAST)
7487                 {
7488                 case expression:
7489                     e = cast(Expression)o;
7490                     if (auto se = e.isDsymbolExp())
7491                         var = se.s.isDeclaration();
7492                     else if (auto ve = e.isVarExp())
7493                         if (!ve.var.isFuncDeclaration())
7494                             // Exempt functions for backwards compatibility reasons.
7495                             // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
7496                             var = ve.var;
7497                     break;
7498                 case dsymbol:
7499                     Dsymbol s = cast(Dsymbol) o;
7500                     Declaration d = s.isDeclaration();
7501                     if (!d || d.isFuncDeclaration())
7502                         // Exempt functions for backwards compatibility reasons.
7503                         // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
7504                         e = new DsymbolExp(exp.loc, s);
7505                     else
7506                         var = d;
7507                     break;
7508                 case type:
7509                     e = new TypeExp(exp.loc, cast(Type)o);
7510                     break;
7511                 default:
7512                     error(exp.loc, "`%s` is not an expression", o.toChars());
7513                     return setError();
7514                 }
7515                 if (var)
7516                     e = new DotVarExp(exp.loc, ev, var);
7517                 exps.push(e);
7518             }
7519 
7520             Expression e = new TupleExp(exp.loc, e0, exps);
7521             e = e.expressionSemantic(sc);
7522             result = e;
7523             return;
7524         }
7525         else if (auto ad = exp.var.isAliasDeclaration())
7526         {
7527             if (auto t = ad.getType())
7528             {
7529                 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
7530                 return;
7531             }
7532         }
7533 
7534         exp.e1 = exp.e1.addDtorHook(sc);
7535 
7536         Type t1 = exp.e1.type;
7537 
7538         if (FuncDeclaration fd = exp.var.isFuncDeclaration())
7539         {
7540             // for functions, do checks after overload resolution
7541             if (!fd.functionSemantic())
7542                 return setError();
7543 
7544             /* https://issues.dlang.org/show_bug.cgi?id=13843
7545              * If fd obviously has no overloads, we should
7546              * normalize AST, and it will give a chance to wrap fd with FuncExp.
7547              */
7548             if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
7549             {
7550                 // (e1, fd)
7551                 auto e = symbolToExp(fd, exp.loc, sc, false);
7552                 result = Expression.combine(exp.e1, e);
7553                 return;
7554             }
7555 
7556             exp.type = fd.type;
7557             assert(exp.type);
7558         }
7559         else if (OverDeclaration od = exp.var.isOverDeclaration())
7560         {
7561             exp.type = Type.tvoid; // ambiguous type?
7562         }
7563         else
7564         {
7565             exp.type = exp.var.type;
7566             if (!exp.type && global.errors) // var is goofed up, just return error.
7567                 return setError();
7568             assert(exp.type);
7569 
7570             if (t1.ty == Tpointer)
7571                 t1 = t1.nextOf();
7572 
7573             exp.type = exp.type.addMod(t1.mod);
7574 
7575             // https://issues.dlang.org/show_bug.cgi?id=23109
7576             // Run semantic on the DotVarExp type
7577             if (auto handle = exp.type.isClassHandle())
7578             {
7579                 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
7580                     handle.dsymbolSemantic(null);
7581             }
7582 
7583             Dsymbol vparent = exp.var.toParent();
7584             AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
7585             if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
7586                 exp.e1 = e1x;
7587             else
7588             {
7589                 /* Later checkRightThis will report correct error for invalid field variable access.
7590                  */
7591                 Expression e = new VarExp(exp.loc, exp.var);
7592                 e = e.expressionSemantic(sc);
7593                 result = e;
7594                 return;
7595             }
7596             checkAccess(exp.loc, sc, exp.e1, exp.var);
7597 
7598             VarDeclaration v = exp.var.isVarDeclaration();
7599             if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
7600             {
7601                 Expression e = expandVar(WANTvalue, v);
7602                 if (e)
7603                 {
7604                     result = e;
7605                     return;
7606                 }
7607             }
7608 
7609             if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
7610                       (!v.needThis() && v.semanticRun > PASS.initial)))  // fix https://issues.dlang.org/show_bug.cgi?id=17258
7611             {
7612                 // (e1, v)
7613                 checkAccess(exp.loc, sc, exp.e1, v);
7614                 Expression e = new VarExp(exp.loc, v);
7615                 e = new CommaExp(exp.loc, exp.e1, e);
7616                 e = e.expressionSemantic(sc);
7617                 result = e;
7618                 return;
7619             }
7620         }
7621         //printf("-DotVarExp::semantic('%s')\n", toChars());
7622         result = exp;
7623     }
7624 
7625     override void visit(DotTemplateInstanceExp exp)
7626     {
7627         static if (LOGSEMANTIC)
7628         {
7629             printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
7630         }
7631         if (exp.type)
7632         {
7633             result = exp;
7634             return;
7635         }
7636         // Indicate we need to resolve by UFCS.
7637         Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
7638         if (!e)
7639             e = resolveUFCSProperties(sc, exp);
7640         if (e is exp)
7641             e.type = Type.tvoid; // Unresolved type, because it needs inference
7642         result = e;
7643     }
7644 
7645     override void visit(DelegateExp e)
7646     {
7647         static if (LOGSEMANTIC)
7648         {
7649             printf("DelegateExp::semantic('%s')\n", e.toChars());
7650         }
7651         if (e.type)
7652         {
7653             result = e;
7654             return;
7655         }
7656 
7657         e.e1 = e.e1.expressionSemantic(sc);
7658 
7659         e.type = new TypeDelegate(e.func.type.isTypeFunction());
7660         e.type = e.type.typeSemantic(e.loc, sc);
7661 
7662         FuncDeclaration f = e.func.toAliasFunc();
7663         AggregateDeclaration ad = f.isMemberLocal();
7664         if (f.needThis())
7665             e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
7666 
7667         if (f.type.ty == Tfunction)
7668         {
7669             TypeFunction tf = cast(TypeFunction)f.type;
7670             if (!MODmethodConv(e.e1.type.mod, f.type.mod))
7671             {
7672                 OutBuffer thisBuf, funcBuf;
7673                 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
7674                 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
7675                 error(e.loc, "%smethod `%s` is not callable using a %s`%s`",
7676                     funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
7677                 return setError();
7678             }
7679         }
7680         if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
7681         {
7682             // A downcast is required for interfaces
7683             // https://issues.dlang.org/show_bug.cgi?id=3706
7684             e.e1 = new CastExp(e.loc, e.e1, ad.type);
7685             e.e1 = e.e1.expressionSemantic(sc);
7686         }
7687         result = e;
7688         // declare dual-context container
7689         if (f.hasDualContext() && !sc.intypeof && sc.func)
7690         {
7691             // check access to second `this`
7692             if (AggregateDeclaration ad2 = f.isMember2())
7693             {
7694                 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
7695                 if (te.op != EXP.error)
7696                     te = getRightThis(e.loc, sc, ad2, te, f);
7697                 if (te.op == EXP.error)
7698                 {
7699                     error(e.loc, "need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
7700                     return setError();
7701                 }
7702             }
7703             VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
7704             e.vthis2 = vthis2;
7705             Expression de = new DeclarationExp(e.loc, vthis2);
7706             result = Expression.combine(de, result);
7707             result = result.expressionSemantic(sc);
7708         }
7709     }
7710 
7711     override void visit(DotTypeExp exp)
7712     {
7713         static if (LOGSEMANTIC)
7714         {
7715             printf("DotTypeExp::semantic('%s')\n", exp.toChars());
7716         }
7717         if (exp.type)
7718         {
7719             result = exp;
7720             return;
7721         }
7722 
7723         if (auto e = unaSemantic(exp, sc))
7724         {
7725             result = e;
7726             return;
7727         }
7728 
7729         exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
7730         result = exp;
7731     }
7732 
7733     override void visit(AddrExp exp)
7734     {
7735         static if (LOGSEMANTIC)
7736         {
7737             printf("AddrExp::semantic('%s')\n", exp.toChars());
7738         }
7739         if (exp.type)
7740         {
7741             result = exp;
7742             return;
7743         }
7744 
7745         if (Expression ex = unaSemantic(exp, sc))
7746         {
7747             result = ex;
7748             return;
7749         }
7750 
7751         if (sc.flags & SCOPE.Cfile)
7752         {
7753             /* Special handling for &"string"/&(T[]){0, 1}
7754              * since C regards string/array literals as lvalues
7755              */
7756             auto e = exp.e1;
7757             if(e.isStringExp() || e.isArrayLiteralExp())
7758             {
7759                 e.type = typeSemantic(e.type, Loc.initial, sc);
7760                 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
7761                 if (!e.type.isTypePointer())
7762                 {
7763                     e.type = e.type.pointerTo();
7764                     result = e;
7765                     return;
7766                 }
7767                 else
7768                 {
7769                     // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7770                     exp.toLvalue(sc, null);
7771                     return setError();
7772                 }
7773             }
7774         }
7775 
7776         int wasCond = exp.e1.op == EXP.question;
7777 
7778         if (exp.e1.op == EXP.dotTemplateInstance)
7779         {
7780             DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
7781             TemplateInstance ti = dti.ti;
7782             {
7783                 //assert(ti.needsTypeInference(sc));
7784                 ti.dsymbolSemantic(sc);
7785                 if (!ti.inst || ti.errors) // if template failed to expand
7786                     return setError();
7787 
7788                 Dsymbol s = ti.toAlias();
7789                 FuncDeclaration f = s.isFuncDeclaration();
7790                 if (f)
7791                 {
7792                     exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
7793                     exp.e1 = exp.e1.expressionSemantic(sc);
7794                 }
7795             }
7796         }
7797         else if (exp.e1.op == EXP.scope_)
7798         {
7799             TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
7800             if (ti)
7801             {
7802                 //assert(ti.needsTypeInference(sc));
7803                 ti.dsymbolSemantic(sc);
7804                 if (!ti.inst || ti.errors) // if template failed to expand
7805                     return setError();
7806 
7807                 Dsymbol s = ti.toAlias();
7808                 FuncDeclaration f = s.isFuncDeclaration();
7809                 if (f)
7810                 {
7811                     exp.e1 = new VarExp(exp.e1.loc, f);
7812                     exp.e1 = exp.e1.expressionSemantic(sc);
7813                 }
7814             }
7815         }
7816         /* https://issues.dlang.org/show_bug.cgi?id=809
7817          *
7818          * If the address of a lazy variable is taken,
7819          * the expression is rewritten so that the type
7820          * of it is the delegate type. This means that
7821          * the symbol is not going to represent a call
7822          * to the delegate anymore, but rather, the
7823          * actual symbol.
7824          */
7825         if (auto ve = exp.e1.isVarExp())
7826         {
7827             if (ve.var.storage_class & STC.lazy_)
7828             {
7829                 exp.e1 = exp.e1.expressionSemantic(sc);
7830                 exp.e1 = resolveProperties(sc, exp.e1);
7831                 if (auto callExp = exp.e1.isCallExp())
7832                 {
7833                     if (callExp.e1.type.toBasetype().ty == Tdelegate)
7834                     {
7835                         /* https://issues.dlang.org/show_bug.cgi?id=20551
7836                          *
7837                          * Cannot take address of lazy parameter in @safe code
7838                          * because it might end up being a pointer to undefined
7839                          * memory.
7840                          */
7841                         if (1)
7842                         {
7843                             if (sc.setUnsafe(false, exp.loc,
7844                                 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
7845                             {
7846                                 setError();
7847                                 return;
7848                             }
7849                         }
7850                         VarExp ve2 = callExp.e1.isVarExp();
7851                         ve2.delegateWasExtracted = true;
7852                         ve2.var.storage_class |= STC.scope_;
7853                         result = ve2;
7854                         return;
7855                     }
7856                 }
7857             }
7858         }
7859 
7860         exp.e1 = exp.e1.toLvalue(sc, null);
7861         if (exp.e1.op == EXP.error)
7862         {
7863             result = exp.e1;
7864             return;
7865         }
7866         if (checkNonAssignmentArrayOp(exp.e1))
7867             return setError();
7868 
7869         if (!exp.e1.type)
7870         {
7871             error(exp.loc, "cannot take address of `%s`", exp.e1.toChars());
7872             return setError();
7873         }
7874         if (!checkAddressable(exp, sc))
7875             return setError();
7876 
7877         bool hasOverloads;
7878         if (auto f = isFuncAddress(exp, &hasOverloads))
7879         {
7880             if (!hasOverloads && f.checkForwardRef(exp.loc))
7881                 return setError();
7882         }
7883         else if (!exp.e1.type.deco)
7884         {
7885             // try to resolve the type
7886             exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, sc);
7887             if (!exp.e1.type.deco)  // still couldn't resolve it
7888             {
7889                 if (auto ve = exp.e1.isVarExp())
7890                 {
7891                     Declaration d = ve.var;
7892                     error(exp.loc, "forward reference to %s `%s`", d.kind(), d.toChars());
7893                 }
7894                 else
7895                     error(exp.loc, "forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7896                 return setError();
7897             }
7898         }
7899 
7900         exp.type = exp.e1.type.pointerTo();
7901 
7902         // See if this should really be a delegate
7903         if (exp.e1.op == EXP.dotVariable)
7904         {
7905             DotVarExp dve = cast(DotVarExp)exp.e1;
7906             FuncDeclaration f = dve.var.isFuncDeclaration();
7907             if (f)
7908             {
7909                 f = f.toAliasFunc(); // FIXME, should see overloads
7910                                      // https://issues.dlang.org/show_bug.cgi?id=1983
7911                 if (!dve.hasOverloads)
7912                     f.tookAddressOf++;
7913 
7914                 Expression e;
7915                 if (f.needThis())
7916                     e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
7917                 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7918                     e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
7919                 e = e.expressionSemantic(sc);
7920                 result = e;
7921                 return;
7922             }
7923 
7924             // Look for misaligned pointer in @safe mode
7925             if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7926                 return setError();
7927         }
7928         else if (exp.e1.op == EXP.variable)
7929         {
7930             VarExp ve = cast(VarExp)exp.e1;
7931             VarDeclaration v = ve.var.isVarDeclaration();
7932             if (v)
7933             {
7934                 if (!checkAddressVar(sc, exp.e1, v))
7935                     return setError();
7936 
7937                 ve.checkPurity(sc, v);
7938             }
7939             FuncDeclaration f = ve.var.isFuncDeclaration();
7940             if (f)
7941             {
7942                 /* Because nested functions cannot be overloaded,
7943                  * mark here that we took its address because castTo()
7944                  * may not be called with an exact match.
7945                  *
7946                  * https://issues.dlang.org/show_bug.cgi?id=19285 :
7947                  * We also need to make sure we aren't inside a typeof. Ideally the compiler
7948                  * would do typeof(...) semantic analysis speculatively then collect information
7949                  * about what it used rather than relying on what are effectively semantically-global
7950                  * variables but it doesn't.
7951                  */
7952                 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
7953                 {
7954                     // TODO: Refactor to use a proper interface that can keep track of causes.
7955                     f.tookAddressOf++;
7956                 }
7957 
7958                 if (f.isNested() && !f.needThis())
7959                 {
7960                     if (f.isFuncLiteralDeclaration())
7961                     {
7962                         if (!f.FuncDeclaration.isNested())
7963                         {
7964                             /* Supply a 'null' for a this pointer if no this is available
7965                              */
7966                             Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7967                             e = e.expressionSemantic(sc);
7968                             result = e;
7969                             return;
7970                         }
7971                     }
7972                     Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7973                     e = e.expressionSemantic(sc);
7974                     result = e;
7975                     return;
7976                 }
7977                 if (f.needThis())
7978                 {
7979                     auto memberFunc = hasThis(sc);
7980                     if (memberFunc && haveSameThis(memberFunc, f))
7981                     {
7982                         /* Should probably supply 'this' after overload resolution,
7983                          * not before.
7984                          */
7985                         Expression ethis = new ThisExp(exp.loc);
7986                         Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7987                         e = e.expressionSemantic(sc);
7988                         result = e;
7989                         return;
7990                     }
7991                     if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
7992                     {
7993                         sc.setUnsafe(false, exp.loc,
7994                             "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7995                             f, sc.func);
7996                     }
7997                 }
7998             }
7999         }
8000         else if (exp.e1.op == EXP.index)
8001         {
8002             /* For:
8003              *   int[3] a;
8004              *   &a[i]
8005              * check 'a' the same as for a regular variable
8006              */
8007             if (VarDeclaration v = expToVariable(exp.e1))
8008             {
8009                 exp.e1.checkPurity(sc, v);
8010             }
8011         }
8012         else if (wasCond)
8013         {
8014             /* a ? b : c was transformed to *(a ? &b : &c), but we still
8015              * need to do safety checks
8016              */
8017             assert(exp.e1.op == EXP.star);
8018             PtrExp pe = cast(PtrExp)exp.e1;
8019             assert(pe.e1.op == EXP.question);
8020             CondExp ce = cast(CondExp)pe.e1;
8021             assert(ce.e1.op == EXP.address);
8022             assert(ce.e2.op == EXP.address);
8023 
8024             // Re-run semantic on the address expressions only
8025             ce.e1.type = null;
8026             ce.e1 = ce.e1.expressionSemantic(sc);
8027             ce.e2.type = null;
8028             ce.e2 = ce.e2.expressionSemantic(sc);
8029         }
8030         result = exp.optimize(WANTvalue);
8031     }
8032 
8033     override void visit(PtrExp exp)
8034     {
8035         static if (LOGSEMANTIC)
8036         {
8037             printf("PtrExp::semantic('%s')\n", exp.toChars());
8038         }
8039         if (exp.type)
8040         {
8041             result = exp;
8042             return;
8043         }
8044 
8045         Expression e = exp.op_overload(sc);
8046         if (e)
8047         {
8048             result = e;
8049             return;
8050         }
8051 
8052         exp.e1 = exp.e1.arrayFuncConv(sc);
8053 
8054         Type tb = exp.e1.type.toBasetype();
8055         switch (tb.ty)
8056         {
8057         case Tpointer:
8058             exp.type = (cast(TypePointer)tb).next;
8059             break;
8060 
8061         case Tsarray:
8062         case Tarray:
8063             if (isNonAssignmentArrayOp(exp.e1))
8064                 goto default;
8065             error(exp.loc, "using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
8066             exp.type = (cast(TypeArray)tb).next;
8067             exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
8068             break;
8069 
8070         case Terror:
8071             return setError();
8072 
8073         case Tnull:
8074             exp.type = Type.tnoreturn;  // typeof(*null) is bottom type
8075             break;
8076 
8077         default:
8078             error(exp.loc, "can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
8079             goto case Terror;
8080         }
8081 
8082         if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
8083         {
8084             // https://issues.dlang.org/show_bug.cgi?id=23752
8085             // `&*((void*)(0))` is allowed in C
8086             result = exp;
8087             return;
8088         }
8089 
8090         if (exp.checkValue())
8091             return setError();
8092 
8093         result = exp;
8094     }
8095 
8096     override void visit(NegExp exp)
8097     {
8098         static if (LOGSEMANTIC)
8099         {
8100             printf("NegExp::semantic('%s')\n", exp.toChars());
8101         }
8102         if (exp.type)
8103         {
8104             result = exp;
8105             return;
8106         }
8107 
8108         Expression e = exp.op_overload(sc);
8109         if (e)
8110         {
8111             result = e;
8112             return;
8113         }
8114 
8115         fix16997(sc, exp);
8116         exp.type = exp.e1.type;
8117         Type tb = exp.type.toBasetype();
8118         if (tb.ty == Tarray || tb.ty == Tsarray)
8119         {
8120             if (!isArrayOpValid(exp.e1))
8121             {
8122                 result = arrayOpInvalidError(exp);
8123                 return;
8124             }
8125             result = exp;
8126             return;
8127         }
8128         if (!target.isVectorOpSupported(tb, exp.op))
8129         {
8130             result = exp.incompatibleTypes();
8131             return;
8132         }
8133         if (exp.e1.checkNoBool())
8134             return setError();
8135         if (exp.e1.checkArithmetic(exp.op) ||
8136             exp.e1.checkSharedAccess(sc))
8137             return setError();
8138 
8139         result = exp;
8140     }
8141 
8142     override void visit(UAddExp exp)
8143     {
8144         static if (LOGSEMANTIC)
8145         {
8146             printf("UAddExp::semantic('%s')\n", exp.toChars());
8147         }
8148         assert(!exp.type);
8149 
8150         Expression e = exp.op_overload(sc);
8151         if (e)
8152         {
8153             result = e;
8154             return;
8155         }
8156 
8157         fix16997(sc, exp);
8158         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
8159         {
8160             result = exp.incompatibleTypes();
8161             return;
8162         }
8163         if (exp.e1.checkNoBool())
8164             return setError();
8165         if (exp.e1.checkArithmetic(exp.op))
8166             return setError();
8167         if (exp.e1.checkSharedAccess(sc))
8168             return setError();
8169 
8170         result = exp.e1;
8171     }
8172 
8173     override void visit(ComExp exp)
8174     {
8175         if (exp.type)
8176         {
8177             result = exp;
8178             return;
8179         }
8180 
8181         Expression e = exp.op_overload(sc);
8182         if (e)
8183         {
8184             result = e;
8185             return;
8186         }
8187 
8188         fix16997(sc, exp);
8189         exp.type = exp.e1.type;
8190         Type tb = exp.type.toBasetype();
8191         if (tb.ty == Tarray || tb.ty == Tsarray)
8192         {
8193             if (!isArrayOpValid(exp.e1))
8194             {
8195                 result = arrayOpInvalidError(exp);
8196                 return;
8197             }
8198             result = exp;
8199             return;
8200         }
8201         if (!target.isVectorOpSupported(tb, exp.op))
8202         {
8203             result = exp.incompatibleTypes();
8204             return;
8205         }
8206         if (exp.e1.checkNoBool())
8207             return setError();
8208         if (exp.e1.checkIntegral() ||
8209             exp.e1.checkSharedAccess(sc))
8210             return setError();
8211 
8212         result = exp;
8213     }
8214 
8215     override void visit(NotExp e)
8216     {
8217         if (e.type)
8218         {
8219             result = e;
8220             return;
8221         }
8222 
8223         e.setNoderefOperand();
8224 
8225         // Note there is no operator overload
8226         if (Expression ex = unaSemantic(e, sc))
8227         {
8228             result = ex;
8229             return;
8230         }
8231 
8232         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8233         if (e.e1.op == EXP.type)
8234             e.e1 = resolveAliasThis(sc, e.e1);
8235 
8236         e.e1 = resolveProperties(sc, e.e1);
8237         e.e1 = e.e1.toBoolean(sc);
8238         if (e.e1.type == Type.terror)
8239         {
8240             result = e.e1;
8241             return;
8242         }
8243 
8244         if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
8245         {
8246             result = e.incompatibleTypes();
8247         }
8248         // https://issues.dlang.org/show_bug.cgi?id=13910
8249         // Today NotExp can take an array as its operand.
8250         if (checkNonAssignmentArrayOp(e.e1))
8251             return setError();
8252 
8253         e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
8254         result = e;
8255     }
8256 
8257     override void visit(DeleteExp exp)
8258     {
8259         // @@@DEPRECATED_2.109@@@
8260         // 1. Deprecated since 2.079
8261         // 2. Error since 2.099
8262         // 3. Removal of keyword, "delete" can be used for other identities
8263         if (!exp.isRAII)
8264         {
8265             error(exp.loc, "the `delete` keyword is obsolete");
8266             errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
8267             return setError();
8268         }
8269 
8270         Expression e = exp;
8271 
8272         if (Expression ex = unaSemantic(exp, sc))
8273         {
8274             result = ex;
8275             return;
8276         }
8277         exp.e1 = resolveProperties(sc, exp.e1);
8278         exp.e1 = exp.e1.modifiableLvalue(sc, null);
8279         if (exp.e1.op == EXP.error)
8280         {
8281             result = exp.e1;
8282             return;
8283         }
8284         exp.type = Type.tvoid;
8285 
8286         Type tb = exp.e1.type.toBasetype();
8287 
8288         /* Now that `delete` in user code is an error, we only get here when
8289          * `isRAII` has been set to true for the deletion of a `scope class`.  */
8290         if (tb.ty != Tclass)
8291         {
8292             error(exp.loc, "cannot delete type `%s`", exp.e1.type.toChars());
8293             return setError();
8294         }
8295 
8296         ClassDeclaration cd = (cast(TypeClass)tb).sym;
8297         if (cd.isCOMinterface())
8298         {
8299             /* Because COM classes are deleted by IUnknown.Release()
8300              */
8301             error(exp.loc, "cannot `delete` instance of COM interface `%s`", cd.toChars());
8302             return setError();
8303         }
8304 
8305         bool err = false;
8306         if (cd.dtor)
8307         {
8308             err |= !cd.dtor.functionSemantic();
8309             err |= exp.checkPurity(sc, cd.dtor);
8310             err |= exp.checkSafety(sc, cd.dtor);
8311             err |= exp.checkNogc(sc, cd.dtor);
8312         }
8313         if (err)
8314             return setError();
8315 
8316         result = e;
8317     }
8318 
8319     override void visit(CastExp exp)
8320     {
8321         static if (LOGSEMANTIC)
8322         {
8323             printf("CastExp::semantic('%s')\n", exp.toChars());
8324         }
8325         //static int x; assert(++x < 10);
8326         if (exp.type)
8327         {
8328             result = exp;
8329             return;
8330         }
8331 
8332         if ((sc && sc.flags & SCOPE.Cfile) &&
8333             exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
8334             (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
8335              exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
8336         {
8337             /* Ambiguous cases arise from CParser if type-name is just an identifier.
8338              *   ( identifier ) cast-expression
8339              *   ( identifier [expression]) cast-expression
8340              * If we determine that `identifier` is a variable, and cast-expression
8341              * is one of the unary operators (& * + -), then rewrite this cast
8342              * as a binary expression.
8343              */
8344             Loc loc = exp.loc;
8345             Type t;
8346             Expression e;
8347             Dsymbol s;
8348             exp.to.resolve(loc, sc, e, t, s);
8349             if (e !is null)
8350             {
8351                 if (auto ex = exp.e1.isAddrExp())       // (ident) &exp -> (ident & exp)
8352                     result = new AndExp(loc, e, ex.e1);
8353                 else if (auto ex = exp.e1.isPtrExp())   // (ident) *exp -> (ident * exp)
8354                     result = new MulExp(loc, e, ex.e1);
8355                 else if (auto ex = exp.e1.isUAddExp())  // (ident) +exp -> (ident + exp)
8356                     result = new AddExp(loc, e, ex.e1);
8357                 else if (auto ex = exp.e1.isNegExp())   // (ident) -exp -> (ident - exp)
8358                     result = new MinExp(loc, e, ex.e1);
8359 
8360                 assert(result);
8361                 result = result.expressionSemantic(sc);
8362                 return;
8363             }
8364         }
8365 
8366         if (exp.to)
8367         {
8368             exp.to = exp.to.typeSemantic(exp.loc, sc);
8369             if (exp.to == Type.terror)
8370                 return setError();
8371 
8372             if (!exp.to.hasPointers())
8373                 exp.setNoderefOperand();
8374 
8375             // When e1 is a template lambda, this cast may instantiate it with
8376             // the type 'to'.
8377             exp.e1 = inferType(exp.e1, exp.to);
8378         }
8379 
8380         if (auto e = unaSemantic(exp, sc))
8381         {
8382             result = e;
8383             return;
8384         }
8385 
8386         if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
8387             exp.e1 = exp.e1.arrayFuncConv(sc);
8388 
8389         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
8390         if (exp.e1.op == EXP.type)
8391             exp.e1 = resolveAliasThis(sc, exp.e1);
8392 
8393         auto e1x = resolveProperties(sc, exp.e1);
8394         if (e1x.op == EXP.error)
8395         {
8396             result = e1x;
8397             return;
8398         }
8399         if (e1x.checkType())
8400             return setError();
8401         exp.e1 = e1x;
8402 
8403         if (!exp.e1.type)
8404         {
8405             error(exp.loc, "cannot cast `%s`", exp.e1.toChars());
8406             return setError();
8407         }
8408 
8409         // https://issues.dlang.org/show_bug.cgi?id=19954
8410         if (exp.e1.type.ty == Ttuple)
8411         {
8412             if (exp.to)
8413             {
8414                 if (TypeTuple tt = exp.to.isTypeTuple())
8415                 {
8416                     if (exp.e1.type.implicitConvTo(tt))
8417                     {
8418                         result = exp.e1.castTo(sc, tt);
8419                         return;
8420                     }
8421                 }
8422             }
8423             TupleExp te = exp.e1.isTupleExp();
8424             if (te.exps.length == 1)
8425                 exp.e1 = (*te.exps)[0];
8426         }
8427 
8428         // only allow S(x) rewrite if cast specified S explicitly.
8429         // See https://issues.dlang.org/show_bug.cgi?id=18545
8430         const bool allowImplicitConstruction = exp.to !is null;
8431 
8432         if (!exp.to) // Handle cast(const) and cast(immutable), etc.
8433         {
8434             exp.to = exp.e1.type.castMod(exp.mod);
8435             exp.to = exp.to.typeSemantic(exp.loc, sc);
8436 
8437             if (exp.to == Type.terror)
8438                 return setError();
8439         }
8440 
8441         if (exp.to.ty == Ttuple)
8442         {
8443             error(exp.loc, "cannot cast `%s` of type `%s` to type sequence `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
8444             return setError();
8445         }
8446 
8447         // cast(void) is used to mark e1 as unused, so it is safe
8448         if (exp.to.ty == Tvoid)
8449         {
8450             exp.type = exp.to;
8451             result = exp;
8452             return;
8453         }
8454 
8455         if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
8456         {
8457             if (Expression e = exp.op_overload(sc))
8458             {
8459                 result = e.implicitCastTo(sc, exp.to);
8460                 return;
8461             }
8462         }
8463 
8464         Type t1b = exp.e1.type.toBasetype();
8465         Type tob = exp.to.toBasetype();
8466 
8467         if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
8468         {
8469             /* Look to replace:
8470              *  cast(S)t
8471              * with:
8472              *  S(t)
8473              */
8474 
8475             // Rewrite as to.call(e1)
8476             Expression e = new TypeExp(exp.loc, exp.to);
8477             e = new CallExp(exp.loc, e, exp.e1);
8478             e = e.trySemantic(sc);
8479             if (e)
8480             {
8481                 result = e;
8482                 return;
8483             }
8484         }
8485 
8486         if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
8487         {
8488             if (checkNonAssignmentArrayOp(exp.e1))
8489                 return setError();
8490         }
8491 
8492         // Look for casting to a vector type
8493         if (tob.ty == Tvector && t1b.ty != Tvector)
8494         {
8495             result = new VectorExp(exp.loc, exp.e1, exp.to);
8496             result = result.expressionSemantic(sc);
8497             return;
8498         }
8499 
8500         Expression ex = exp.e1.castTo(sc, exp.to);
8501         if (ex.op == EXP.error)
8502         {
8503             result = ex;
8504             return;
8505         }
8506 
8507         // Check for unsafe casts
8508         if (!isSafeCast(ex, t1b, tob))
8509         {
8510             if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
8511             {
8512                 return setError();
8513             }
8514         }
8515 
8516         // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
8517         // to handle certain casts.  Those casts which `object.__ArrayCast` does not support are filtered out.
8518         // See `e2ir.toElemCast` for other types of casts.  If `object.__ArrayCast` is improved to support more
8519         // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
8520         if (tob.ty == Tarray)
8521         {
8522             // https://issues.dlang.org/show_bug.cgi?id=19840
8523             if (auto ad = isAggregate(t1b))
8524             {
8525                 if (ad.aliasthis)
8526                 {
8527                     Expression e = resolveAliasThis(sc, exp.e1);
8528                     e = new CastExp(exp.loc, e, exp.to);
8529                     result = e.expressionSemantic(sc);
8530                     return;
8531                 }
8532             }
8533 
8534             if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
8535             {
8536                 auto tFrom = t1b.nextOf();
8537                 auto tTo = tob.nextOf();
8538 
8539                 // https://issues.dlang.org/show_bug.cgi?id=20130
8540                 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
8541                 {
8542                     const uint fromSize = cast(uint)tFrom.size();
8543                     const uint toSize = cast(uint)tTo.size();
8544                     if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
8545                         return setError();
8546 
8547                     // If array element sizes do not match, we must adjust the dimensions
8548                     if (fromSize != toSize)
8549                     {
8550                         if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
8551                             return setError();
8552 
8553                         // A runtime check is needed in case arrays don't line up.  That check should
8554                         // be done in the implementation of `object.__ArrayCast`
8555                         if (toSize == 0 || (fromSize % toSize) != 0)
8556                         {
8557                             // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
8558 
8559                             // fully qualify as `object.__ArrayCast`
8560                             Expression id = new IdentifierExp(exp.loc, Id.empty);
8561                             auto dotid = new DotIdExp(exp.loc, id, Id.object);
8562 
8563                             auto tiargs = new Objects();
8564                             tiargs.push(tFrom);
8565                             tiargs.push(tTo);
8566                             auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
8567 
8568                             auto arguments = new Expressions();
8569                             arguments.push(exp.e1);
8570                             Expression ce = new CallExp(exp.loc, dt, arguments);
8571 
8572                             result = expressionSemantic(ce, sc);
8573                             return;
8574                         }
8575                     }
8576                 }
8577             }
8578         }
8579 
8580         if (sc && sc.flags & SCOPE.Cfile)
8581         {
8582             /* C11 6.5.4-5: A cast does not yield an lvalue.
8583              * So ensure that castTo does not strip away the cast so that this
8584              * can be enforced in other semantic visitor methods.
8585              */
8586             if (!ex.isCastExp())
8587             {
8588                 ex = new CastExp(exp.loc, ex, exp.to);
8589                 ex.type = exp.to;
8590             }
8591         }
8592         result = ex;
8593     }
8594 
8595     override void visit(VectorExp exp)
8596     {
8597         static if (LOGSEMANTIC)
8598         {
8599             printf("VectorExp::semantic('%s')\n", exp.toChars());
8600         }
8601         if (exp.type)
8602         {
8603             result = exp;
8604             return;
8605         }
8606 
8607         exp.e1 = exp.e1.expressionSemantic(sc);
8608         exp.type = exp.to.typeSemantic(exp.loc, sc);
8609         if (exp.e1.op == EXP.error || exp.type.ty == Terror)
8610         {
8611             result = exp.e1;
8612             return;
8613         }
8614 
8615         Type tb = exp.type.toBasetype();
8616         assert(tb.ty == Tvector);
8617         TypeVector tv = cast(TypeVector)tb;
8618         Type te = tv.elementType();
8619         exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
8620 
8621         bool checkElem(Expression elem)
8622         {
8623             if (elem.isConst() == 1)
8624                 return false;
8625 
8626              error(exp.loc, "constant expression expected, not `%s`", elem.toChars());
8627              return true;
8628         }
8629 
8630         exp.e1 = exp.e1.optimize(WANTvalue);
8631         bool res;
8632         if (exp.e1.op == EXP.arrayLiteral)
8633         {
8634             foreach (i; 0 .. exp.dim)
8635             {
8636                 // Do not stop on first error - check all AST nodes even if error found
8637                 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
8638             }
8639         }
8640         else if (exp.e1.type.ty == Tvoid)
8641             checkElem(exp.e1);
8642 
8643         result = res ? ErrorExp.get() : exp;
8644     }
8645 
8646     override void visit(VectorArrayExp e)
8647     {
8648         static if (LOGSEMANTIC)
8649         {
8650             printf("VectorArrayExp::semantic('%s')\n", e.toChars());
8651         }
8652         if (!e.type)
8653         {
8654             unaSemantic(e, sc);
8655             e.e1 = resolveProperties(sc, e.e1);
8656 
8657             if (e.e1.op == EXP.error)
8658             {
8659                 result = e.e1;
8660                 return;
8661             }
8662             assert(e.e1.type.ty == Tvector);
8663             e.type = e.e1.type.isTypeVector().basetype;
8664         }
8665         result = e;
8666     }
8667 
8668     override void visit(SliceExp exp)
8669     {
8670         static if (LOGSEMANTIC)
8671         {
8672             printf("SliceExp::semantic('%s')\n", exp.toChars());
8673         }
8674         if (exp.type)
8675         {
8676             result = exp;
8677             return;
8678         }
8679 
8680         // operator overloading should be handled in ArrayExp already.
8681         if (Expression ex = unaSemantic(exp, sc))
8682         {
8683             result = ex;
8684             return;
8685         }
8686         exp.e1 = resolveProperties(sc, exp.e1);
8687         if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8688         {
8689             if (exp.lwr || exp.upr)
8690             {
8691                 error(exp.loc, "cannot slice type `%s`", exp.e1.toChars());
8692                 return setError();
8693             }
8694             Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
8695             result = e.expressionSemantic(sc);
8696             return;
8697         }
8698         if (!exp.lwr && !exp.upr)
8699         {
8700             if (exp.e1.op == EXP.arrayLiteral)
8701             {
8702                 // Convert [a,b,c][] to [a,b,c]
8703                 Type t1b = exp.e1.type.toBasetype();
8704                 Expression e = exp.e1;
8705                 if (t1b.ty == Tsarray)
8706                 {
8707                     e = e.copy();
8708                     e.type = t1b.nextOf().arrayOf();
8709                 }
8710                 result = e;
8711                 return;
8712             }
8713             if (exp.e1.op == EXP.slice)
8714             {
8715                 // Convert e[][] to e[]
8716                 SliceExp se = cast(SliceExp)exp.e1;
8717                 if (!se.lwr && !se.upr)
8718                 {
8719                     result = se;
8720                     return;
8721                 }
8722             }
8723             if (isArrayOpOperand(exp.e1))
8724             {
8725                 // Convert (a[]+b[])[] to a[]+b[]
8726                 result = exp.e1;
8727                 return;
8728             }
8729         }
8730         if (exp.e1.op == EXP.error)
8731         {
8732             result = exp.e1;
8733             return;
8734         }
8735         if (exp.e1.type.ty == Terror)
8736             return setError();
8737 
8738         Type t1b = exp.e1.type.toBasetype();
8739         if (auto tp = t1b.isTypePointer())
8740         {
8741             if (t1b.isPtrToFunction())
8742             {
8743                 error(exp.loc, "cannot slice function pointer `%s`", exp.e1.toChars());
8744                 return setError();
8745             }
8746             if (!exp.lwr || !exp.upr)
8747             {
8748                 error(exp.loc, "upper and lower bounds are needed to slice a pointer");
8749                 if (auto ad = isAggregate(tp.next.toBasetype()))
8750                 {
8751                     auto s = search_function(ad, Id.index);
8752                     if (!s) s = search_function(ad, Id.slice);
8753                     if (s)
8754                     {
8755                         auto fd = s.isFuncDeclaration();
8756                         if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
8757                         {
8758                             errorSupplemental(exp.loc,
8759                                 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
8760                                 exp.e1.toChars(),
8761                                 s.ident.toChars(),
8762                                 exp.e1.toChars()
8763                             );
8764                         }
8765 
8766                     }
8767                 }
8768 
8769                 return setError();
8770             }
8771             if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
8772                 return setError();
8773         }
8774         else if (t1b.ty == Tarray)
8775         {
8776         }
8777         else if (t1b.ty == Tsarray)
8778         {
8779         }
8780         else if (t1b.ty == Ttuple)
8781         {
8782             if (!exp.lwr && !exp.upr)
8783             {
8784                 result = exp.e1;
8785                 return;
8786             }
8787             if (!exp.lwr || !exp.upr)
8788             {
8789                 error(exp.loc, "need upper and lower bound to slice a sequence");
8790                 return setError();
8791             }
8792         }
8793         else if (t1b.ty == Tvector && exp.e1.isLvalue())
8794         {
8795             // Convert e1 to corresponding static array
8796             TypeVector tv1 = cast(TypeVector)t1b;
8797             t1b = tv1.basetype;
8798             t1b = t1b.castMod(tv1.mod);
8799             exp.e1.type = t1b;
8800         }
8801         else
8802         {
8803             error(exp.loc, "`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
8804             return setError();
8805         }
8806 
8807         /* Run semantic on lwr and upr.
8808          */
8809         Scope* scx = sc;
8810         if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8811         {
8812             // Create scope for 'length' variable
8813             ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8814             sym.parent = sc.scopesym;
8815             sc = sc.push(sym);
8816         }
8817         if (exp.lwr)
8818         {
8819             if (t1b.ty == Ttuple)
8820                 sc = sc.startCTFE();
8821             exp.lwr = exp.lwr.expressionSemantic(sc);
8822             exp.lwr = resolveProperties(sc, exp.lwr);
8823             if (t1b.ty == Ttuple)
8824                 sc = sc.endCTFE();
8825             exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
8826         }
8827         if (exp.upr)
8828         {
8829             if (t1b.ty == Ttuple)
8830                 sc = sc.startCTFE();
8831             exp.upr = exp.upr.expressionSemantic(sc);
8832             exp.upr = resolveProperties(sc, exp.upr);
8833             if (t1b.ty == Ttuple)
8834                 sc = sc.endCTFE();
8835             exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
8836         }
8837         if (sc != scx)
8838             sc = sc.pop();
8839         if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
8840             return setError();
8841 
8842         if (t1b.ty == Ttuple)
8843         {
8844             exp.lwr = exp.lwr.ctfeInterpret();
8845             exp.upr = exp.upr.ctfeInterpret();
8846             uinteger_t i1 = exp.lwr.toUInteger();
8847             uinteger_t i2 = exp.upr.toUInteger();
8848 
8849             TupleExp te;
8850             TypeTuple tup;
8851             size_t length;
8852             if (exp.e1.op == EXP.tuple) // slicing an expression tuple
8853             {
8854                 te = cast(TupleExp)exp.e1;
8855                 tup = null;
8856                 length = te.exps.length;
8857             }
8858             else if (exp.e1.op == EXP.type) // slicing a type tuple
8859             {
8860                 te = null;
8861                 tup = cast(TypeTuple)t1b;
8862                 length = Parameter.dim(tup.arguments);
8863             }
8864             else
8865                 assert(0);
8866 
8867             if (i2 < i1 || length < i2)
8868             {
8869                 error(exp.loc, "string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8870                 return setError();
8871             }
8872 
8873             size_t j1 = cast(size_t)i1;
8874             size_t j2 = cast(size_t)i2;
8875             Expression e;
8876             if (exp.e1.op == EXP.tuple)
8877             {
8878                 auto exps = new Expressions(j2 - j1);
8879                 for (size_t i = 0; i < j2 - j1; i++)
8880                 {
8881                     (*exps)[i] = (*te.exps)[j1 + i];
8882                 }
8883                 e = new TupleExp(exp.loc, te.e0, exps);
8884             }
8885             else
8886             {
8887                 auto args = new Parameters();
8888                 args.reserve(j2 - j1);
8889                 for (size_t i = j1; i < j2; i++)
8890                 {
8891                     Parameter arg = Parameter.getNth(tup.arguments, i);
8892                     args.push(arg);
8893                 }
8894                 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8895             }
8896             e = e.expressionSemantic(sc);
8897             result = e;
8898             return;
8899         }
8900 
8901         exp.type = t1b.nextOf().arrayOf();
8902         // Allow typedef[] -> typedef[]
8903         if (exp.type.equals(t1b))
8904             exp.type = exp.e1.type;
8905 
8906         // We might know $ now
8907         setLengthVarIfKnown(exp.lengthVar, t1b);
8908 
8909         if (exp.lwr && exp.upr)
8910         {
8911             exp.lwr = exp.lwr.optimize(WANTvalue);
8912             exp.upr = exp.upr.optimize(WANTvalue);
8913 
8914             IntRange lwrRange = getIntRange(exp.lwr);
8915             IntRange uprRange = getIntRange(exp.upr);
8916 
8917             if (t1b.ty == Tsarray || t1b.ty == Tarray)
8918             {
8919                 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8920                 el = el.expressionSemantic(sc);
8921                 el = el.optimize(WANTvalue);
8922                 if (el.op == EXP.int64)
8923                 {
8924                     // Array length is known at compile-time. Upper is in bounds if it fits length.
8925                     dinteger_t length = el.toInteger();
8926                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8927                     exp.upperIsInBounds = bounds.contains(uprRange);
8928                 }
8929                 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
8930                 {
8931                     // Upper slice expression is '0'. Value is always in bounds.
8932                     exp.upperIsInBounds = true;
8933                 }
8934                 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
8935                 {
8936                     // Upper slice expression is '$'. Value is always in bounds.
8937                     exp.upperIsInBounds = true;
8938                 }
8939             }
8940             else if (t1b.ty == Tpointer)
8941             {
8942                 exp.upperIsInBounds = true;
8943             }
8944             else
8945                 assert(0);
8946 
8947             exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8948 
8949             //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8950         }
8951 
8952         result = exp;
8953     }
8954 
8955     override void visit(ArrayLengthExp e)
8956     {
8957         static if (LOGSEMANTIC)
8958         {
8959             printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8960         }
8961         if (e.type)
8962         {
8963             result = e;
8964             return;
8965         }
8966 
8967         if (Expression ex = unaSemantic(e, sc))
8968         {
8969             result = ex;
8970             return;
8971         }
8972         e.e1 = resolveProperties(sc, e.e1);
8973 
8974         e.type = Type.tsize_t;
8975         result = e;
8976     }
8977 
8978     override void visit(ArrayExp exp)
8979     {
8980         static if (LOGSEMANTIC)
8981         {
8982             printf("ArrayExp::semantic('%s')\n", exp.toChars());
8983         }
8984         assert(!exp.type);
8985 
8986         if (sc.flags & SCOPE.Cfile)
8987         {
8988             /* See if need to rewrite the AST because of cast/call ambiguity
8989              */
8990             if (auto e = castCallAmbiguity(exp, sc))
8991             {
8992                 result = expressionSemantic(e, sc);
8993                 return;
8994             }
8995         }
8996 
8997         result = exp.carraySemantic(sc);  // C semantics
8998         if (result)
8999             return;
9000 
9001         Expression e = exp.op_overload(sc);
9002         if (e)
9003         {
9004             result = e;
9005             return;
9006         }
9007 
9008         if (isAggregate(exp.e1.type))
9009             error(exp.loc, "no `[]` operator overload for type `%s`", exp.e1.type.toChars());
9010         else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9011             error(exp.loc, "static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
9012         else if (isIndexableNonAggregate(exp.e1.type))
9013             error(exp.loc, "only one index allowed to index `%s`", exp.e1.type.toChars());
9014         else
9015             error(exp.loc, "cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
9016 
9017         result = ErrorExp.get();
9018     }
9019 
9020     override void visit(DotExp exp)
9021     {
9022         static if (LOGSEMANTIC)
9023         {
9024             printf("DotExp::semantic('%s')\n", exp.toChars());
9025             if (exp.type)
9026                 printf("\ttype = %s\n", exp.type.toChars());
9027         }
9028         exp.e1 = exp.e1.expressionSemantic(sc);
9029         exp.e2 = exp.e2.expressionSemantic(sc);
9030 
9031         if (exp.e1.op == EXP.type)
9032         {
9033             result = exp.e2;
9034             return;
9035         }
9036         if (exp.e2.op == EXP.type)
9037         {
9038             result = exp.e2;
9039             return;
9040         }
9041         if (auto te = exp.e2.isTemplateExp())
9042         {
9043             Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
9044             result = e.expressionSemantic(sc);
9045             return;
9046         }
9047         if (!exp.type)
9048             exp.type = exp.e2.type;
9049         result = exp;
9050     }
9051 
9052     override void visit(CommaExp e)
9053     {
9054         //printf("Semantic.CommaExp() %s\n", e.toChars());
9055         if (e.type)
9056         {
9057             result = e;
9058             return;
9059         }
9060 
9061         // Allow `((a,b),(x,y))`
9062         if (e.allowCommaExp)
9063         {
9064             CommaExp.allow(e.e1);
9065             CommaExp.allow(e.e2);
9066         }
9067 
9068         if (Expression ex = binSemanticProp(e, sc))
9069         {
9070             result = ex;
9071             return;
9072         }
9073         e.e1 = e.e1.addDtorHook(sc);
9074 
9075         if (checkNonAssignmentArrayOp(e.e1))
9076             return setError();
9077 
9078         // Comma expressions trigger this conversion
9079         e.e2 = e.e2.arrayFuncConv(sc);
9080 
9081         e.type = e.e2.type;
9082         result = e;
9083 
9084         if (sc.flags & SCOPE.Cfile)
9085             return;
9086 
9087         if (e.type is Type.tvoid)
9088         {
9089             checkMustUse(e.e1, sc);
9090             discardValue(e.e1);
9091         }
9092         else if (!e.allowCommaExp && !e.isGenerated)
9093             error(e.loc, "using the result of a comma expression is not allowed");
9094     }
9095 
9096     override void visit(IntervalExp e)
9097     {
9098         static if (LOGSEMANTIC)
9099         {
9100             printf("IntervalExp::semantic('%s')\n", e.toChars());
9101         }
9102         if (e.type)
9103         {
9104             result = e;
9105             return;
9106         }
9107 
9108         Expression le = e.lwr;
9109         le = le.expressionSemantic(sc);
9110         le = resolveProperties(sc, le);
9111 
9112         Expression ue = e.upr;
9113         ue = ue.expressionSemantic(sc);
9114         ue = resolveProperties(sc, ue);
9115 
9116         if (le.op == EXP.error)
9117         {
9118             result = le;
9119             return;
9120         }
9121         if (ue.op == EXP.error)
9122         {
9123             result = ue;
9124             return;
9125         }
9126 
9127         e.lwr = le;
9128         e.upr = ue;
9129 
9130         e.type = Type.tvoid;
9131         result = e;
9132     }
9133 
9134     override void visit(DelegatePtrExp e)
9135     {
9136         static if (LOGSEMANTIC)
9137         {
9138             printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
9139         }
9140         if (!e.type)
9141         {
9142             unaSemantic(e, sc);
9143             e.e1 = resolveProperties(sc, e.e1);
9144 
9145             if (e.e1.op == EXP.error)
9146             {
9147                 result = e.e1;
9148                 return;
9149             }
9150             e.type = Type.tvoidptr;
9151         }
9152         result = e;
9153     }
9154 
9155     override void visit(DelegateFuncptrExp e)
9156     {
9157         static if (LOGSEMANTIC)
9158         {
9159             printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
9160         }
9161         if (!e.type)
9162         {
9163             unaSemantic(e, sc);
9164             e.e1 = resolveProperties(sc, e.e1);
9165             if (e.e1.op == EXP.error)
9166             {
9167                 result = e.e1;
9168                 return;
9169             }
9170             e.type = e.e1.type.nextOf().pointerTo();
9171         }
9172         result = e;
9173     }
9174 
9175     override void visit(IndexExp exp)
9176     {
9177         static if (LOGSEMANTIC)
9178         {
9179             printf("IndexExp::semantic('%s')\n", exp.toChars());
9180         }
9181         if (exp.type)
9182         {
9183             result = exp;
9184             return;
9185         }
9186 
9187         // operator overloading should be handled in ArrayExp already.
9188         if (!exp.e1.type)
9189             exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
9190         assert(exp.e1.type); // semantic() should already be run on it
9191         if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
9192         {
9193             exp.e2 = exp.e2.expressionSemantic(sc);
9194             exp.e2 = resolveProperties(sc, exp.e2);
9195             Type nt;
9196             if (exp.e2.op == EXP.type)
9197                 nt = new TypeAArray(exp.e1.type, exp.e2.type);
9198             else
9199                 nt = new TypeSArray(exp.e1.type, exp.e2);
9200             Expression e = new TypeExp(exp.loc, nt);
9201             result = e.expressionSemantic(sc);
9202             return;
9203         }
9204         if (exp.e1.op == EXP.error)
9205         {
9206             result = exp.e1;
9207             return;
9208         }
9209         if (exp.e1.type.ty == Terror)
9210             return setError();
9211 
9212         // Note that unlike C we do not implement the int[ptr]
9213 
9214         Type t1b = exp.e1.type.toBasetype();
9215 
9216         if (TypeVector tv1 = t1b.isTypeVector())
9217         {
9218             // Convert e1 to corresponding static array
9219             t1b = tv1.basetype;
9220             t1b = t1b.castMod(tv1.mod);
9221             exp.e1 = exp.e1.castTo(sc, t1b);
9222         }
9223         if (t1b.ty == Tsarray || t1b.ty == Tarray)
9224         {
9225             if (!checkAddressable(exp, sc))
9226                 return setError();
9227         }
9228 
9229         /* Run semantic on e2
9230          */
9231         Scope* scx = sc;
9232         if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
9233         {
9234             // Create scope for 'length' variable
9235             ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
9236             sym.parent = sc.scopesym;
9237             sc = sc.push(sym);
9238         }
9239         if (t1b.ty == Ttuple)
9240             sc = sc.startCTFE();
9241         exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
9242         exp.e2 = resolveProperties(sc, exp.e2);
9243         if (t1b.ty == Ttuple)
9244             sc = sc.endCTFE();
9245         if (exp.e2.op == EXP.tuple)
9246         {
9247             TupleExp te = cast(TupleExp)exp.e2;
9248             if (te.exps && te.exps.length == 1)
9249                 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
9250         }
9251         if (sc != scx)
9252             sc = sc.pop();
9253         if (exp.e2.type == Type.terror)
9254             return setError();
9255 
9256         if (checkNonAssignmentArrayOp(exp.e1))
9257             return setError();
9258 
9259         switch (t1b.ty)
9260         {
9261         case Tpointer:
9262             if (t1b.isPtrToFunction())
9263             {
9264                 error(exp.loc, "cannot index function pointer `%s`", exp.e1.toChars());
9265                 return setError();
9266             }
9267             exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9268             if (exp.e2.type == Type.terror)
9269                 return setError();
9270             exp.e2 = exp.e2.optimize(WANTvalue);
9271             if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
9272             {
9273             }
9274             else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
9275             {
9276                 return setError();
9277             }
9278             exp.type = (cast(TypeNext)t1b).next;
9279             break;
9280 
9281         case Tarray:
9282             exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9283             if (exp.e2.type == Type.terror)
9284                 return setError();
9285             exp.type = (cast(TypeNext)t1b).next;
9286             break;
9287 
9288         case Tsarray:
9289             {
9290                 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9291                 if (exp.e2.type == Type.terror)
9292                     return setError();
9293                 exp.type = t1b.nextOf();
9294                 break;
9295             }
9296         case Taarray:
9297             {
9298                 TypeAArray taa = cast(TypeAArray)t1b;
9299                 /* We can skip the implicit conversion if they differ only by
9300                  * constness
9301                  * https://issues.dlang.org/show_bug.cgi?id=2684
9302                  * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
9303                  */
9304                 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
9305                 {
9306                     exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
9307                     if (exp.e2.type == Type.terror)
9308                         return setError();
9309                 }
9310 
9311                 semanticTypeInfo(sc, taa);
9312                 checkNewEscape(sc, exp.e2, false);
9313 
9314                 exp.type = taa.next;
9315                 break;
9316             }
9317         case Ttuple:
9318             {
9319                 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
9320                 if (exp.e2.type == Type.terror)
9321                     return setError();
9322 
9323                 exp.e2 = exp.e2.ctfeInterpret();
9324                 uinteger_t index = exp.e2.toUInteger();
9325 
9326                 TupleExp te;
9327                 TypeTuple tup;
9328                 size_t length;
9329                 if (exp.e1.op == EXP.tuple)
9330                 {
9331                     te = cast(TupleExp)exp.e1;
9332                     tup = null;
9333                     length = te.exps.length;
9334                 }
9335                 else if (exp.e1.op == EXP.type)
9336                 {
9337                     te = null;
9338                     tup = cast(TypeTuple)t1b;
9339                     length = Parameter.dim(tup.arguments);
9340                 }
9341                 else
9342                     assert(0);
9343 
9344                 if (length <= index)
9345                 {
9346                     error(exp.loc, "array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
9347                     return setError();
9348                 }
9349                 Expression e;
9350                 if (exp.e1.op == EXP.tuple)
9351                 {
9352                     e = (*te.exps)[cast(size_t)index];
9353                     e = Expression.combine(te.e0, e);
9354                 }
9355                 else
9356                     e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
9357                 result = e;
9358                 return;
9359             }
9360         default:
9361             error(exp.loc, "`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
9362             return setError();
9363         }
9364 
9365         // We might know $ now
9366         setLengthVarIfKnown(exp.lengthVar, t1b);
9367 
9368         if (t1b.ty == Tsarray || t1b.ty == Tarray)
9369         {
9370             Expression el = new ArrayLengthExp(exp.loc, exp.e1);
9371             el = el.expressionSemantic(sc);
9372             el = el.optimize(WANTvalue);
9373             if (el.op == EXP.int64)
9374             {
9375                 exp.e2 = exp.e2.optimize(WANTvalue);
9376                 dinteger_t length = el.toInteger();
9377                 if (length)
9378                 {
9379                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
9380                     // OR it in, because it might already be set for C array indexing
9381                     exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
9382                 }
9383                 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
9384                 {
9385                     if (auto ve = exp.e1.isVarExp())
9386                     {
9387                         /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
9388                          */
9389                         auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
9390                         auto e = new AddExp(exp.loc, vp, exp.e2);
9391                         auto pe = new PtrExp(exp.loc, e);
9392                         result = pe.expressionSemantic(sc).optimize(WANTvalue);
9393                         return;
9394                     }
9395                 }
9396             }
9397         }
9398 
9399         result = exp;
9400     }
9401 
9402     override void visit(PostExp exp)
9403     {
9404         static if (LOGSEMANTIC)
9405         {
9406             printf("PostExp::semantic('%s')\n", exp.toChars());
9407         }
9408         if (exp.type)
9409         {
9410             result = exp;
9411             return;
9412         }
9413 
9414         if (sc.flags & SCOPE.Cfile)
9415         {
9416             /* See if need to rewrite the AST because of cast/call ambiguity
9417              */
9418             if (auto e = castCallAmbiguity(exp, sc))
9419             {
9420                 result = expressionSemantic(e, sc);
9421                 return;
9422             }
9423         }
9424 
9425         if (Expression ex = binSemantic(exp, sc))
9426         {
9427             result = ex;
9428             return;
9429         }
9430         Expression e1x = resolveProperties(sc, exp.e1);
9431         if (e1x.op == EXP.error)
9432         {
9433             result = e1x;
9434             return;
9435         }
9436         exp.e1 = e1x;
9437 
9438         Expression e = exp.op_overload(sc);
9439         if (e)
9440         {
9441             result = e;
9442             return;
9443         }
9444 
9445         if (exp.e1.checkReadModifyWrite(exp.op))
9446             return setError();
9447 
9448         if (exp.e1.op == EXP.slice)
9449         {
9450             const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
9451             error(exp.loc, "cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
9452             return setError();
9453         }
9454 
9455         Type t1 = exp.e1.type.toBasetype();
9456         if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
9457         {
9458             /* Check for operator overloading,
9459              * but rewrite in terms of ++e instead of e++
9460              */
9461 
9462             /* If e1 is not trivial, take a reference to it
9463              */
9464             Expression de = null;
9465             if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
9466             {
9467                 // ref v = e1;
9468                 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
9469                 de = new DeclarationExp(exp.loc, v);
9470                 exp.e1 = new VarExp(exp.e1.loc, v);
9471             }
9472 
9473             /* Rewrite as:
9474              * auto tmp = e1; ++e1; tmp
9475              */
9476             auto tmp = copyToTemp(0, "__pitmp", exp.e1);
9477             Expression ea = new DeclarationExp(exp.loc, tmp);
9478 
9479             Expression eb = exp.e1.syntaxCopy();
9480             eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
9481 
9482             Expression ec = new VarExp(exp.loc, tmp);
9483 
9484             // Combine de,ea,eb,ec
9485             if (de)
9486                 ea = new CommaExp(exp.loc, de, ea);
9487             e = new CommaExp(exp.loc, ea, eb);
9488             e = new CommaExp(exp.loc, e, ec);
9489             e = e.expressionSemantic(sc);
9490             result = e;
9491             return;
9492         }
9493 
9494         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
9495         exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
9496 
9497         e = exp;
9498         if (exp.e1.checkScalar() ||
9499             exp.e1.checkSharedAccess(sc))
9500             return setError();
9501         if (exp.e1.checkNoBool())
9502             return setError();
9503 
9504         if (exp.e1.type.ty == Tpointer)
9505             e = scaleFactor(exp, sc);
9506         else
9507             exp.e2 = exp.e2.castTo(sc, exp.e1.type);
9508         e.type = exp.e1.type;
9509         result = e;
9510     }
9511 
9512     override void visit(PreExp exp)
9513     {
9514         Expression e = exp.op_overload(sc);
9515         // printf("PreExp::semantic('%s')\n", toChars());
9516         if (e)
9517         {
9518             result = e;
9519             return;
9520         }
9521 
9522         // Rewrite as e1+=1 or e1-=1
9523         if (exp.op == EXP.prePlusPlus)
9524             e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
9525         else
9526             e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
9527         result = e.expressionSemantic(sc);
9528     }
9529 
9530     /*
9531      * Get the expression initializer for a specific struct
9532      *
9533      * Params:
9534      *  sd = the struct for which the expression initializer is needed
9535      *  loc = the location of the initializer
9536      *  sc = the scope where the expression is located
9537      *  t = the type of the expression
9538      *
9539      * Returns:
9540      *  The expression initializer or error expression if any errors occured
9541      */
9542     private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
9543     {
9544         if (sd.zeroInit && !sd.isNested())
9545         {
9546             // https://issues.dlang.org/show_bug.cgi?id=14606
9547             // Always use BlitExp for the special expression: (struct = 0)
9548             return IntegerExp.literal!0;
9549         }
9550 
9551         if (sd.isNested())
9552         {
9553             auto sle = new StructLiteralExp(loc, sd, null, t);
9554             if (!sd.fill(loc, *sle.elements, true))
9555                 return ErrorExp.get();
9556             if (checkFrameAccess(loc, sc, sd, sle.elements.length))
9557                 return ErrorExp.get();
9558 
9559             sle.type = t;
9560             return sle;
9561         }
9562 
9563         return t.defaultInit(loc);
9564     }
9565 
9566     override void visit(AssignExp exp)
9567     {
9568         static if (LOGSEMANTIC)
9569         {
9570             if (exp.op == EXP.blit)      printf("BlitExp.toElem('%s')\n", exp.toChars());
9571             if (exp.op == EXP.assign)    printf("AssignExp.toElem('%s')\n", exp.toChars());
9572             if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
9573         }
9574 
9575         void setResult(Expression e, int line = __LINE__)
9576         {
9577             //printf("line %d\n", line);
9578             result = e;
9579         }
9580 
9581         if (exp.type)
9582         {
9583             return setResult(exp);
9584         }
9585 
9586         Expression e1old = exp.e1;
9587 
9588         if (auto e2comma = exp.e2.isCommaExp())
9589         {
9590             if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
9591                 error(exp.loc, "using the result of a comma expression is not allowed");
9592 
9593             /* Rewrite to get rid of the comma from rvalue
9594              *   e1=(e0,e2) => e0,(e1=e2)
9595              */
9596             Expression e0;
9597             exp.e2 = Expression.extractLast(e2comma, e0);
9598             Expression e = Expression.combine(e0, exp);
9599             return setResult(e.expressionSemantic(sc));
9600         }
9601 
9602         /* Look for operator overloading of a[arguments] = e2.
9603          * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
9604          * converted to unary operator overloading already.
9605          */
9606         if (auto ae = exp.e1.isArrayExp())
9607         {
9608             Expression res;
9609 
9610             ae.e1 = ae.e1.expressionSemantic(sc);
9611             ae.e1 = resolveProperties(sc, ae.e1);
9612             Expression ae1old = ae.e1;
9613 
9614             const(bool) maybeSlice =
9615                 (ae.arguments.length == 0 ||
9616                  ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
9617 
9618             IntervalExp ie = null;
9619             if (maybeSlice && ae.arguments.length)
9620             {
9621                 assert((*ae.arguments)[0].op == EXP.interval);
9622                 ie = cast(IntervalExp)(*ae.arguments)[0];
9623             }
9624             Type att = null; // first cyclic `alias this` type
9625             while (true)
9626             {
9627                 if (ae.e1.op == EXP.error)
9628                     return setResult(ae.e1);
9629 
9630                 Expression e0 = null;
9631                 Expression ae1save = ae.e1;
9632                 ae.lengthVar = null;
9633 
9634                 Type t1b = ae.e1.type.toBasetype();
9635                 AggregateDeclaration ad = isAggregate(t1b);
9636                 if (!ad)
9637                     break;
9638                 if (search_function(ad, Id.indexass))
9639                 {
9640                     // Deal with $
9641                     res = resolveOpDollar(sc, ae, &e0);
9642                     if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
9643                         goto Lfallback;
9644                     if (res.op == EXP.error)
9645                         return setResult(res);
9646 
9647                     res = exp.e2.expressionSemantic(sc);
9648                     if (res.op == EXP.error)
9649                         return setResult(res);
9650                     exp.e2 = res;
9651 
9652                     /* Rewrite (a[arguments] = e2) as:
9653                      *      a.opIndexAssign(e2, arguments)
9654                      */
9655                     Expressions* a = ae.arguments.copy();
9656                     a.insert(0, exp.e2);
9657                     res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
9658                     res = new CallExp(exp.loc, res, a);
9659                     if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
9660                         res = res.trySemantic(sc);
9661                     else
9662                         res = res.expressionSemantic(sc);
9663                     if (res)
9664                         return setResult(Expression.combine(e0, res));
9665                 }
9666 
9667             Lfallback:
9668                 if (maybeSlice && search_function(ad, Id.sliceass))
9669                 {
9670                     // Deal with $
9671                     res = resolveOpDollar(sc, ae, ie, &e0);
9672                     if (res.op == EXP.error)
9673                         return setResult(res);
9674 
9675                     res = exp.e2.expressionSemantic(sc);
9676                     if (res.op == EXP.error)
9677                         return setResult(res);
9678 
9679                     exp.e2 = res;
9680 
9681                     /* Rewrite (a[i..j] = e2) as:
9682                      *      a.opSliceAssign(e2, i, j)
9683                      */
9684                     auto a = new Expressions();
9685                     a.push(exp.e2);
9686                     if (ie)
9687                     {
9688                         a.push(ie.lwr);
9689                         a.push(ie.upr);
9690                     }
9691                     res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
9692                     res = new CallExp(exp.loc, res, a);
9693                     res = res.expressionSemantic(sc);
9694                     return setResult(Expression.combine(e0, res));
9695                 }
9696 
9697                 // No operator overloading member function found yet, but
9698                 // there might be an alias this to try.
9699                 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
9700                 {
9701                     /* Rewrite (a[arguments] op e2) as:
9702                      *      a.aliasthis[arguments] op e2
9703                      */
9704                     ae.e1 = resolveAliasThis(sc, ae1save, true);
9705                     if (ae.e1)
9706                         continue;
9707                 }
9708                 break;
9709             }
9710             ae.e1 = ae1old; // recovery
9711             ae.lengthVar = null;
9712         }
9713 
9714         /* Run this.e1 semantic.
9715          */
9716         {
9717             Expression e1x = exp.e1;
9718 
9719             /* With UFCS, e.f = value
9720              * Could mean:
9721              *      .f(e, value)
9722              * or:
9723              *      .f(e) = value
9724              */
9725             if (auto dti = e1x.isDotTemplateInstanceExp())
9726             {
9727                 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
9728                 if (!e)
9729                 {
9730                     return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9731                 }
9732 
9733                 e1x = e;
9734             }
9735             else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
9736             {
9737                 auto die = e1x.isDotIdExp();
9738                 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
9739             }
9740             else if (auto die = e1x.isDotIdExp())
9741             {
9742                 Expression e = die.dotIdSemanticProp(sc, 1);
9743                 if (e && isDotOpDispatch(e))
9744                 {
9745                     /* https://issues.dlang.org/show_bug.cgi?id=19687
9746                      *
9747                      * On this branch, e2 is semantically analyzed in resolvePropertiesX,
9748                      * but that call is done with gagged errors. That is the only time when
9749                      * semantic gets ran on e2, that is why the error never gets to be printed.
9750                      * In order to make sure that UFCS is tried with correct parameters, e2
9751                      * needs to have semantic ran on it.
9752                      */
9753                     auto ode = e;
9754                     exp.e2 = exp.e2.expressionSemantic(sc);
9755                     uint errors = global.startGagging();
9756                     e = resolvePropertiesX(sc, e, exp.e2);
9757                     // Any error or if 'e' is not resolved, go to UFCS
9758                     if (global.endGagging(errors) || e is ode)
9759                         e = null; /* fall down to UFCS */
9760                     else
9761                         return setResult(e);
9762                 }
9763                 if (!e)
9764                     return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9765                 e1x = e;
9766             }
9767             else
9768             {
9769                 if (auto se = e1x.isSliceExp())
9770                     se.arrayop = true;
9771 
9772                 e1x = e1x.expressionSemantic(sc);
9773             }
9774 
9775             /* We have f = value.
9776              * Could mean:
9777              *      f(value)
9778              * or:
9779              *      f() = value
9780              */
9781             if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
9782                 return setResult(e);
9783 
9784             if (e1x.checkRightThis(sc))
9785             {
9786                 return setError();
9787             }
9788             exp.e1 = e1x;
9789             assert(exp.e1.type);
9790         }
9791         Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
9792 
9793         /* Run this.e2 semantic.
9794          * Different from other binary expressions, the analysis of e2
9795          * depends on the result of e1 in assignments.
9796          */
9797         {
9798             Expression e2x = inferType(exp.e2, t1.baseElemOf());
9799             e2x = e2x.expressionSemantic(sc);
9800             if (!t1.isTypeSArray())
9801                 e2x = e2x.arrayFuncConv(sc);
9802             e2x = resolveProperties(sc, e2x);
9803             if (e2x.op == EXP.type)
9804                 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
9805             if (e2x.op == EXP.error)
9806                 return setResult(e2x);
9807             // We delay checking the value for structs/classes as these might have
9808             // an opAssign defined.
9809             if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
9810                 e2x.checkSharedAccess(sc))
9811                 return setError();
9812 
9813             auto etmp = checkNoreturnVarAccess(e2x);
9814             if (etmp != e2x)
9815                 return setResult(etmp);
9816 
9817             exp.e2 = e2x;
9818         }
9819 
9820         /* Rewrite tuple assignment as a tuple of assignments.
9821          */
9822         {
9823             Expression e2x = exp.e2;
9824 
9825         Ltupleassign:
9826             if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
9827             {
9828                 TupleExp tup1 = cast(TupleExp)exp.e1;
9829                 TupleExp tup2 = cast(TupleExp)e2x;
9830                 size_t dim = tup1.exps.length;
9831                 Expression e = null;
9832                 if (dim != tup2.exps.length)
9833                 {
9834                     error(exp.loc, "mismatched sequence lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
9835                     return setError();
9836                 }
9837                 if (dim == 0)
9838                 {
9839                     e = IntegerExp.literal!0;
9840                     e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
9841                     e = Expression.combine(tup1.e0, tup2.e0, e);
9842                 }
9843                 else
9844                 {
9845                     auto exps = new Expressions(dim);
9846                     for (size_t i = 0; i < dim; i++)
9847                     {
9848                         Expression ex1 = (*tup1.exps)[i];
9849                         Expression ex2 = (*tup2.exps)[i];
9850                         (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
9851                     }
9852                     e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
9853                 }
9854                 return setResult(e.expressionSemantic(sc));
9855             }
9856 
9857             /* Look for form: e1 = e2.aliasthis.
9858              */
9859             if (exp.e1.op == EXP.tuple)
9860             {
9861                 TupleDeclaration td = isAliasThisTuple(e2x);
9862                 if (!td)
9863                     goto Lnomatch;
9864 
9865                 assert(exp.e1.type.ty == Ttuple);
9866                 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9867 
9868                 Expression e0;
9869                 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9870 
9871                 auto iexps = new Expressions();
9872                 iexps.push(ev);
9873                 for (size_t u = 0; u < iexps.length; u++)
9874                 {
9875                 Lexpand:
9876                     Expression e = (*iexps)[u];
9877 
9878                     Parameter arg = Parameter.getNth(tt.arguments, u);
9879                     //printf("[%d] iexps.length = %d, ", u, iexps.length);
9880                     //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
9881                     //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9882 
9883                     if (!arg || !e.type.implicitConvTo(arg.type))
9884                     {
9885                         // expand initializer to tuple
9886                         if (expandAliasThisTuples(iexps, u) != -1)
9887                         {
9888                             if (iexps.length <= u)
9889                                 break;
9890                             goto Lexpand;
9891                         }
9892                         goto Lnomatch;
9893                     }
9894                 }
9895                 e2x = new TupleExp(e2x.loc, e0, iexps);
9896                 e2x = e2x.expressionSemantic(sc);
9897                 if (e2x.op == EXP.error)
9898                 {
9899                     result = e2x;
9900                     return;
9901                 }
9902                 // Do not need to overwrite this.e2
9903                 goto Ltupleassign;
9904             }
9905         Lnomatch:
9906         }
9907 
9908         /* Inside constructor, if this is the first assignment of object field,
9909          * rewrite this to initializing the field.
9910          */
9911         if (exp.op == EXP.assign
9912             && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9913         {
9914             //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9915             auto t = exp.type;
9916             exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9917             exp.type = t;
9918 
9919             // https://issues.dlang.org/show_bug.cgi?id=13515
9920             // set Index::modifiable flag for complex AA element initialization
9921             if (auto ie1 = exp.e1.isIndexExp())
9922             {
9923                 Expression e1x = ie1.markSettingAAElem();
9924                 if (e1x.op == EXP.error)
9925                 {
9926                     result = e1x;
9927                     return;
9928                 }
9929             }
9930         }
9931         else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
9932                  (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9933         {
9934             exp.memset = MemorySet.referenceInit;
9935         }
9936 
9937         if (exp.op == EXP.assign)  // skip EXP.blit and EXP.construct, which are initializations
9938         {
9939             exp.e1.checkSharedAccess(sc);
9940             checkUnsafeAccess(sc, exp.e1, false, true);
9941         }
9942 
9943         checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9944 
9945         /* If it is an assignment from a 'foreign' type,
9946          * check for operator overloading.
9947          */
9948         if (exp.memset == MemorySet.referenceInit)
9949         {
9950             // If this is an initialization of a reference,
9951             // do nothing
9952         }
9953         else if (t1.ty == Tstruct)
9954         {
9955             auto e1x = exp.e1;
9956             auto e2x = exp.e2;
9957             auto sd = (cast(TypeStruct)t1).sym;
9958 
9959             if (exp.op == EXP.construct)
9960             {
9961                 Type t2 = e2x.type.toBasetype();
9962                 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9963                 {
9964                     sd.size(exp.loc);
9965                     if (sd.sizeok != Sizeok.done)
9966                         return setError();
9967                     if (!sd.ctor)
9968                         sd.ctor = sd.searchCtor();
9969 
9970                     // https://issues.dlang.org/show_bug.cgi?id=15661
9971                     // Look for the form from last of comma chain.
9972                     auto e2y = lastComma(e2x);
9973 
9974                     CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9975                     DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
9976                         ? cast(DotVarExp)ce.e1 : null;
9977                     if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9978                         // https://issues.dlang.org/show_bug.cgi?id=19389
9979                         dve.e1.op != EXP.dotVariable &&
9980                         e2y.type.implicitConvTo(t1))
9981                     {
9982                         /* Look for form of constructor call which is:
9983                          *    __ctmp.ctor(arguments...)
9984                          */
9985 
9986                         /* Before calling the constructor, initialize
9987                          * variable with a bit copy of the default
9988                          * initializer
9989                          */
9990                         Expression einit = getInitExp(sd, exp.loc, sc, t1);
9991                         if (einit.op == EXP.error)
9992                         {
9993                             result = einit;
9994                             return;
9995                         }
9996 
9997                         auto ae = new BlitExp(exp.loc, exp.e1, einit);
9998                         ae.type = e1x.type;
9999 
10000                         /* Replace __ctmp being constructed with e1.
10001                          * We need to copy constructor call expression,
10002                          * because it may be used in other place.
10003                          */
10004                         auto dvx = cast(DotVarExp)dve.copy();
10005                         dvx.e1 = e1x;
10006                         auto cx = cast(CallExp)ce.copy();
10007                         cx.e1 = dvx;
10008                         if (checkConstructorEscape(sc, cx, false))
10009                             return setError();
10010 
10011                         Expression e0;
10012                         Expression.extractLast(e2x, e0);
10013 
10014                         auto e = Expression.combine(e0, ae, cx);
10015                         e = e.expressionSemantic(sc);
10016                         result = e;
10017                         return;
10018                     }
10019                     // https://issues.dlang.org/show_bug.cgi?id=21586
10020                     // Rewrite CondExp or e1 will miss direct construction, e.g.
10021                     // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
10022                     // a temporary created and an extra destructor call.
10023                     // AST will be rewritten to:
10024                     // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
10025                     if (e2x.op == EXP.question)
10026                     {
10027                         /* Rewrite as:
10028                          *  a ? e1 = b : e1 = c;
10029                          */
10030                         CondExp econd = cast(CondExp)e2x;
10031                         Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
10032                         Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
10033                         Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
10034                         result = e.expressionSemantic(sc);
10035                         return;
10036                     }
10037                     if (sd.postblit || sd.hasCopyCtor)
10038                     {
10039                         /* We have a copy constructor for this
10040                          */
10041 
10042                         if (e2x.isLvalue())
10043                         {
10044                             if (sd.hasCopyCtor)
10045                             {
10046                                 /* Rewrite as:
10047                                  * e1 = init, e1.copyCtor(e2);
10048                                  */
10049                                 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
10050                                 einit.type = e1x.type;
10051 
10052                                 Expression e;
10053                                 e = new DotIdExp(exp.loc, e1x, Id.ctor);
10054                                 e = new CallExp(exp.loc, e, e2x);
10055                                 e = new CommaExp(exp.loc, einit, e);
10056 
10057                                 //printf("e: %s\n", e.toChars());
10058 
10059                                 result = e.expressionSemantic(sc);
10060                                 return;
10061                             }
10062                             else
10063                             {
10064                                 if (!e2x.type.implicitConvTo(e1x.type))
10065                                 {
10066                                     error(exp.loc, "conversion error from `%s` to `%s`",
10067                                         e2x.type.toChars(), e1x.type.toChars());
10068                                     return setError();
10069                                 }
10070 
10071                                 /* Rewrite as:
10072                                  *  (e1 = e2).postblit();
10073                                  *
10074                                  * Blit assignment e1 = e2 returns a reference to the original e1,
10075                                  * then call the postblit on it.
10076                                  */
10077                                 Expression e = e1x.copy();
10078                                 e.type = e.type.mutableOf();
10079                                 if (e.type.isShared && !sd.type.isShared)
10080                                     e.type = e.type.unSharedOf();
10081                                 e = new BlitExp(exp.loc, e, e2x);
10082                                 e = new DotVarExp(exp.loc, e, sd.postblit, false);
10083                                 e = new CallExp(exp.loc, e);
10084                                 result = e.expressionSemantic(sc);
10085                                 return;
10086                             }
10087                         }
10088                         else
10089                         {
10090                             /* The struct value returned from the function is transferred
10091                              * so should not call the destructor on it.
10092                              */
10093                             e2x = valueNoDtor(e2x);
10094                         }
10095                     }
10096 
10097                     // https://issues.dlang.org/show_bug.cgi?id=19251
10098                     // if e2 cannot be converted to e1.type, maybe there is an alias this
10099                     if (!e2x.implicitConvTo(t1))
10100                     {
10101                         AggregateDeclaration ad2 = isAggregate(e2x.type);
10102                         if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10103                         {
10104                             /* Rewrite (e1 op e2) as:
10105                              *      (e1 op e2.aliasthis)
10106                              */
10107                             exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10108                             result = exp.expressionSemantic(sc);
10109                             return;
10110                         }
10111                     }
10112                 }
10113                 else if (!e2x.implicitConvTo(t1))
10114                 {
10115                     sd.size(exp.loc);
10116                     if (sd.sizeok != Sizeok.done)
10117                         return setError();
10118                     if (!sd.ctor)
10119                         sd.ctor = sd.searchCtor();
10120 
10121                     if (sd.ctor)
10122                     {
10123                         /* Look for implicit constructor call
10124                          * Rewrite as:
10125                          *  e1 = init, e1.ctor(e2)
10126                          */
10127 
10128                         /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
10129                          * Using `new` to initialize a struct object is a common mistake, but
10130                          * the error message from the compiler is not very helpful in that
10131                          * case. If exp.e2 is a NewExp and the type of new is the same as
10132                          * the type as exp.e1 (struct in this case), then we know for sure
10133                          * that the user wants to instantiate a struct. This is done to avoid
10134                          * issuing an error when the user actually wants to call a constructor
10135                          * which receives a class object.
10136                          *
10137                          * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
10138                          * which receives an instance of a Foo2 class
10139                          */
10140                         if (exp.e2.op == EXP.new_)
10141                         {
10142                             auto newExp = cast(NewExp)(exp.e2);
10143                             if (newExp.newtype && newExp.newtype == t1)
10144                             {
10145                                 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
10146                                       newExp.toChars(), newExp.type.toChars(), t1.toChars());
10147                                 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
10148                                 return setError();
10149                             }
10150                         }
10151 
10152                         Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
10153                         einit.type = e1x.type;
10154 
10155                         Expression e;
10156                         e = new DotIdExp(exp.loc, e1x, Id.ctor);
10157                         e = new CallExp(exp.loc, e, e2x);
10158                         e = new CommaExp(exp.loc, einit, e);
10159                         e = e.expressionSemantic(sc);
10160                         result = e;
10161                         return;
10162                     }
10163                     if (search_function(sd, Id.call))
10164                     {
10165                         /* Look for static opCall
10166                          * https://issues.dlang.org/show_bug.cgi?id=2702
10167                          * Rewrite as:
10168                          *  e1 = typeof(e1).opCall(arguments)
10169                          */
10170                         e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
10171                         e2x = new CallExp(exp.loc, e2x, exp.e2);
10172 
10173                         e2x = e2x.expressionSemantic(sc);
10174                         e2x = resolveProperties(sc, e2x);
10175                         if (e2x.op == EXP.error)
10176                         {
10177                             result = e2x;
10178                             return;
10179                         }
10180                         if (e2x.checkValue() || e2x.checkSharedAccess(sc))
10181                             return setError();
10182                     }
10183                 }
10184                 else // https://issues.dlang.org/show_bug.cgi?id=11355
10185                 {
10186                     AggregateDeclaration ad2 = isAggregate(e2x.type);
10187                     if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
10188                     {
10189                         /* Rewrite (e1 op e2) as:
10190                          *      (e1 op e2.aliasthis)
10191                          */
10192                         exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
10193                         result = exp.expressionSemantic(sc);
10194                         return;
10195                     }
10196                 }
10197             }
10198             else if (exp.op == EXP.assign)
10199             {
10200                 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
10201                 {
10202                     /*
10203                      * Rewrite:
10204                      *      aa[key] = e2;
10205                      * as:
10206                      *      ref __aatmp = aa;
10207                      *      ref __aakey = key;
10208                      *      ref __aaval = e2;
10209                      *      (__aakey in __aatmp
10210                      *          ? __aatmp[__aakey].opAssign(__aaval)
10211                      *          : ConstructExp(__aatmp[__aakey], __aaval));
10212                      */
10213                     // ensure we keep the expr modifiable
10214                     Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
10215                     if (esetting.op == EXP.error)
10216                     {
10217                         result = esetting;
10218                         return;
10219                     }
10220                     assert(esetting.op == EXP.index);
10221                     IndexExp ie = cast(IndexExp) esetting;
10222                     Type t2 = e2x.type.toBasetype();
10223 
10224                     Expression e0 = null;
10225                     Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
10226                     Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
10227                     Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
10228 
10229                     AssignExp ae = cast(AssignExp)exp.copy();
10230                     ae.e1 = new IndexExp(exp.loc, ea, ek);
10231                     ae.e1 = ae.e1.expressionSemantic(sc);
10232                     ae.e1 = ae.e1.optimize(WANTvalue);
10233                     ae.e2 = ev;
10234                     Expression e = ae.op_overload(sc);
10235                     if (e)
10236                     {
10237                         Expression ey = null;
10238                         if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
10239                         {
10240                             ey = ev;
10241                         }
10242                         else if (!ev.implicitConvTo(ie.type) && sd.ctor)
10243                         {
10244                             // Look for implicit constructor call
10245                             // Rewrite as S().ctor(e2)
10246                             ey = new StructLiteralExp(exp.loc, sd, null);
10247                             ey = new DotIdExp(exp.loc, ey, Id.ctor);
10248                             ey = new CallExp(exp.loc, ey, ev);
10249                             ey = ey.trySemantic(sc);
10250                         }
10251                         if (ey)
10252                         {
10253                             Expression ex;
10254                             ex = new IndexExp(exp.loc, ea, ek);
10255                             ex = ex.expressionSemantic(sc);
10256                             ex = ex.modifiableLvalue(sc, ex); // allocate new slot
10257                             ex = ex.optimize(WANTvalue);
10258 
10259                             ey = new ConstructExp(exp.loc, ex, ey);
10260                             ey = ey.expressionSemantic(sc);
10261                             if (ey.op == EXP.error)
10262                             {
10263                                 result = ey;
10264                                 return;
10265                             }
10266                             ex = e;
10267 
10268                             // https://issues.dlang.org/show_bug.cgi?id=14144
10269                             // The whole expression should have the common type
10270                             // of opAssign() return and assigned AA entry.
10271                             // Even if there's no common type, expression should be typed as void.
10272                             if (!typeMerge(sc, EXP.question, ex, ey))
10273                             {
10274                                 ex = new CastExp(ex.loc, ex, Type.tvoid);
10275                                 ey = new CastExp(ey.loc, ey, Type.tvoid);
10276                             }
10277                             e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
10278                         }
10279                         e = Expression.combine(e0, e);
10280                         e = e.expressionSemantic(sc);
10281                         result = e;
10282                         return;
10283                     }
10284                 }
10285                 else
10286                 {
10287                     Expression e = exp.op_overload(sc);
10288                     if (e)
10289                     {
10290                         result = e;
10291                         return;
10292                     }
10293                 }
10294             }
10295             else
10296                 assert(exp.op == EXP.blit);
10297 
10298             if (e2x.checkValue())
10299                 return setError();
10300 
10301             exp.e1 = e1x;
10302             exp.e2 = e2x;
10303         }
10304         else if (t1.ty == Tclass)
10305         {
10306             // Disallow assignment operator overloads for same type
10307             if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
10308             {
10309                 Expression e = exp.op_overload(sc);
10310                 if (e)
10311                 {
10312                     result = e;
10313                     return;
10314                 }
10315             }
10316             if (exp.e2.checkValue())
10317                 return setError();
10318         }
10319         else if (t1.ty == Tsarray)
10320         {
10321             // SliceExp cannot have static array type without context inference.
10322             assert(exp.e1.op != EXP.slice);
10323             Expression e1x = exp.e1;
10324             Expression e2x = exp.e2;
10325 
10326             /* C strings come through as static arrays. May need to adjust the size of the
10327              * string to match the size of e1.
10328              */
10329             Type t2 = e2x.type.toBasetype();
10330             if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
10331             {
10332                 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
10333                 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
10334                 if (dim1 + 1 == dim2 || dim2 < dim1)
10335                 {
10336                     auto tsa2 = t2.isTypeSArray();
10337                     auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
10338                     e2x = castTo(e2x, sc, newt);
10339                     exp.e2 = e2x;
10340                 }
10341             }
10342 
10343             if (e2x.implicitConvTo(e1x.type))
10344             {
10345                 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()))
10346                 {
10347                     if (e1x.checkPostblit(sc, t1))
10348                         return setError();
10349                 }
10350 
10351                 // e2 matches to t1 because of the implicit length match, so
10352                 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
10353                 {
10354                     // convert e1 to e1[]
10355                     // e.g. e1[] = a[] + b[];
10356                     auto sle = new SliceExp(e1x.loc, e1x, null, null);
10357                     sle.arrayop = true;
10358                     e1x = sle.expressionSemantic(sc);
10359                 }
10360                 else
10361                 {
10362                     // convert e2 to t1 later
10363                     // e.g. e1 = [1, 2, 3];
10364                 }
10365             }
10366             else
10367             {
10368                 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
10369                 {
10370                     uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
10371                     uinteger_t dim2 = dim1;
10372                     if (auto ale = e2x.isArrayLiteralExp())
10373                     {
10374                         dim2 = ale.elements ? ale.elements.length : 0;
10375                     }
10376                     else if (auto se = e2x.isSliceExp())
10377                     {
10378                         Type tx = toStaticArrayType(se);
10379                         if (tx)
10380                             dim2 = (cast(TypeSArray)tx).dim.toInteger();
10381                     }
10382                     if (dim1 != dim2)
10383                     {
10384                         error(exp.loc, "mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
10385                         return setError();
10386                     }
10387                 }
10388 
10389                 // May be block or element-wise assignment, so
10390                 // convert e1 to e1[]
10391                 if (exp.op != EXP.assign)
10392                 {
10393                     // If multidimensional static array, treat as one large array
10394                     //
10395                     // Find the appropriate array type depending on the assignment, e.g.
10396                     // int[3] = int => int[3]
10397                     // int[3][2] = int => int[6]
10398                     // int[3][2] = int[] => int[3][2]
10399                     // int[3][2][4] + int => int[24]
10400                     // int[3][2][4] + int[] => int[3][8]
10401                     ulong dim = t1.isTypeSArray().dim.toUInteger();
10402                     auto type = t1.nextOf();
10403 
10404                     for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
10405                     {
10406                         import core.checkedint : mulu;
10407 
10408                         // Accumulate skipped dimensions
10409                         bool overflow = false;
10410                         dim = mulu(dim, tsa.dim.toUInteger(), overflow);
10411                         if (overflow || dim >= uint.max)
10412                         {
10413                             // dym exceeds maximum array size
10414                             error(exp.loc, "static array `%s` size overflowed to %llu",
10415                                         e1x.type.toChars(), cast(ulong) dim);
10416                             return setError();
10417                         }
10418 
10419                         // Move to the element type
10420                         type = tsa.nextOf().toBasetype();
10421 
10422                         // Rewrite ex1 as a static array if a matching type was found
10423                         if (e2x.implicitConvTo(type) > MATCH.nomatch)
10424                         {
10425                             e1x.type = type.sarrayOf(dim);
10426                             break;
10427                         }
10428                     }
10429                 }
10430                 auto sle = new SliceExp(e1x.loc, e1x, null, null);
10431                 sle.arrayop = true;
10432                 e1x = sle.expressionSemantic(sc);
10433             }
10434             if (e1x.op == EXP.error)
10435                 return setResult(e1x);
10436             if (e2x.op == EXP.error)
10437                 return setResult(e2x);
10438 
10439             exp.e1 = e1x;
10440             exp.e2 = e2x;
10441             t1 = e1x.type.toBasetype();
10442         }
10443         /* Check the mutability of e1.
10444          */
10445         if (auto ale = exp.e1.isArrayLengthExp())
10446         {
10447             // e1 is not an lvalue, but we let code generator handle it
10448 
10449             auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
10450             if (ale1x.op == EXP.error)
10451                 return setResult(ale1x);
10452             ale.e1 = ale1x;
10453 
10454             Type tn = ale.e1.type.toBasetype().nextOf();
10455             checkDefCtor(ale.loc, tn);
10456 
10457             Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
10458             if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
10459                 return setError();
10460 
10461             exp.e2 = exp.e2.expressionSemantic(sc);
10462             auto lc = lastComma(exp.e2);
10463             lc = lc.optimize(WANTvalue);
10464             // use slice expression when arr.length = 0 to avoid runtime call
10465             if(lc.op == EXP.int64 && lc.toInteger() == 0)
10466             {
10467                 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
10468                 Expression as = new AssignExp(ale.loc, ale.e1, se);
10469                 as = as.expressionSemantic(sc);
10470                 auto res = Expression.combine(as, exp.e2);
10471                 res.type = ale.type;
10472                 return setResult(res);
10473             }
10474 
10475             if (!sc.needsCodegen())      // if compile time creature only
10476             {
10477                 exp.type = Type.tsize_t;
10478                 return setResult(exp);
10479             }
10480 
10481             // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
10482             Expression id = new IdentifierExp(ale.loc, Id.empty);
10483             id = new DotIdExp(ale.loc, id, Id.object);
10484             auto tiargs = new Objects();
10485             tiargs.push(ale.e1.type);
10486             id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
10487             id = new DotIdExp(ale.loc, id, hook);
10488             id = id.expressionSemantic(sc);
10489 
10490             auto arguments = new Expressions();
10491             arguments.reserve(5);
10492             if (global.params.tracegc)
10493             {
10494                 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10495                 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10496                 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10497                 arguments.push(new StringExp(exp.loc, funcname.toDString()));
10498             }
10499             arguments.push(ale.e1);
10500             arguments.push(exp.e2);
10501 
10502             Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
10503             auto res = new LoweredAssignExp(exp, ce);
10504             // if (global.params.verbose)
10505             //     message("lowered   %s =>\n          %s", exp.toChars(), res.toChars());
10506             res.type = Type.tsize_t;
10507             return setResult(res);
10508         }
10509         else if (auto se = exp.e1.isSliceExp())
10510         {
10511             Type tn = se.type.nextOf();
10512             const fun = sc.func;
10513             if (exp.op == EXP.assign && !tn.isMutable() &&
10514                 // allow modifiation in module ctor, see
10515                 // https://issues.dlang.org/show_bug.cgi?id=9884
10516                 (!fun || (fun && !fun.isStaticCtorDeclaration())))
10517             {
10518                 error(exp.loc, "slice `%s` is not mutable", se.toChars());
10519                 return setError();
10520             }
10521 
10522             if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
10523             {
10524                 error(exp.loc, "slice `%s` is not mutable, struct `%s` has immutable members",
10525                     exp.e1.toChars(), tn.baseElemOf().toChars());
10526                 result = ErrorExp.get();
10527                 return;
10528             }
10529 
10530             // For conditional operator, both branches need conversion.
10531             while (se.e1.op == EXP.slice)
10532                 se = cast(SliceExp)se.e1;
10533             if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
10534             {
10535                 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
10536                 if (se.e1.op == EXP.error)
10537                     return setResult(se.e1);
10538             }
10539         }
10540         else
10541         {
10542             if (t1.ty == Tsarray && exp.op == EXP.assign)
10543             {
10544                 Type tn = exp.e1.type.nextOf();
10545                 if (tn && !tn.baseElemOf().isAssignable())
10546                 {
10547                     error(exp.loc, "array `%s` is not mutable, struct `%s` has immutable members",
10548                         exp.e1.toChars(), tn.baseElemOf().toChars());
10549                     result = ErrorExp.get();
10550                     return;
10551                 }
10552             }
10553 
10554             Expression e1x = exp.e1;
10555 
10556             // Try to do a decent error message with the expression
10557             // before it gets constant folded
10558             if (exp.op == EXP.assign)
10559                 e1x = e1x.modifiableLvalue(sc, e1old);
10560 
10561             e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
10562 
10563             if (e1x.op == EXP.error)
10564             {
10565                 result = e1x;
10566                 return;
10567             }
10568             exp.e1 = e1x;
10569         }
10570 
10571         /* Tweak e2 based on the type of e1.
10572          */
10573         Expression e2x = exp.e2;
10574         Type t2 = e2x.type.toBasetype();
10575 
10576         // If it is a array, get the element type. Note that it may be
10577         // multi-dimensional.
10578         Type telem = t1;
10579         while (telem.ty == Tarray)
10580             telem = telem.nextOf();
10581 
10582         if (exp.e1.op == EXP.slice && t1.nextOf() &&
10583             (telem.ty != Tvoid || e2x.op == EXP.null_) &&
10584             e2x.implicitConvTo(t1.nextOf()))
10585         {
10586             // Check for block assignment. If it is of type void[], void[][], etc,
10587             // '= null' is the only allowable block assignment (Bug 7493)
10588             exp.memset = MemorySet.blockAssign;    // make it easy for back end to tell what this is
10589             e2x = e2x.implicitCastTo(sc, t1.nextOf());
10590             if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
10591                 return setError();
10592         }
10593         else if (exp.e1.op == EXP.slice &&
10594                  (t2.ty == Tarray || t2.ty == Tsarray) &&
10595                  t2.nextOf().implicitConvTo(t1.nextOf()))
10596         {
10597             // Check element-wise assignment.
10598 
10599             /* If assigned elements number is known at compile time,
10600              * check the mismatch.
10601              */
10602             SliceExp se1 = cast(SliceExp)exp.e1;
10603             TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
10604             TypeSArray tsa2 = null;
10605             if (auto ale = e2x.isArrayLiteralExp())
10606                 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
10607             else if (auto se = e2x.isSliceExp())
10608                 tsa2 = cast(TypeSArray)toStaticArrayType(se);
10609             else
10610                 tsa2 = t2.isTypeSArray();
10611 
10612             if (tsa1 && tsa2)
10613             {
10614                 uinteger_t dim1 = tsa1.dim.toInteger();
10615                 uinteger_t dim2 = tsa2.dim.toInteger();
10616                 if (dim1 != dim2)
10617                 {
10618                     error(exp.loc, "mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
10619                     return setError();
10620                 }
10621             }
10622 
10623             if (exp.op != EXP.blit &&
10624                 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
10625                  e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
10626                  e2x.op != EXP.slice && e2x.isLvalue()))
10627             {
10628                 if (exp.e1.checkPostblit(sc, t1.nextOf()))
10629                     return setError();
10630             }
10631 
10632             Type t2n = t2.nextOf();
10633             Type t1n = t1.nextOf();
10634             int offset;
10635             if (t2n.equivalent(t1n) ||
10636                 t1n.isBaseOf(t2n, &offset) && offset == 0)
10637             {
10638                 /* Allow copy of distinct qualifier elements.
10639                  * eg.
10640                  *  char[] dst;  const(char)[] src;
10641                  *  dst[] = src;
10642                  *
10643                  *  class C {}   class D : C {}
10644                  *  C[2] ca;  D[] da;
10645                  *  ca[] = da;
10646                  */
10647                 if (isArrayOpValid(e2x))
10648                 {
10649                     // Don't add CastExp to keep AST for array operations
10650                     e2x = e2x.copy();
10651                     e2x.type = exp.e1.type.constOf();
10652                 }
10653                 else
10654                     e2x = e2x.castTo(sc, exp.e1.type.constOf());
10655             }
10656             else
10657             {
10658                 /* https://issues.dlang.org/show_bug.cgi?id=15778
10659                  * A string literal has an array type of immutable
10660                  * elements by default, and normally it cannot be convertible to
10661                  * array type of mutable elements. But for element-wise assignment,
10662                  * elements need to be const at best. So we should give a chance
10663                  * to change code unit size for polysemous string literal.
10664                  */
10665                 if (e2x.op == EXP.string_)
10666                     e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
10667                 else
10668                     e2x = e2x.implicitCastTo(sc, exp.e1.type);
10669             }
10670             if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
10671             {
10672                 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
10673                     return setError();
10674             }
10675         }
10676         else
10677         {
10678             if (exp.op == EXP.blit)
10679                 e2x = e2x.castTo(sc, exp.e1.type);
10680             else
10681             {
10682                 e2x = e2x.implicitCastTo(sc, exp.e1.type);
10683 
10684                 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
10685 
10686                 // If the implicit cast has failed and the assign expression is
10687                 // the initialization of a struct member field
10688                 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
10689                 {
10690                     scope sd = (cast(TypeStruct)t1).sym;
10691                     Dsymbol opAssign = search_function(sd, Id.assign);
10692 
10693                     // and the struct defines an opAssign
10694                     if (opAssign)
10695                     {
10696                         // offer more information about the cause of the problem
10697                         errorSupplemental(exp.loc,
10698                                           "`%s` is the first assignment of `%s` therefore it represents its initialization",
10699                                           exp.toChars(), exp.e1.toChars());
10700                         errorSupplemental(exp.loc,
10701                                           "`opAssign` methods are not used for initialization, but for subsequent assignments");
10702                     }
10703                 }
10704             }
10705         }
10706         if (e2x.op == EXP.error)
10707         {
10708             result = e2x;
10709             return;
10710         }
10711         exp.e2 = e2x;
10712         t2 = exp.e2.type.toBasetype();
10713 
10714         /* Look for array operations
10715          */
10716         if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
10717         {
10718             // Look for valid array operations
10719             if (exp.memset != MemorySet.blockAssign &&
10720                 exp.e1.op == EXP.slice &&
10721                 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
10722             {
10723                 exp.type = exp.e1.type;
10724                 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
10725                                         // tweak mutability of e1 element
10726                     exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
10727                 result = arrayOp(exp, sc);
10728                 return;
10729             }
10730 
10731             // Drop invalid array operations in e2
10732             //  d = a[] + b[], d = (a[] + b[])[0..2], etc
10733             if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
10734                 return setError();
10735 
10736             // Remains valid array assignments
10737             //  d = d[], d = [1,2,3], etc
10738         }
10739 
10740         /* Don't allow assignment to classes that were allocated on the stack with:
10741          *      scope Class c = new Class();
10742          */
10743         if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
10744         {
10745             VarExp ve = cast(VarExp)exp.e1;
10746             VarDeclaration vd = ve.var.isVarDeclaration();
10747             if (vd && vd.onstack)
10748             {
10749                 assert(t1.ty == Tclass);
10750                 error(exp.loc, "cannot rebind scope variables");
10751             }
10752         }
10753 
10754         if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
10755         {
10756             error(exp.loc, "cannot modify compiler-generated variable `__ctfe`");
10757         }
10758 
10759         exp.type = exp.e1.type;
10760         assert(exp.type);
10761         auto assignElem = exp.e2;
10762         auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
10763         /* https://issues.dlang.org/show_bug.cgi?id=22366
10764          *
10765          * `reorderSettingAAElem` creates a tree of comma expressions, however,
10766          * `checkAssignExp` expects only AssignExps.
10767          */
10768         if (res == exp) // no `AA[k] = v` rewrite was performed
10769             checkAssignEscape(sc, res, false, false);
10770         else
10771             checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
10772 
10773         if (auto ae = res.isConstructExp())
10774         {
10775             Type t1b = ae.e1.type.toBasetype();
10776             if (t1b.ty != Tsarray && t1b.ty != Tarray)
10777                 return setResult(res);
10778 
10779             // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10780             Type t1e = t1b.nextOf();
10781             TypeStruct ts = t1e.baseElemOf().isTypeStruct();
10782             if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
10783                 return setResult(res);
10784 
10785             // don't lower ref-constructions etc.
10786             if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
10787                 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
10788                 return setResult(res);
10789 
10790             // Construction from an equivalent other array?
10791             // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10792             Type t2b = ae.e2.type.toBasetype();
10793             // skip over a (possibly implicit) cast of a static array RHS to a slice
10794             Expression rhs = ae.e2;
10795             Type rhsType = t2b;
10796             if (t2b.ty == Tarray)
10797             {
10798                 if (auto ce = rhs.isCastExp())
10799                 {
10800                     auto ct = ce.e1.type.toBasetype();
10801                     if (ct.ty == Tsarray)
10802                     {
10803                         rhs = ce.e1;
10804                         rhsType = ct;
10805                     }
10806                 }
10807             }
10808 
10809             if (!sc.needsCodegen()) // interpreter can handle these
10810                 return setResult(res);
10811 
10812             const lowerToArrayCtor =
10813                 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
10814                   (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
10815                 t1e.equivalent(t2b.nextOf);
10816 
10817             // Construction from a single element?
10818             // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10819             const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
10820 
10821             if (lowerToArrayCtor || lowerToArraySetCtor)
10822             {
10823                 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
10824                 const other = lowerToArrayCtor ? "other array" : "value";
10825                 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
10826                     return setError();
10827 
10828                 // Lower to object._d_array{,set}ctor(e1, e2)
10829                 Expression id = new IdentifierExp(exp.loc, Id.empty);
10830                 id = new DotIdExp(exp.loc, id, Id.object);
10831                 id = new DotIdExp(exp.loc, id, func);
10832 
10833                 auto arguments = new Expressions();
10834                 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
10835                 if (lowerToArrayCtor)
10836                 {
10837                     arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
10838                     Expression ce = new CallExp(exp.loc, id, arguments);
10839                     res = ce.expressionSemantic(sc);
10840                 }
10841                 else
10842                 {
10843                     Expression e0;
10844                     // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10845                     if (!ae.e2.isLvalue)
10846                     {
10847                         auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
10848                         e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10849                         arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
10850                     }
10851                     else
10852                         arguments.push(ae.e2);
10853 
10854                     Expression ce = new CallExp(exp.loc, id, arguments);
10855                     res = Expression.combine(e0, ce).expressionSemantic(sc);
10856                 }
10857 
10858                 if (global.params.v.verbose)
10859                     message("lowered   %s =>\n          %s", exp.toChars(), res.toChars());
10860             }
10861         }
10862         else if (auto ae = res.isAssignExp())
10863             res = lowerArrayAssign(ae);
10864         else if (auto ce = res.isCommaExp())
10865         {
10866             if (auto ae1 = ce.e1.isAssignExp())
10867                 ce.e1 = lowerArrayAssign(ae1, true);
10868             if (auto ae2 = ce.e2.isAssignExp())
10869                 ce.e2 = lowerArrayAssign(ae2, true);
10870         }
10871 
10872         return setResult(res);
10873     }
10874 
10875     /***************************************
10876      * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
10877      *
10878      * Params:
10879      *      ae = the AssignExp to be lowered
10880      *      fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10881      *                     so no unnecessary temporay variable is created.
10882      * Returns:
10883      *      a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10884      *      if needed or `ae` otherwise
10885      */
10886     private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
10887     {
10888         Type t1b = ae.e1.type.toBasetype();
10889         if (t1b.ty != Tsarray && t1b.ty != Tarray)
10890             return ae;
10891 
10892         const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10893             (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
10894             (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
10895 
10896         const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10897             (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
10898 
10899         if (!isArrayAssign && !isArraySetAssign)
10900             return ae;
10901 
10902         const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10903         if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10904             return ae;
10905 
10906         Expression res;
10907         Identifier func = isArraySetAssign ? Id._d_arraysetassign :
10908             ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
10909 
10910         // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
10911         Expression id = new IdentifierExp(ae.loc, Id.empty);
10912         id = new DotIdExp(ae.loc, id, Id.object);
10913         id = new DotIdExp(ae.loc, id, func);
10914 
10915         auto arguments = new Expressions();
10916         arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
10917             .expressionSemantic(sc));
10918 
10919         Expression eValue2, value2 = ae.e2;
10920         if (isArrayAssign && value2.isLvalue())
10921             value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
10922                 .expressionSemantic(sc);
10923         else if (!fromCommaExp &&
10924             (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
10925         {
10926             // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10927             // and are temporary variables themselves. Rvalues from trivial
10928             // SliceExps are simply passed by reference without any copying.
10929 
10930             // `__assigntmp` will be destroyed together with the array `ae.e1`.
10931             // When `ae.e2` is a variadic arg array, it is also `scope`, so
10932             // `__assigntmp` may also be scope.
10933             StorageClass stc = STC.nodtor;
10934             if (isArrayAssign)
10935                 stc |= STC.rvalue | STC.scope_;
10936 
10937             auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
10938             eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10939             value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
10940         }
10941         arguments.push(value2);
10942 
10943         Expression ce = new CallExp(ae.loc, id, arguments);
10944         res = Expression.combine(eValue2, ce).expressionSemantic(sc);
10945         if (isArrayAssign)
10946             res = Expression.combine(res, ae.e1).expressionSemantic(sc);
10947 
10948         if (global.params.v.verbose)
10949             message("lowered   %s =>\n          %s", ae.toChars(), res.toChars());
10950 
10951         res = new LoweredAssignExp(ae, res);
10952         res.type = ae.type;
10953 
10954         return res;
10955     }
10956 
10957     override void visit(PowAssignExp exp)
10958     {
10959         if (exp.type)
10960         {
10961             result = exp;
10962             return;
10963         }
10964 
10965         Expression e = exp.op_overload(sc);
10966         if (e)
10967         {
10968             result = e;
10969             return;
10970         }
10971 
10972         if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10973             return setError();
10974 
10975         assert(exp.e1.type && exp.e2.type);
10976         if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
10977         {
10978             if (checkNonAssignmentArrayOp(exp.e1))
10979                 return setError();
10980 
10981             // T[] ^^= ...
10982             if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10983             {
10984                 // T[] ^^= T
10985                 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10986             }
10987             else if (Expression ex = typeCombine(exp, sc))
10988             {
10989                 result = ex;
10990                 return;
10991             }
10992 
10993             // Check element types are arithmetic
10994             Type tb1 = exp.e1.type.nextOf().toBasetype();
10995             Type tb2 = exp.e2.type.toBasetype();
10996             if (tb2.ty == Tarray || tb2.ty == Tsarray)
10997                 tb2 = tb2.nextOf().toBasetype();
10998             if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10999             {
11000                 exp.type = exp.e1.type;
11001                 result = arrayOp(exp, sc);
11002                 return;
11003             }
11004         }
11005         else
11006         {
11007             exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
11008         }
11009 
11010         if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
11011         {
11012             Expression e0 = null;
11013             e = exp.reorderSettingAAElem(sc);
11014             e = Expression.extractLast(e, e0);
11015             assert(e == exp);
11016 
11017             if (exp.e1.op == EXP.variable)
11018             {
11019                 // Rewrite: e1 = e1 ^^ e2
11020                 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
11021                 e = new AssignExp(exp.loc, exp.e1, e);
11022             }
11023             else
11024             {
11025                 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
11026                 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
11027                 auto de = new DeclarationExp(exp.e1.loc, v);
11028                 auto ve = new VarExp(exp.e1.loc, v);
11029                 e = new PowExp(exp.loc, ve, exp.e2);
11030                 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
11031                 e = new CommaExp(exp.loc, de, e);
11032             }
11033             e = Expression.combine(e0, e);
11034             e = e.expressionSemantic(sc);
11035             result = e;
11036             return;
11037         }
11038         result = exp.incompatibleTypes();
11039     }
11040 
11041     override void visit(CatAssignExp exp)
11042     {
11043         if (exp.type)
11044         {
11045             result = exp;
11046             return;
11047         }
11048 
11049         //printf("CatAssignExp::semantic() %s\n", exp.toChars());
11050         Expression e = exp.op_overload(sc);
11051         if (e)
11052         {
11053             result = e;
11054             return;
11055         }
11056 
11057         if (SliceExp se = exp.e1.isSliceExp())
11058         {
11059             if (se.e1.type.toBasetype().ty == Tsarray)
11060             {
11061                 error(exp.loc, "cannot append to static array `%s`", se.e1.type.toChars());
11062                 return setError();
11063             }
11064         }
11065 
11066         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
11067         if (exp.e1.op == EXP.error)
11068         {
11069             result = exp.e1;
11070             return;
11071         }
11072         if (exp.e2.op == EXP.error)
11073         {
11074             result = exp.e2;
11075             return;
11076         }
11077 
11078         if (checkNonAssignmentArrayOp(exp.e2))
11079             return setError();
11080 
11081         Type tb1 = exp.e1.type.toBasetype();
11082         Type tb1next = tb1.nextOf();
11083         Type tb2 = exp.e2.type.toBasetype();
11084 
11085         /* Possibilities:
11086          * EXP.concatenateAssign: appending T[] to T[]
11087          * EXP.concatenateElemAssign: appending T to T[]
11088          * EXP.concatenateDcharAssign: appending dchar to T[]
11089          */
11090         if ((tb1.ty == Tarray) &&
11091             (tb2.ty == Tarray || tb2.ty == Tsarray) &&
11092             (exp.e2.implicitConvTo(exp.e1.type) ||
11093              (tb2.nextOf().implicitConvTo(tb1next) &&
11094               (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
11095         {
11096             // EXP.concatenateAssign
11097             assert(exp.op == EXP.concatenateAssign);
11098             if (exp.e1.checkPostblit(sc, tb1next))
11099                 return setError();
11100 
11101             exp.e2 = exp.e2.castTo(sc, exp.e1.type);
11102         }
11103         else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
11104         {
11105             /* https://issues.dlang.org/show_bug.cgi?id=19782
11106              *
11107              * If e2 is implicitly convertible to tb1next, the conversion
11108              * might be done through alias this, in which case, e2 needs to
11109              * be modified accordingly (e2 => e2.aliasthis).
11110              */
11111             if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
11112                 goto Laliasthis;
11113             if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
11114                 goto Laliasthis;
11115             // Append element
11116             if (exp.e2.checkPostblit(sc, tb2))
11117                 return setError();
11118 
11119             if (checkNewEscape(sc, exp.e2, false))
11120                 return setError();
11121 
11122             exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
11123             exp.e2 = doCopyOrMove(sc, exp.e2);
11124         }
11125         else if (tb1.ty == Tarray &&
11126                  (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
11127                  exp.e2.type.ty != tb1next.ty &&
11128                  exp.e2.implicitConvTo(Type.tdchar))
11129         {
11130             // Append dchar to char[] or wchar[]
11131             exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
11132 
11133             /* Do not allow appending wchar to char[] because if wchar happens
11134              * to be a surrogate pair, nothing good can result.
11135              */
11136         }
11137         else
11138         {
11139             // Try alias this on first operand
11140             static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
11141             {
11142                 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
11143                 if (!ad1 || !ad1.aliasthis)
11144                     return null;
11145 
11146                 /* Rewrite (e1 op e2) as:
11147                  *      (e1.aliasthis op e2)
11148                  */
11149                 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
11150                     return null;
11151                 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
11152                 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
11153                 BinExp be = cast(BinExp)exp.copy();
11154                 be.e1 = e1;
11155                 return be.trySemantic(sc);
11156             }
11157 
11158             // Try alias this on second operand
11159             static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
11160             {
11161                 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
11162                 if (!ad2 || !ad2.aliasthis)
11163                     return null;
11164                 /* Rewrite (e1 op e2) as:
11165                  *      (e1 op e2.aliasthis)
11166                  */
11167                 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
11168                     return null;
11169                 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
11170                 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
11171                 BinExp be = cast(BinExp)exp.copy();
11172                 be.e2 = e2;
11173                 return be.trySemantic(sc);
11174             }
11175 
11176     Laliasthis:
11177             result = tryAliasThisForLhs(exp, sc);
11178             if (result)
11179                 return;
11180 
11181             result = tryAliasThisForRhs(exp, sc);
11182             if (result)
11183                 return;
11184 
11185             error(exp.loc, "cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
11186             return setError();
11187         }
11188 
11189         if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
11190             return setError();
11191 
11192         exp.type = exp.e1.type;
11193         auto assignElem = exp.e2;
11194         auto res = exp.reorderSettingAAElem(sc);
11195         if (res != exp) // `AA[k] = v` rewrite was performed
11196             checkNewEscape(sc, assignElem, false);
11197         else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
11198             checkAssignEscape(sc, res, false, false);
11199 
11200         result = res;
11201 
11202         if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
11203             sc.needsCodegen())
11204         {
11205             // if aa ordering is triggered, `res` will be a CommaExp
11206             // and `.e2` will be the rewritten original expression.
11207 
11208             // `output` will point to the expression that the lowering will overwrite
11209             Expression* output;
11210             if (auto comma = res.isCommaExp())
11211             {
11212                 output = &comma.e2;
11213                 // manual cast because it could be either CatAssignExp or CatElemAssignExp
11214                 exp = cast(CatAssignExp)comma.e2;
11215             }
11216             else
11217             {
11218                 output = &result;
11219                 exp = cast(CatAssignExp)result;
11220             }
11221 
11222             if (exp.op == EXP.concatenateAssign)
11223             {
11224                 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
11225 
11226                 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
11227                     return setError();
11228 
11229                 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
11230                 Expression id = new IdentifierExp(exp.loc, Id.empty);
11231                 id = new DotIdExp(exp.loc, id, Id.object);
11232                 id = new DotIdExp(exp.loc, id, hook);
11233 
11234                 auto arguments = new Expressions();
11235                 arguments.reserve(5);
11236                 if (global.params.tracegc)
11237                 {
11238                     auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11239                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11240                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11241                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
11242                 }
11243 
11244                 arguments.push(exp.e1);
11245                 arguments.push(exp.e2);
11246                 Expression ce = new CallExp(exp.loc, id, arguments);
11247                 *output = ce.expressionSemantic(sc);
11248             }
11249             else if (exp.op == EXP.concatenateElemAssign)
11250             {
11251                 /* Do not lower concats to the indices array returned by
11252                  *`static foreach`, as this array is only used at compile-time.
11253                  */
11254                 if (auto ve = exp.e1.isVarExp)
11255                 {
11256                     import core.stdc.ctype : isdigit;
11257                     // The name of the indices array that static foreach loops uses.
11258                     // See dmd.cond.lowerNonArrayAggregate
11259                     enum varName = "__res";
11260                     const(char)[] id = ve.var.ident.toString;
11261                     if (ve.var.storage_class & STC.temp && id.length > varName.length &&
11262                         id[0 .. varName.length] == varName && id[varName.length].isdigit)
11263                         return;
11264                 }
11265 
11266                 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
11267                 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
11268                     return setError();
11269 
11270                 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
11271                 Expression id = new IdentifierExp(exp.loc, Id.empty);
11272                 id = new DotIdExp(exp.loc, id, Id.object);
11273                 auto tiargs = new Objects();
11274                 tiargs.push(exp.e1.type);
11275                 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
11276                 id = new DotIdExp(exp.loc, id, hook);
11277 
11278                 auto arguments = new Expressions();
11279                 arguments.reserve(5);
11280                 if (global.params.tracegc)
11281                 {
11282                     auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11283                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11284                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11285                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
11286                 }
11287 
11288                 Expression eValue1;
11289                 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
11290 
11291                 arguments.push(value1);
11292                 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
11293 
11294                 Expression ce = new CallExp(exp.loc, id, arguments);
11295 
11296                 Expression eValue2;
11297                 Expression value2 = exp.e2;
11298                 if (!value2.isVarExp() && !value2.isConst())
11299                 {
11300                     /* Before the template hook, this check was performed in e2ir.d
11301                      * for expressions like `a ~= a[$-1]`. Here, $ will be modified
11302                      * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
11303                      * a temporary variable.
11304                      */
11305                     value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
11306                     exp.e2 = value2;
11307 
11308                     // `__appendtmp*` will be destroyed together with the array `exp.e1`.
11309                     auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
11310                     vd.storage_class |= STC.nodtor;
11311                     // Be more explicit that this "declaration" is local to the expression
11312                     vd.storage_class |= STC.exptemp;
11313                 }
11314 
11315                 auto ale = new ArrayLengthExp(exp.loc, value1);
11316                 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
11317                 auto ae = new ConstructExp(exp.loc, elem, value2);
11318 
11319                 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
11320                 e0 = Expression.combine(e0, value1);
11321                 e0 = Expression.combine(eValue1, e0);
11322 
11323                 e0 = Expression.combine(eValue2, e0);
11324 
11325                 *output = e0.expressionSemantic(sc);
11326             }
11327         }
11328 
11329     }
11330 
11331     override void visit(AddExp exp)
11332     {
11333         static if (LOGSEMANTIC)
11334         {
11335             printf("AddExp::semantic('%s')\n", exp.toChars());
11336         }
11337         if (exp.type)
11338         {
11339             result = exp;
11340             return;
11341         }
11342 
11343         if (Expression ex = binSemanticProp(exp, sc))
11344         {
11345             result = ex;
11346             return;
11347         }
11348         Expression e = exp.op_overload(sc);
11349         if (e)
11350         {
11351             result = e;
11352             return;
11353         }
11354 
11355         /* ImportC: convert arrays to pointers, functions to pointers to functions
11356          */
11357         exp.e1 = exp.e1.arrayFuncConv(sc);
11358         exp.e2 = exp.e2.arrayFuncConv(sc);
11359 
11360         Type tb1 = exp.e1.type.toBasetype();
11361         Type tb2 = exp.e2.type.toBasetype();
11362 
11363         bool err = false;
11364         if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
11365         {
11366             err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
11367         }
11368         if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
11369         {
11370             err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
11371         }
11372         if (err)
11373             return setError();
11374 
11375         if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
11376         {
11377             result = scaleFactor(exp, sc);
11378             return;
11379         }
11380 
11381         if (tb1.ty == Tpointer && tb2.ty == Tpointer)
11382         {
11383             result = exp.incompatibleTypes();
11384             return;
11385         }
11386 
11387         if (Expression ex = typeCombine(exp, sc))
11388         {
11389             result = ex;
11390             return;
11391         }
11392 
11393         Type tb = exp.type.toBasetype();
11394         if (tb.ty == Tarray || tb.ty == Tsarray)
11395         {
11396             if (!isArrayOpValid(exp))
11397             {
11398                 result = arrayOpInvalidError(exp);
11399                 return;
11400             }
11401             result = exp;
11402             return;
11403         }
11404 
11405         tb1 = exp.e1.type.toBasetype();
11406         if (!target.isVectorOpSupported(tb1, exp.op, tb2))
11407         {
11408             result = exp.incompatibleTypes();
11409             return;
11410         }
11411         if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
11412         {
11413             switch (exp.type.toBasetype().ty)
11414             {
11415             case Tfloat32:
11416             case Timaginary32:
11417                 exp.type = Type.tcomplex32;
11418                 break;
11419 
11420             case Tfloat64:
11421             case Timaginary64:
11422                 exp.type = Type.tcomplex64;
11423                 break;
11424 
11425             case Tfloat80:
11426             case Timaginary80:
11427                 exp.type = Type.tcomplex80;
11428                 break;
11429 
11430             default:
11431                 assert(0);
11432             }
11433         }
11434         result = exp;
11435     }
11436 
11437     override void visit(MinExp exp)
11438     {
11439         static if (LOGSEMANTIC)
11440         {
11441             printf("MinExp::semantic('%s')\n", exp.toChars());
11442         }
11443         if (exp.type)
11444         {
11445             result = exp;
11446             return;
11447         }
11448 
11449         if (Expression ex = binSemanticProp(exp, sc))
11450         {
11451             result = ex;
11452             return;
11453         }
11454         Expression e = exp.op_overload(sc);
11455         if (e)
11456         {
11457             result = e;
11458             return;
11459         }
11460 
11461         /* ImportC: convert arrays to pointers, functions to pointers to functions
11462          */
11463         exp.e1 = exp.e1.arrayFuncConv(sc);
11464         exp.e2 = exp.e2.arrayFuncConv(sc);
11465 
11466         Type t1 = exp.e1.type.toBasetype();
11467         Type t2 = exp.e2.type.toBasetype();
11468 
11469         bool err = false;
11470         if (t1.ty == Tdelegate || t1.isPtrToFunction())
11471         {
11472             err |= exp.e1.checkArithmetic(exp.op) || exp.e1.checkSharedAccess(sc);
11473         }
11474         if (t2.ty == Tdelegate || t2.isPtrToFunction())
11475         {
11476             err |= exp.e2.checkArithmetic(exp.op) || exp.e2.checkSharedAccess(sc);
11477         }
11478         if (err)
11479             return setError();
11480 
11481         if (t1.ty == Tpointer)
11482         {
11483             if (t2.ty == Tpointer)
11484             {
11485                 // https://dlang.org/spec/expression.html#add_expressions
11486                 // "If both operands are pointers, and the operator is -, the pointers are
11487                 // subtracted and the result is divided by the size of the type pointed to
11488                 // by the operands. It is an error if the pointers point to different types."
11489                 Type p1 = t1.nextOf();
11490                 Type p2 = t2.nextOf();
11491 
11492                 if (!p1.equivalent(p2))
11493                 {
11494                     // Deprecation to remain for at least a year, after which this should be
11495                     // changed to an error
11496                     // See https://github.com/dlang/dmd/pull/7332
11497                     deprecation(exp.loc,
11498                         "cannot subtract pointers to different types: `%s` and `%s`.",
11499                         t1.toChars(), t2.toChars());
11500                 }
11501 
11502                 // Need to divide the result by the stride
11503                 // Replace (ptr - ptr) with (ptr - ptr) / stride
11504                 long stride;
11505 
11506                 // make sure pointer types are compatible
11507                 if (Expression ex = typeCombine(exp, sc))
11508                 {
11509                     result = ex;
11510                     return;
11511                 }
11512 
11513                 exp.type = Type.tptrdiff_t;
11514                 stride = t2.nextOf().size();
11515                 if (stride == 0)
11516                 {
11517                     e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
11518                 }
11519                 else if (stride == cast(long)SIZE_INVALID)
11520                     e = ErrorExp.get();
11521                 else
11522                 {
11523                     e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
11524                     e.type = Type.tptrdiff_t;
11525                 }
11526             }
11527             else if (t2.isintegral())
11528                 e = scaleFactor(exp, sc);
11529             else
11530             {
11531                 error(exp.loc, "can't subtract `%s` from pointer", t2.toChars());
11532                 e = ErrorExp.get();
11533             }
11534             result = e;
11535             return;
11536         }
11537         if (t2.ty == Tpointer)
11538         {
11539             exp.type = exp.e2.type;
11540             error(exp.loc, "can't subtract pointer from `%s`", exp.e1.type.toChars());
11541             return setError();
11542         }
11543 
11544         if (Expression ex = typeCombine(exp, sc))
11545         {
11546             result = ex;
11547             return;
11548         }
11549 
11550         Type tb = exp.type.toBasetype();
11551         if (tb.ty == Tarray || tb.ty == Tsarray)
11552         {
11553             if (!isArrayOpValid(exp))
11554             {
11555                 result = arrayOpInvalidError(exp);
11556                 return;
11557             }
11558             result = exp;
11559             return;
11560         }
11561 
11562         t1 = exp.e1.type.toBasetype();
11563         t2 = exp.e2.type.toBasetype();
11564         if (!target.isVectorOpSupported(t1, exp.op, t2))
11565         {
11566             result = exp.incompatibleTypes();
11567             return;
11568         }
11569         if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
11570         {
11571             switch (exp.type.ty)
11572             {
11573             case Tfloat32:
11574             case Timaginary32:
11575                 exp.type = Type.tcomplex32;
11576                 break;
11577 
11578             case Tfloat64:
11579             case Timaginary64:
11580                 exp.type = Type.tcomplex64;
11581                 break;
11582 
11583             case Tfloat80:
11584             case Timaginary80:
11585                 exp.type = Type.tcomplex80;
11586                 break;
11587 
11588             default:
11589                 assert(0);
11590             }
11591         }
11592         result = exp;
11593         return;
11594     }
11595 
11596     /**
11597      * If the given expression is a `CatExp`, the function tries to lower it to
11598      * `_d_arraycatnTX`.
11599      *
11600      * Params:
11601      *      ee = the `CatExp` to lower
11602      * Returns:
11603      *      `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
11604      *      `ee` otherwise
11605      */
11606     private Expression lowerToArrayCat(CatExp exp)
11607     {
11608         // String literals are concatenated by the compiler. No lowering is needed.
11609         if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
11610             (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
11611             return exp;
11612 
11613         bool useTraceGCHook = global.params.tracegc && sc.needsCodegen();
11614 
11615         Identifier hook = useTraceGCHook ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
11616         if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
11617         {
11618             setError();
11619             return result;
11620         }
11621 
11622         void handleCatArgument(Expressions *arguments, Expression e)
11623         {
11624             if (auto ce = e.isCatExp())
11625             {
11626                 Expression lowering = ce.lowering;
11627 
11628                 /* Skip `file`, `line`, and `funcname` if the hook of the parent
11629                  * `CatExp` is `_d_arraycatnTXTrace`.
11630                  */
11631                 if (auto callExp = isRuntimeHook(lowering, hook))
11632                 {
11633                     if (hook == Id._d_arraycatnTX)
11634                         arguments.pushSlice((*callExp.arguments)[]);
11635                     else
11636                         arguments.pushSlice((*callExp.arguments)[3 .. $]);
11637                 }
11638             }
11639             else
11640                 arguments.push(e);
11641         }
11642 
11643         auto arguments = new Expressions();
11644         if (useTraceGCHook)
11645         {
11646             auto funcname = (sc.callsc && sc.callsc.func) ?
11647                 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11648             arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11649             arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11650             arguments.push(new StringExp(exp.loc, funcname.toDString()));
11651         }
11652 
11653         handleCatArgument(arguments, exp.e1);
11654         handleCatArgument(arguments, exp.e2);
11655 
11656         Expression id = new IdentifierExp(exp.loc, Id.empty);
11657         id = new DotIdExp(exp.loc, id, Id.object);
11658 
11659         auto tiargs = new Objects();
11660         tiargs.push(exp.type);
11661         id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
11662         id = new CallExp(exp.loc, id, arguments);
11663         return id.expressionSemantic(sc);
11664     }
11665 
11666     void trySetCatExpLowering(Expression exp)
11667     {
11668         /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
11669          * used with `-betterC`, but only during CTFE.
11670          */
11671         if (!global.params.useGC)
11672             return;
11673 
11674         if (auto ce = exp.isCatExp())
11675             ce.lowering = lowerToArrayCat(ce);
11676     }
11677 
11678     override void visit(CatExp exp)
11679     {
11680         // https://dlang.org/spec/expression.html#cat_expressions
11681         //printf("CatExp.semantic() %s\n", toChars());
11682         if (exp.type)
11683         {
11684             result = exp;
11685             return;
11686         }
11687 
11688         if (Expression ex = binSemanticProp(exp, sc))
11689         {
11690             result = ex;
11691             return;
11692         }
11693         Expression e = exp.op_overload(sc);
11694         if (e)
11695         {
11696             result = e;
11697             return;
11698         }
11699 
11700         Type tb1 = exp.e1.type.toBasetype();
11701         Type tb2 = exp.e2.type.toBasetype();
11702 
11703         auto f1 = checkNonAssignmentArrayOp(exp.e1);
11704         auto f2 = checkNonAssignmentArrayOp(exp.e2);
11705         if (f1 || f2)
11706             return setError();
11707 
11708         Type tb1next = tb1.nextOf();
11709         Type tb2next = tb2.nextOf();
11710 
11711         // Check for: array ~ array
11712         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)))
11713         {
11714             /* https://issues.dlang.org/show_bug.cgi?id=9248
11715              * Here to avoid the case of:
11716              *    void*[] a = [cast(void*)1];
11717              *    void*[] b = [cast(void*)2];
11718              *    a ~ b;
11719              * becoming:
11720              *    a ~ [cast(void*)b];
11721              */
11722 
11723             /* https://issues.dlang.org/show_bug.cgi?id=14682
11724              * Also to avoid the case of:
11725              *    int[][] a;
11726              *    a ~ [];
11727              * becoming:
11728              *    a ~ cast(int[])[];
11729              */
11730             goto Lpeer;
11731         }
11732 
11733         // Check for: array ~ element
11734         if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
11735         {
11736             if (exp.e1.op == EXP.arrayLiteral)
11737             {
11738                 exp.e2 = doCopyOrMove(sc, exp.e2);
11739                 // https://issues.dlang.org/show_bug.cgi?id=14686
11740                 // Postblit call appears in AST, and this is
11741                 // finally translated  to an ArrayLiteralExp in below optimize().
11742             }
11743             else if (exp.e1.op == EXP.string_)
11744             {
11745                 // No postblit call exists on character (integer) value.
11746             }
11747             else
11748             {
11749                 if (exp.e2.checkPostblit(sc, tb2))
11750                     return setError();
11751                 // Postblit call will be done in runtime helper function
11752             }
11753 
11754             if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
11755             {
11756                 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
11757                 exp.type = tb2.arrayOf();
11758                 goto L2elem;
11759             }
11760             if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
11761             {
11762                 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
11763                 exp.type = tb1next.arrayOf();
11764             L2elem:
11765                 if (checkNewEscape(sc, exp.e2, false))
11766                     return setError();
11767                 result = exp.optimize(WANTvalue);
11768                 trySetCatExpLowering(result);
11769                 return;
11770             }
11771         }
11772         // Check for: element ~ array
11773         if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
11774         {
11775             if (exp.e2.op == EXP.arrayLiteral)
11776             {
11777                 exp.e1 = doCopyOrMove(sc, exp.e1);
11778             }
11779             else if (exp.e2.op == EXP.string_)
11780             {
11781             }
11782             else
11783             {
11784                 if (exp.e1.checkPostblit(sc, tb1))
11785                     return setError();
11786             }
11787 
11788             if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
11789             {
11790                 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
11791                 exp.type = tb1.arrayOf();
11792                 goto L1elem;
11793             }
11794             if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
11795             {
11796                 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
11797                 exp.type = tb2next.arrayOf();
11798             L1elem:
11799                 if (checkNewEscape(sc, exp.e1, false))
11800                     return setError();
11801                 result = exp.optimize(WANTvalue);
11802                 trySetCatExpLowering(result);
11803                 return;
11804             }
11805         }
11806 
11807     Lpeer:
11808         if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
11809         {
11810             Type t1 = tb1next.mutableOf().constOf().arrayOf();
11811             Type t2 = tb2next.mutableOf().constOf().arrayOf();
11812             if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
11813                 exp.e1.type = t1;
11814             else
11815                 exp.e1 = exp.e1.castTo(sc, t1);
11816             if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
11817                 exp.e2.type = t2;
11818             else
11819                 exp.e2 = exp.e2.castTo(sc, t2);
11820         }
11821 
11822         if (Expression ex = typeCombine(exp, sc))
11823         {
11824             result = ex;
11825             trySetCatExpLowering(result);
11826             return;
11827         }
11828         exp.type = exp.type.toHeadMutable();
11829 
11830         Type tb = exp.type.toBasetype();
11831         if (tb.ty == Tsarray)
11832             exp.type = tb.nextOf().arrayOf();
11833         if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
11834         {
11835             exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
11836         }
11837         if (Type tbn = tb.nextOf())
11838         {
11839             if (exp.checkPostblit(sc, tbn))
11840                 return setError();
11841         }
11842         Type t1 = exp.e1.type.toBasetype();
11843         Type t2 = exp.e2.type.toBasetype();
11844         if ((t1.ty == Tarray || t1.ty == Tsarray) &&
11845             (t2.ty == Tarray || t2.ty == Tsarray))
11846         {
11847             // Normalize to ArrayLiteralExp or StringExp as far as possible
11848             e = exp.optimize(WANTvalue);
11849         }
11850         else
11851         {
11852             //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11853             result = exp.incompatibleTypes();
11854             return;
11855         }
11856 
11857         result = e;
11858         trySetCatExpLowering(result);
11859     }
11860 
11861     override void visit(MulExp exp)
11862     {
11863         version (none)
11864         {
11865             printf("MulExp::semantic() %s\n", exp.toChars());
11866         }
11867         if (exp.type)
11868         {
11869             result = exp;
11870             return;
11871         }
11872 
11873         if (Expression ex = binSemanticProp(exp, sc))
11874         {
11875             result = ex;
11876             return;
11877         }
11878         Expression e = exp.op_overload(sc);
11879         if (e)
11880         {
11881             result = e;
11882             return;
11883         }
11884 
11885         if (Expression ex = typeCombine(exp, sc))
11886         {
11887             result = ex;
11888             return;
11889         }
11890 
11891         Type tb = exp.type.toBasetype();
11892         if (tb.ty == Tarray || tb.ty == Tsarray)
11893         {
11894             if (!isArrayOpValid(exp))
11895             {
11896                 result = arrayOpInvalidError(exp);
11897                 return;
11898             }
11899             result = exp;
11900             return;
11901         }
11902 
11903         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11904             return setError();
11905 
11906         if (exp.type.isfloating())
11907         {
11908             Type t1 = exp.e1.type;
11909             Type t2 = exp.e2.type;
11910 
11911             if (t1.isreal())
11912             {
11913                 exp.type = t2;
11914             }
11915             else if (t2.isreal())
11916             {
11917                 exp.type = t1;
11918             }
11919             else if (t1.isimaginary())
11920             {
11921                 if (t2.isimaginary())
11922                 {
11923                     switch (t1.toBasetype().ty)
11924                     {
11925                     case Timaginary32:
11926                         exp.type = Type.tfloat32;
11927                         break;
11928 
11929                     case Timaginary64:
11930                         exp.type = Type.tfloat64;
11931                         break;
11932 
11933                     case Timaginary80:
11934                         exp.type = Type.tfloat80;
11935                         break;
11936 
11937                     default:
11938                         assert(0);
11939                     }
11940 
11941                     // iy * iv = -yv
11942                     exp.e1.type = exp.type;
11943                     exp.e2.type = exp.type;
11944                     e = new NegExp(exp.loc, exp);
11945                     e = e.expressionSemantic(sc);
11946                     result = e;
11947                     return;
11948                 }
11949                 else
11950                     exp.type = t2; // t2 is complex
11951             }
11952             else if (t2.isimaginary())
11953             {
11954                 exp.type = t1; // t1 is complex
11955             }
11956         }
11957         else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11958         {
11959             result = exp.incompatibleTypes();
11960             return;
11961         }
11962         result = exp;
11963     }
11964 
11965     override void visit(DivExp exp)
11966     {
11967         if (exp.type)
11968         {
11969             result = exp;
11970             return;
11971         }
11972 
11973         if (Expression ex = binSemanticProp(exp, sc))
11974         {
11975             result = ex;
11976             return;
11977         }
11978         Expression e = exp.op_overload(sc);
11979         if (e)
11980         {
11981             result = e;
11982             return;
11983         }
11984 
11985         if (Expression ex = typeCombine(exp, sc))
11986         {
11987             result = ex;
11988             return;
11989         }
11990 
11991         Type tb = exp.type.toBasetype();
11992         if (tb.ty == Tarray || tb.ty == Tsarray)
11993         {
11994             if (!isArrayOpValid(exp))
11995             {
11996                 result = arrayOpInvalidError(exp);
11997                 return;
11998             }
11999             result = exp;
12000             return;
12001         }
12002 
12003         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12004             return setError();
12005 
12006         if (exp.type.isfloating())
12007         {
12008             Type t1 = exp.e1.type;
12009             Type t2 = exp.e2.type;
12010 
12011             if (t1.isreal())
12012             {
12013                 exp.type = t2;
12014                 if (t2.isimaginary())
12015                 {
12016                     // x/iv = i(-x/v)
12017                     exp.e2.type = t1;
12018                     e = new NegExp(exp.loc, exp);
12019                     e = e.expressionSemantic(sc);
12020                     result = e;
12021                     return;
12022                 }
12023             }
12024             else if (t2.isreal())
12025             {
12026                 exp.type = t1;
12027             }
12028             else if (t1.isimaginary())
12029             {
12030                 if (t2.isimaginary())
12031                 {
12032                     switch (t1.toBasetype().ty)
12033                     {
12034                     case Timaginary32:
12035                         exp.type = Type.tfloat32;
12036                         break;
12037 
12038                     case Timaginary64:
12039                         exp.type = Type.tfloat64;
12040                         break;
12041 
12042                     case Timaginary80:
12043                         exp.type = Type.tfloat80;
12044                         break;
12045 
12046                     default:
12047                         assert(0);
12048                     }
12049                 }
12050                 else
12051                     exp.type = t2; // t2 is complex
12052             }
12053             else if (t2.isimaginary())
12054             {
12055                 exp.type = t1; // t1 is complex
12056             }
12057         }
12058         else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12059         {
12060             result = exp.incompatibleTypes();
12061             return;
12062         }
12063         result = exp;
12064     }
12065 
12066     override void visit(ModExp exp)
12067     {
12068         if (exp.type)
12069         {
12070             result = exp;
12071             return;
12072         }
12073 
12074         if (Expression ex = binSemanticProp(exp, sc))
12075         {
12076             result = ex;
12077             return;
12078         }
12079         Expression e = exp.op_overload(sc);
12080         if (e)
12081         {
12082             result = e;
12083             return;
12084         }
12085 
12086         if (Expression ex = typeCombine(exp, sc))
12087         {
12088             result = ex;
12089             return;
12090         }
12091 
12092         Type tb = exp.type.toBasetype();
12093         if (tb.ty == Tarray || tb.ty == Tsarray)
12094         {
12095             if (!isArrayOpValid(exp))
12096             {
12097                 result = arrayOpInvalidError(exp);
12098                 return;
12099             }
12100             result = exp;
12101             return;
12102         }
12103         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12104         {
12105             result = exp.incompatibleTypes();
12106             return;
12107         }
12108 
12109         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12110             return setError();
12111 
12112         if (exp.type.isfloating())
12113         {
12114             exp.type = exp.e1.type;
12115             if (exp.e2.type.iscomplex())
12116             {
12117                 error(exp.loc, "cannot perform modulo complex arithmetic");
12118                 return setError();
12119             }
12120         }
12121         result = exp;
12122     }
12123 
12124     override void visit(PowExp exp)
12125     {
12126         if (exp.type)
12127         {
12128             result = exp;
12129             return;
12130         }
12131 
12132         //printf("PowExp::semantic() %s\n", toChars());
12133         if (Expression ex = binSemanticProp(exp, sc))
12134         {
12135             result = ex;
12136             return;
12137         }
12138         Expression e = exp.op_overload(sc);
12139         if (e)
12140         {
12141             result = e;
12142             return;
12143         }
12144 
12145         if (Expression ex = typeCombine(exp, sc))
12146         {
12147             result = ex;
12148             return;
12149         }
12150 
12151         Type tb = exp.type.toBasetype();
12152         if (tb.ty == Tarray || tb.ty == Tsarray)
12153         {
12154             if (!isArrayOpValid(exp))
12155             {
12156                 result = arrayOpInvalidError(exp);
12157                 return;
12158             }
12159             result = exp;
12160             return;
12161         }
12162 
12163         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
12164             return setError();
12165 
12166         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12167         {
12168             result = exp.incompatibleTypes();
12169             return;
12170         }
12171 
12172         // First, attempt to fold the expression.
12173         e = exp.optimize(WANTvalue);
12174         if (e.op != EXP.pow)
12175         {
12176             e = e.expressionSemantic(sc);
12177             result = e;
12178             return;
12179         }
12180 
12181         Module mmath = Module.loadStdMath();
12182         if (!mmath)
12183         {
12184             error(e.loc, "`%s` requires `std.math` for `^^` operators", e.toChars());
12185             return setError();
12186         }
12187         e = new ScopeExp(exp.loc, mmath);
12188 
12189         if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
12190         {
12191             // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
12192             e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
12193         }
12194         else
12195         {
12196             // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
12197             e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
12198         }
12199         e = e.expressionSemantic(sc);
12200         result = e;
12201         return;
12202     }
12203 
12204     override void visit(ShlExp exp)
12205     {
12206         //printf("ShlExp::semantic(), type = %p\n", type);
12207         if (exp.type)
12208         {
12209             result = exp;
12210             return;
12211         }
12212 
12213         if (Expression ex = binSemanticProp(exp, sc))
12214         {
12215             result = ex;
12216             return;
12217         }
12218         Expression e = exp.op_overload(sc);
12219         if (e)
12220         {
12221             result = e;
12222             return;
12223         }
12224 
12225         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12226             return setError();
12227 
12228         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12229         {
12230             result = exp.incompatibleTypes();
12231             return;
12232         }
12233         exp.e1 = integralPromotions(exp.e1, sc);
12234         if (exp.e2.type.toBasetype().ty != Tvector)
12235             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12236 
12237         exp.type = exp.e1.type;
12238         result = exp;
12239     }
12240 
12241     override void visit(ShrExp exp)
12242     {
12243         if (exp.type)
12244         {
12245             result = exp;
12246             return;
12247         }
12248 
12249         if (Expression ex = binSemanticProp(exp, sc))
12250         {
12251             result = ex;
12252             return;
12253         }
12254         Expression e = exp.op_overload(sc);
12255         if (e)
12256         {
12257             result = e;
12258             return;
12259         }
12260 
12261         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12262             return setError();
12263 
12264         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12265         {
12266             result = exp.incompatibleTypes();
12267             return;
12268         }
12269         exp.e1 = integralPromotions(exp.e1, sc);
12270         if (exp.e2.type.toBasetype().ty != Tvector)
12271             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12272 
12273         exp.type = exp.e1.type;
12274         result = exp;
12275     }
12276 
12277     override void visit(UshrExp exp)
12278     {
12279         if (exp.type)
12280         {
12281             result = exp;
12282             return;
12283         }
12284 
12285         if (Expression ex = binSemanticProp(exp, sc))
12286         {
12287             result = ex;
12288             return;
12289         }
12290         Expression e = exp.op_overload(sc);
12291         if (e)
12292         {
12293             result = e;
12294             return;
12295         }
12296 
12297         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12298             return setError();
12299 
12300         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
12301         {
12302             result = exp.incompatibleTypes();
12303             return;
12304         }
12305         exp.e1 = integralPromotions(exp.e1, sc);
12306         if (exp.e2.type.toBasetype().ty != Tvector)
12307             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
12308 
12309         exp.type = exp.e1.type;
12310         result = exp;
12311     }
12312 
12313     override void visit(AndExp exp)
12314     {
12315         if (exp.type)
12316         {
12317             result = exp;
12318             return;
12319         }
12320 
12321         if (Expression ex = binSemanticProp(exp, sc))
12322         {
12323             result = ex;
12324             return;
12325         }
12326         Expression e = exp.op_overload(sc);
12327         if (e)
12328         {
12329             result = e;
12330             return;
12331         }
12332 
12333         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12334         {
12335             exp.type = exp.e1.type;
12336             result = exp;
12337             return;
12338         }
12339 
12340         if (Expression ex = typeCombine(exp, sc))
12341         {
12342             result = ex;
12343             return;
12344         }
12345 
12346         Type tb = exp.type.toBasetype();
12347         if (tb.ty == Tarray || tb.ty == Tsarray)
12348         {
12349             if (!isArrayOpValid(exp))
12350             {
12351                 result = arrayOpInvalidError(exp);
12352                 return;
12353             }
12354             result = exp;
12355             return;
12356         }
12357         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12358         {
12359             result = exp.incompatibleTypes();
12360             return;
12361         }
12362         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12363             return setError();
12364 
12365         result = exp;
12366     }
12367 
12368     override void visit(OrExp exp)
12369     {
12370         if (exp.type)
12371         {
12372             result = exp;
12373             return;
12374         }
12375 
12376         if (Expression ex = binSemanticProp(exp, sc))
12377         {
12378             result = ex;
12379             return;
12380         }
12381         Expression e = exp.op_overload(sc);
12382         if (e)
12383         {
12384             result = e;
12385             return;
12386         }
12387 
12388         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12389         {
12390             exp.type = exp.e1.type;
12391             result = exp;
12392             return;
12393         }
12394 
12395         if (Expression ex = typeCombine(exp, sc))
12396         {
12397             result = ex;
12398             return;
12399         }
12400 
12401         Type tb = exp.type.toBasetype();
12402         if (tb.ty == Tarray || tb.ty == Tsarray)
12403         {
12404             if (!isArrayOpValid(exp))
12405             {
12406                 result = arrayOpInvalidError(exp);
12407                 return;
12408             }
12409             result = exp;
12410             return;
12411         }
12412         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12413         {
12414             result = exp.incompatibleTypes();
12415             return;
12416         }
12417         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12418             return setError();
12419 
12420         result = exp;
12421     }
12422 
12423     override void visit(XorExp exp)
12424     {
12425         if (exp.type)
12426         {
12427             result = exp;
12428             return;
12429         }
12430 
12431         if (Expression ex = binSemanticProp(exp, sc))
12432         {
12433             result = ex;
12434             return;
12435         }
12436         Expression e = exp.op_overload(sc);
12437         if (e)
12438         {
12439             result = e;
12440             return;
12441         }
12442 
12443         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
12444         {
12445             exp.type = exp.e1.type;
12446             result = exp;
12447             return;
12448         }
12449 
12450         if (Expression ex = typeCombine(exp, sc))
12451         {
12452             result = ex;
12453             return;
12454         }
12455 
12456         Type tb = exp.type.toBasetype();
12457         if (tb.ty == Tarray || tb.ty == Tsarray)
12458         {
12459             if (!isArrayOpValid(exp))
12460             {
12461                 result = arrayOpInvalidError(exp);
12462                 return;
12463             }
12464             result = exp;
12465             return;
12466         }
12467         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
12468         {
12469             result = exp.incompatibleTypes();
12470             return;
12471         }
12472         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
12473             return setError();
12474 
12475         result = exp;
12476     }
12477 
12478     override void visit(LogicalExp exp)
12479     {
12480         static if (LOGSEMANTIC)
12481         {
12482             printf("LogicalExp::semantic() %s\n", exp.toChars());
12483         }
12484 
12485         if (exp.type)
12486         {
12487             result = exp;
12488             return;
12489         }
12490 
12491         exp.setNoderefOperands();
12492 
12493         Expression e1x = exp.e1.expressionSemantic(sc);
12494 
12495         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12496         if (e1x.op == EXP.type)
12497             e1x = resolveAliasThis(sc, e1x);
12498 
12499         e1x = resolveProperties(sc, e1x);
12500         e1x = e1x.toBoolean(sc);
12501 
12502         if (sc.flags & SCOPE.condition)
12503         {
12504             /* If in static if, don't evaluate e2 if we don't have to.
12505              */
12506             e1x = e1x.optimize(WANTvalue);
12507             if (e1x.toBool().hasValue(exp.op == EXP.orOr))
12508             {
12509                 if (sc.flags & SCOPE.Cfile)
12510                     result = new IntegerExp(exp.op == EXP.orOr);
12511                 else
12512                     result = IntegerExp.createBool(exp.op == EXP.orOr);
12513                 return;
12514             }
12515         }
12516 
12517         CtorFlow ctorflow = sc.ctorflow.clone();
12518         Expression e2x = exp.e2.expressionSemantic(sc);
12519         sc.merge(exp.loc, ctorflow);
12520         ctorflow.freeFieldinit();
12521 
12522         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12523         if (e2x.op == EXP.type)
12524             e2x = resolveAliasThis(sc, e2x);
12525 
12526         e2x = resolveProperties(sc, e2x);
12527 
12528         auto f1 = checkNonAssignmentArrayOp(e1x);
12529         auto f2 = checkNonAssignmentArrayOp(e2x);
12530         if (f1 || f2)
12531             return setError();
12532 
12533         // Unless the right operand is 'void', the expression is converted to 'bool'.
12534         if (e2x.type.ty != Tvoid)
12535             e2x = e2x.toBoolean(sc);
12536 
12537         if (e2x.op == EXP.type || e2x.op == EXP.scope_)
12538         {
12539             error(exp.loc, "`%s` is not an expression", exp.e2.toChars());
12540             return setError();
12541         }
12542         if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
12543         {
12544             result = e1x;
12545             return;
12546         }
12547         if (e2x.op == EXP.error)
12548         {
12549             result = e2x;
12550             return;
12551         }
12552 
12553         // The result type is 'bool', unless the right operand has type 'void'.
12554         if (e2x.type.ty == Tvoid)
12555             exp.type = Type.tvoid;
12556         else
12557             exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12558 
12559         exp.e1 = e1x;
12560         exp.e2 = e2x;
12561         result = exp;
12562     }
12563 
12564 
12565     override void visit(CmpExp exp)
12566     {
12567         static if (LOGSEMANTIC)
12568         {
12569             printf("CmpExp::semantic('%s')\n", exp.toChars());
12570         }
12571         if (exp.type)
12572         {
12573             result = exp;
12574             return;
12575         }
12576 
12577         exp.setNoderefOperands();
12578 
12579         if (Expression ex = binSemanticProp(exp, sc))
12580         {
12581             result = ex;
12582             return;
12583         }
12584         Type t1 = exp.e1.type.toBasetype();
12585         Type t2 = exp.e2.type.toBasetype();
12586         if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
12587         {
12588             error(exp.loc, "do not use `null` when comparing class types");
12589             return setError();
12590         }
12591 
12592 
12593         EXP cmpop = exp.op;
12594         if (auto e = exp.op_overload(sc, &cmpop))
12595         {
12596             if (!e.type.isscalar() && e.type.equals(exp.e1.type))
12597             {
12598                 error(exp.loc, "recursive `opCmp` expansion");
12599                 return setError();
12600             }
12601             if (e.op == EXP.call)
12602             {
12603 
12604                 if (t1.ty == Tclass && t2.ty == Tclass)
12605                 {
12606                     // Lower to object.__cmp(e1, e2)
12607                     Expression cl = new IdentifierExp(exp.loc, Id.empty);
12608                     cl = new DotIdExp(exp.loc, cl, Id.object);
12609                     cl = new DotIdExp(exp.loc, cl, Id.__cmp);
12610                     cl = cl.expressionSemantic(sc);
12611 
12612                     auto arguments = new Expressions();
12613                     // Check if op_overload found a better match by calling e2.opCmp(e1)
12614                     // If the operands were swapped, then the result must be reversed
12615                     // e1.opCmp(e2) == -e2.opCmp(e1)
12616                     // cmpop takes care of this
12617                     if (exp.op == cmpop)
12618                     {
12619                         arguments.push(exp.e1);
12620                         arguments.push(exp.e2);
12621                     }
12622                     else
12623                     {
12624                         // Use better match found by op_overload
12625                         arguments.push(exp.e2);
12626                         arguments.push(exp.e1);
12627                     }
12628 
12629                     cl = new CallExp(exp.loc, cl, arguments);
12630                     cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
12631                     result = cl.expressionSemantic(sc);
12632                     return;
12633                 }
12634 
12635                 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
12636                 e = e.expressionSemantic(sc);
12637             }
12638             result = e;
12639             return;
12640         }
12641 
12642 
12643         if (Expression ex = typeCombine(exp, sc))
12644         {
12645             result = ex;
12646             return;
12647         }
12648 
12649         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12650         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12651         if (f1 || f2)
12652             return setError();
12653 
12654         exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12655 
12656         // Special handling for array comparisons
12657         Expression arrayLowering = null;
12658         t1 = exp.e1.type.toBasetype();
12659         t2 = exp.e2.type.toBasetype();
12660         if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
12661         {
12662             Type t1next = t1.nextOf();
12663             Type t2next = t2.nextOf();
12664             if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
12665             {
12666                 error(exp.loc, "array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
12667                 return setError();
12668             }
12669 
12670             if ((t1.ty == Tarray || t1.ty == Tsarray) &&
12671                 (t2.ty == Tarray || t2.ty == Tsarray))
12672             {
12673                 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
12674                     return setError();
12675 
12676                 // Lower to object.__cmp(e1, e2)
12677                 Expression al = new IdentifierExp(exp.loc, Id.empty);
12678                 al = new DotIdExp(exp.loc, al, Id.object);
12679                 al = new DotIdExp(exp.loc, al, Id.__cmp);
12680                 al = al.expressionSemantic(sc);
12681 
12682                 auto arguments = new Expressions(2);
12683                 (*arguments)[0] = exp.e1;
12684                 (*arguments)[1] = exp.e2;
12685 
12686                 al = new CallExp(exp.loc, al, arguments);
12687                 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
12688 
12689                 arrayLowering = al;
12690             }
12691         }
12692         else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
12693         {
12694             if (t2.ty == Tstruct)
12695                 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
12696             else
12697                 error(exp.loc, "need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
12698             return setError();
12699         }
12700         else if (t1.iscomplex() || t2.iscomplex())
12701         {
12702             error(exp.loc, "compare not defined for complex operands");
12703             return setError();
12704         }
12705         else if (t1.ty == Taarray || t2.ty == Taarray)
12706         {
12707             error(exp.loc, "`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
12708             return setError();
12709         }
12710         else if (!target.isVectorOpSupported(t1, exp.op, t2))
12711         {
12712             result = exp.incompatibleTypes();
12713             return;
12714         }
12715         else
12716         {
12717             bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
12718             bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
12719             if (r1 || r2)
12720                 return setError();
12721         }
12722 
12723         //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12724         if (arrayLowering)
12725         {
12726             arrayLowering = arrayLowering.expressionSemantic(sc);
12727             result = arrayLowering;
12728             return;
12729         }
12730 
12731         if (auto tv = t1.isTypeVector())
12732             exp.type = tv.toBooleanVector();
12733 
12734         result = exp;
12735         return;
12736     }
12737 
12738     override void visit(InExp exp)
12739     {
12740         if (exp.type)
12741         {
12742             result = exp;
12743             return;
12744         }
12745 
12746         if (Expression ex = binSemanticProp(exp, sc))
12747         {
12748             result = ex;
12749             return;
12750         }
12751         Expression e = exp.op_overload(sc);
12752         if (e)
12753         {
12754             result = e;
12755             return;
12756         }
12757 
12758         Type t2b = exp.e2.type.toBasetype();
12759         switch (t2b.ty)
12760         {
12761         case Taarray:
12762             {
12763                 TypeAArray ta = cast(TypeAArray)t2b;
12764 
12765                 // Special handling for array keys
12766                 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
12767                 {
12768                     // Convert key to type of key
12769                     exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
12770                 }
12771 
12772                 semanticTypeInfo(sc, ta.index);
12773 
12774                 // Return type is pointer to value
12775                 exp.type = ta.nextOf().pointerTo();
12776                 break;
12777             }
12778 
12779         case Terror:
12780             return setError();
12781 
12782         case Tarray, Tsarray:
12783             result = exp.incompatibleTypes();
12784             errorSupplemental(exp.loc, "`in` is only allowed on associative arrays");
12785             const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
12786             errorSupplemental(exp.loc, "perhaps use `std.algorithm.find(%s, %s%s)` instead",
12787                 exp.e1.toChars(), exp.e2.toChars(), slice);
12788             return;
12789 
12790         default:
12791             result = exp.incompatibleTypes();
12792             return;
12793         }
12794         result = exp;
12795     }
12796 
12797     override void visit(RemoveExp e)
12798     {
12799         if (Expression ex = binSemantic(e, sc))
12800         {
12801             result = ex;
12802             return;
12803         }
12804         result = e;
12805     }
12806 
12807     override void visit(EqualExp exp)
12808     {
12809         //printf("EqualExp::semantic('%s')\n", exp.toChars());
12810         if (exp.type)
12811         {
12812             result = exp;
12813             return;
12814         }
12815 
12816         exp.setNoderefOperands();
12817 
12818         if (auto e = binSemanticProp(exp, sc))
12819         {
12820             result = e;
12821             return;
12822         }
12823         if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12824         {
12825             /* https://issues.dlang.org/show_bug.cgi?id=12520
12826              * empty tuples are represented as types so special cases are added
12827              * so that they can be compared for equality with tuples of values.
12828              */
12829             static auto extractTypeTupAndExpTup(Expression e)
12830             {
12831                 static struct Result { bool ttEmpty; bool te; }
12832                 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
12833                 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
12834             }
12835             auto tups1 = extractTypeTupAndExpTup(exp.e1);
12836             auto tups2 = extractTypeTupAndExpTup(exp.e2);
12837             // AliasSeq!() == AliasSeq!(<at least a value>)
12838             if (tups1.ttEmpty && tups2.te)
12839             {
12840                 result = IntegerExp.createBool(exp.op != EXP.equal);
12841                 return;
12842             }
12843             // AliasSeq!(<at least a value>) == AliasSeq!()
12844             else if (tups1.te && tups2.ttEmpty)
12845             {
12846                 result = IntegerExp.createBool(exp.op != EXP.equal);
12847                 return;
12848             }
12849             // AliasSeq!() == AliasSeq!()
12850             else if (tups1.ttEmpty && tups2.ttEmpty)
12851             {
12852                 result = IntegerExp.createBool(exp.op == EXP.equal);
12853                 return;
12854             }
12855             // otherwise, two types are really not comparable
12856             result = exp.incompatibleTypes();
12857             return;
12858         }
12859 
12860         {
12861             auto t1 = exp.e1.type;
12862             auto t2 = exp.e2.type;
12863             if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
12864                 error(exp.loc, "comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
12865                     t1.toChars(), t2.toChars());
12866         }
12867 
12868         /* Before checking for operator overloading, check to see if we're
12869          * comparing the addresses of two statics. If so, we can just see
12870          * if they are the same symbol.
12871          */
12872         if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
12873         {
12874             AddrExp ae1 = cast(AddrExp)exp.e1;
12875             AddrExp ae2 = cast(AddrExp)exp.e2;
12876             if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
12877             {
12878                 VarExp ve1 = cast(VarExp)ae1.e1;
12879                 VarExp ve2 = cast(VarExp)ae2.e1;
12880                 if (ve1.var == ve2.var)
12881                 {
12882                     // They are the same, result is 'true' for ==, 'false' for !=
12883                     result = IntegerExp.createBool(exp.op == EXP.equal);
12884                     return;
12885                 }
12886             }
12887         }
12888 
12889         Type t1 = exp.e1.type.toBasetype();
12890         Type t2 = exp.e2.type.toBasetype();
12891 
12892         // Indicates whether the comparison of the 2 specified array types
12893         // requires an object.__equals() lowering.
12894         static bool needsDirectEq(Type t1, Type t2, Scope* sc)
12895         {
12896             Type t1n = t1.nextOf().toBasetype();
12897             Type t2n = t2.nextOf().toBasetype();
12898             if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
12899                 (t1n.ty == Tvoid || t2n.ty == Tvoid))
12900             {
12901                 return false;
12902             }
12903             if (t1n.constOf() != t2n.constOf())
12904                 return true;
12905 
12906             Type t = t1n;
12907             while (t.toBasetype().nextOf())
12908                 t = t.nextOf().toBasetype();
12909             if (auto ts = t.isTypeStruct())
12910             {
12911                 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12912                 if (global.params.useTypeInfo && Type.dtypeinfo)
12913                     semanticTypeInfo(sc, ts);
12914 
12915                 return ts.sym.hasIdentityEquals; // has custom opEquals
12916             }
12917 
12918             return false;
12919         }
12920 
12921         if (auto e = exp.op_overload(sc))
12922         {
12923             result = e;
12924             return;
12925         }
12926 
12927 
12928         const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
12929                                   (t2.ty == Tarray || t2.ty == Tsarray);
12930         const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
12931 
12932         if (!needsArrayLowering)
12933         {
12934             // https://issues.dlang.org/show_bug.cgi?id=23783
12935             if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
12936                 return setError();
12937             if (auto e = typeCombine(exp, sc))
12938             {
12939                 result = e;
12940                 return;
12941             }
12942         }
12943 
12944         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12945         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12946         if (f1 || f2)
12947             return setError();
12948 
12949         exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12950 
12951         if (!isArrayComparison)
12952         {
12953             if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12954             {
12955                 // Cast both to complex
12956                 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12957                 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12958             }
12959         }
12960 
12961         // lower some array comparisons to object.__equals(e1, e2)
12962         if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
12963         {
12964             //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12965 
12966             // https://issues.dlang.org/show_bug.cgi?id=22390
12967             // Equality comparison between array of noreturns simply lowers to length equality comparison
12968             if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
12969             {
12970                 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
12971                 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
12972                 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
12973                 result = e.expressionSemantic(sc);
12974                 return;
12975             }
12976 
12977             if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12978                 return setError();
12979 
12980             Expression __equals = new IdentifierExp(exp.loc, Id.empty);
12981             Identifier id = Identifier.idPool("__equals");
12982             __equals = new DotIdExp(exp.loc, __equals, Id.object);
12983             __equals = new DotIdExp(exp.loc, __equals, id);
12984 
12985             /* https://issues.dlang.org/show_bug.cgi?id=23674
12986              *
12987              * Optimize before creating the call expression to the
12988              * druntime hook as the optimizer may output errors
12989              * that will get swallowed otherwise.
12990              */
12991             exp.e1 = exp.e1.optimize(WANTvalue);
12992             exp.e2 = exp.e2.optimize(WANTvalue);
12993 
12994             auto arguments = new Expressions(2);
12995             (*arguments)[0] = exp.e1;
12996             (*arguments)[1] = exp.e2;
12997 
12998             __equals = new CallExp(exp.loc, __equals, arguments);
12999             if (exp.op == EXP.notEqual)
13000             {
13001                 __equals = new NotExp(exp.loc, __equals);
13002             }
13003             __equals = __equals.trySemantic(sc); // for better error message
13004             if (!__equals)
13005             {
13006                 error(exp.loc, "incompatible types for array comparison: `%s` and `%s`",
13007                           exp.e1.type.toChars(), exp.e2.type.toChars());
13008                 __equals = ErrorExp.get();
13009             }
13010 
13011             result = __equals;
13012             return;
13013         }
13014 
13015         if (exp.e1.type.toBasetype().ty == Taarray)
13016             semanticTypeInfo(sc, exp.e1.type.toBasetype());
13017 
13018 
13019         if (!target.isVectorOpSupported(t1, exp.op, t2))
13020         {
13021             result = exp.incompatibleTypes();
13022             return;
13023         }
13024 
13025         if (auto tv = t1.isTypeVector())
13026             exp.type = tv.toBooleanVector();
13027 
13028         result = exp;
13029     }
13030 
13031     override void visit(IdentityExp exp)
13032     {
13033         if (exp.type)
13034         {
13035             result = exp;
13036             return;
13037         }
13038 
13039         exp.setNoderefOperands();
13040 
13041         if (auto e = binSemanticProp(exp, sc))
13042         {
13043             result = e;
13044             return;
13045         }
13046 
13047         if (auto e = typeCombine(exp, sc))
13048         {
13049             result = e;
13050             return;
13051         }
13052 
13053         auto f1 = checkNonAssignmentArrayOp(exp.e1);
13054         auto f2 = checkNonAssignmentArrayOp(exp.e2);
13055         if (f1 || f2)
13056             return setError();
13057 
13058         if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
13059         {
13060             result = exp.incompatibleTypes();
13061             return;
13062         }
13063 
13064         exp.type = Type.tbool;
13065 
13066         if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
13067         {
13068             // Cast both to complex
13069             exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
13070             exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
13071         }
13072 
13073         auto tb1 = exp.e1.type.toBasetype();
13074         auto tb2 = exp.e2.type.toBasetype();
13075         if (!target.isVectorOpSupported(tb1, exp.op, tb2))
13076         {
13077             result = exp.incompatibleTypes();
13078             return;
13079         }
13080 
13081         if (exp.e1.op == EXP.call)
13082             exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
13083         if (exp.e2.op == EXP.call)
13084             exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
13085 
13086         if (exp.e1.type.toBasetype().ty == Tsarray ||
13087             exp.e2.type.toBasetype().ty == Tsarray)
13088             deprecation(exp.loc, "identity comparison of static arrays "
13089                 ~ "implicitly coerces them to slices, "
13090                 ~ "which are compared by reference");
13091 
13092         result = exp;
13093     }
13094 
13095     override void visit(CondExp exp)
13096     {
13097         static if (LOGSEMANTIC)
13098         {
13099             printf("CondExp::semantic('%s')\n", exp.toChars());
13100         }
13101         if (exp.type)
13102         {
13103             result = exp;
13104             return;
13105         }
13106 
13107         if (auto die = exp.econd.isDotIdExp())
13108             die.noderef = true;
13109 
13110         Expression ec = exp.econd.expressionSemantic(sc);
13111         ec = resolveProperties(sc, ec);
13112         ec = ec.toBoolean(sc);
13113 
13114         CtorFlow ctorflow_root = sc.ctorflow.clone();
13115         Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
13116         e1x = resolveProperties(sc, e1x);
13117 
13118         CtorFlow ctorflow1 = sc.ctorflow;
13119         sc.ctorflow = ctorflow_root;
13120         Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
13121         e2x = resolveProperties(sc, e2x);
13122 
13123         sc.merge(exp.loc, ctorflow1);
13124         ctorflow1.freeFieldinit();
13125 
13126         if (ec.op == EXP.error)
13127         {
13128             result = ec;
13129             return;
13130         }
13131         if (ec.type == Type.terror)
13132             return setError();
13133         exp.econd = ec;
13134 
13135         if (e1x.op == EXP.error)
13136         {
13137             result = e1x;
13138             return;
13139         }
13140         if (e1x.type == Type.terror)
13141             return setError();
13142         exp.e1 = e1x;
13143 
13144         if (e2x.op == EXP.error)
13145         {
13146             result = e2x;
13147             return;
13148         }
13149         if (e2x.type == Type.terror)
13150             return setError();
13151         exp.e2 = e2x;
13152 
13153         auto f0 = checkNonAssignmentArrayOp(exp.econd);
13154         auto f1 = checkNonAssignmentArrayOp(exp.e1);
13155         auto f2 = checkNonAssignmentArrayOp(exp.e2);
13156         if (f0 || f1 || f2)
13157             return setError();
13158 
13159         Type t1 = exp.e1.type;
13160         Type t2 = exp.e2.type;
13161 
13162         // https://issues.dlang.org/show_bug.cgi?id=23767
13163         // `cast(void*) 0` should be treated as `null` so the ternary expression
13164         // gets the pointer type of the other branch
13165         if (sc.flags & SCOPE.Cfile)
13166         {
13167             static void rewriteCNull(ref Expression e, ref Type t)
13168             {
13169                 if (!t.isTypePointer())
13170                     return;
13171                 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
13172                 {
13173                     if (ie.getInteger() == 0)
13174                     {
13175                         e = new NullExp(e.loc, Type.tnull);
13176                         t = Type.tnull;
13177                     }
13178                 }
13179             }
13180             rewriteCNull(exp.e1, t1);
13181             rewriteCNull(exp.e2, t2);
13182         }
13183 
13184         if (t1.ty == Tnoreturn)
13185         {
13186             exp.type = t2;
13187             exp.e1 = specialNoreturnCast(exp.e1, exp.type);
13188         }
13189         else if (t2.ty == Tnoreturn)
13190         {
13191             exp.type = t1;
13192             exp.e2 = specialNoreturnCast(exp.e2, exp.type);
13193         }
13194         // If either operand is void the result is void, we have to cast both
13195         // the expression to void so that we explicitly discard the expression
13196         // value if any
13197         // https://issues.dlang.org/show_bug.cgi?id=16598
13198         else if (t1.ty == Tvoid || t2.ty == Tvoid)
13199         {
13200             exp.type = Type.tvoid;
13201             exp.e1 = exp.e1.castTo(sc, exp.type);
13202             exp.e2 = exp.e2.castTo(sc, exp.type);
13203         }
13204         else if (t1 == t2)
13205             exp.type = t1;
13206         else
13207         {
13208             if (Expression ex = typeCombine(exp, sc))
13209             {
13210                 result = ex;
13211                 return;
13212             }
13213 
13214             switch (exp.e1.type.toBasetype().ty)
13215             {
13216             case Tcomplex32:
13217             case Tcomplex64:
13218             case Tcomplex80:
13219                 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
13220                 break;
13221             default:
13222                 break;
13223             }
13224             switch (exp.e2.type.toBasetype().ty)
13225             {
13226             case Tcomplex32:
13227             case Tcomplex64:
13228             case Tcomplex80:
13229                 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
13230                 break;
13231             default:
13232                 break;
13233             }
13234             if (exp.type.toBasetype().ty == Tarray)
13235             {
13236                 exp.e1 = exp.e1.castTo(sc, exp.type);
13237                 exp.e2 = exp.e2.castTo(sc, exp.type);
13238             }
13239         }
13240         exp.type = exp.type.merge2();
13241         version (none)
13242         {
13243             printf("res: %s\n", exp.type.toChars());
13244             printf("e1 : %s\n", exp.e1.type.toChars());
13245             printf("e2 : %s\n", exp.e2.type.toChars());
13246         }
13247 
13248         /* https://issues.dlang.org/show_bug.cgi?id=14696
13249          * If either e1 or e2 contain temporaries which need dtor,
13250          * make them conditional.
13251          * Rewrite:
13252          *      cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
13253          * to:
13254          *      (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
13255          * and replace edtors of __tmp1 and __tmp2 with:
13256          *      __tmp1.edtor --> __cond && __tmp1.dtor()
13257          *      __tmp2.edtor --> __cond || __tmp2.dtor()
13258          */
13259         exp.hookDtors(sc);
13260 
13261         result = exp;
13262     }
13263 
13264     override void visit(GenericExp exp)
13265     {
13266         static if (LOGSEMANTIC)
13267         {
13268             printf("GenericExp::semantic('%s')\n", exp.toChars());
13269         }
13270         // C11 6.5.1.1 Generic Selection
13271 
13272         auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
13273         bool errors = ec.isErrorExp() !is null;
13274         auto tc = ec.type;
13275 
13276         auto types = (*exp.types)[];
13277         foreach (i, ref t; types)
13278         {
13279             if (!t)
13280                 continue;       // `default:` case
13281             t = t.typeSemantic(ec.loc, sc);
13282             if (t.isTypeError())
13283             {
13284                 errors = true;
13285                 continue;
13286             }
13287 
13288             /* C11 6.5.1-2 duplicate check
13289              */
13290             /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
13291              * C target, a long may have the same type as `int` in the D type system.
13292              * So, skip checks when this may be the case. Later pick the first match
13293              */
13294             if (
13295                 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
13296                 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
13297                 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
13298                )
13299                 continue;
13300 
13301             foreach (t2; types[0 .. i])
13302             {
13303                 if (t2 && t2.equals(t))
13304                 {
13305                     error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
13306                     errors = true;
13307                     break;
13308                 }
13309             }
13310         }
13311 
13312         auto exps = (*exp.exps)[];
13313         foreach (ref e; exps)
13314         {
13315             e = e.expressionSemantic(sc);
13316             if (e.isErrorExp())
13317                 errors = true;
13318         }
13319 
13320         if (errors)
13321             return setError();
13322 
13323         enum size_t None = ~0;
13324         size_t imatch = None;
13325         size_t idefault = None;
13326         foreach (const i, t; types)
13327         {
13328             if (t)
13329             {
13330                 /* if tc is compatible with t, it's a match
13331                  * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
13332                  */
13333                 if (tc.equals(t))
13334                 {
13335                     assert(imatch == None);
13336                     imatch = i;
13337                     break;              // pick first match
13338                 }
13339             }
13340             else
13341                 idefault = i;  // multiple defaults are not allowed, and are caught by cparse
13342         }
13343 
13344         if (imatch == None)
13345             imatch = idefault;
13346         if (imatch == None)
13347         {
13348             error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
13349             return setError();
13350         }
13351 
13352         result = exps[imatch];
13353     }
13354 
13355     override void visit(FileInitExp e)
13356     {
13357         //printf("FileInitExp::semantic()\n");
13358         e.type = Type.tstring;
13359         result = e;
13360     }
13361 
13362     override void visit(LineInitExp e)
13363     {
13364         e.type = Type.tint32;
13365         result = e;
13366     }
13367 
13368     override void visit(ModuleInitExp e)
13369     {
13370         //printf("ModuleInitExp::semantic()\n");
13371         e.type = Type.tstring;
13372         result = e;
13373     }
13374 
13375     override void visit(FuncInitExp e)
13376     {
13377         //printf("FuncInitExp::semantic()\n");
13378         e.type = Type.tstring;
13379         if (sc.func)
13380         {
13381             result = e.resolveLoc(Loc.initial, sc);
13382             return;
13383         }
13384         result = e;
13385     }
13386 
13387     override void visit(PrettyFuncInitExp e)
13388     {
13389         //printf("PrettyFuncInitExp::semantic()\n");
13390         e.type = Type.tstring;
13391         if (sc.func)
13392         {
13393             result = e.resolveLoc(Loc.initial, sc);
13394             return;
13395         }
13396 
13397         result = e;
13398     }
13399 }
13400 
13401 /**********************************
13402  * Try to run semantic routines.
13403  * If they fail, return NULL.
13404  */
13405 Expression trySemantic(Expression exp, Scope* sc)
13406 {
13407     //printf("+trySemantic(%s)\n", exp.toChars());
13408     uint errors = global.startGagging();
13409     Expression e = expressionSemantic(exp, sc);
13410     if (global.endGagging(errors))
13411     {
13412         e = null;
13413     }
13414     //printf("-trySemantic(%s)\n", exp.toChars());
13415     return e;
13416 }
13417 
13418 /**************************
13419  * Helper function for easy error propagation.
13420  * If error occurs, returns ErrorExp. Otherwise returns NULL.
13421  */
13422 Expression unaSemantic(UnaExp e, Scope* sc)
13423 {
13424     static if (LOGSEMANTIC)
13425     {
13426         printf("UnaExp::semantic('%s')\n", e.toChars());
13427     }
13428     Expression e1x = e.e1.expressionSemantic(sc);
13429     if (e1x.op == EXP.error)
13430         return e1x;
13431     e.e1 = e1x;
13432     return null;
13433 }
13434 
13435 /**************************
13436  * Helper function for easy error propagation.
13437  * If error occurs, returns ErrorExp. Otherwise returns NULL.
13438  */
13439 Expression binSemantic(BinExp e, Scope* sc)
13440 {
13441     static if (LOGSEMANTIC)
13442     {
13443         printf("BinExp::semantic('%s')\n", e.toChars());
13444     }
13445     Expression e1x = e.e1.expressionSemantic(sc);
13446     Expression e2x = e.e2.expressionSemantic(sc);
13447 
13448     // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
13449     if (e1x.op == EXP.type)
13450         e1x = resolveAliasThis(sc, e1x);
13451     if (e2x.op == EXP.type)
13452         e2x = resolveAliasThis(sc, e2x);
13453 
13454     if (e1x.op == EXP.error)
13455         return e1x;
13456     if (e2x.op == EXP.error)
13457         return e2x;
13458     e.e1 = e1x;
13459     e.e2 = e2x;
13460     return null;
13461 }
13462 
13463 Expression binSemanticProp(BinExp e, Scope* sc)
13464 {
13465     if (Expression ex = binSemantic(e, sc))
13466         return ex;
13467     Expression e1x = resolveProperties(sc, e.e1);
13468     Expression e2x = resolveProperties(sc, e.e2);
13469     if (e1x.op == EXP.error)
13470         return e1x;
13471     if (e2x.op == EXP.error)
13472         return e2x;
13473     e.e1 = e1x;
13474     e.e2 = e2x;
13475     return null;
13476 }
13477 
13478 // entrypoint for semantic ExpressionSemanticVisitor
13479 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
13480 {
13481     scope v = new ExpressionSemanticVisitor(sc);
13482     e.accept(v);
13483     return v.result;
13484 }
13485 
13486 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
13487 {
13488     //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
13489     if (Expression ex = unaSemantic(exp, sc))
13490         return ex;
13491 
13492     if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
13493     {
13494         // symbol.mangleof
13495 
13496         // return mangleof as an Expression
13497         static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
13498         {
13499             assert(ds);
13500             if (auto f = ds.isFuncDeclaration())
13501             {
13502                 if (f.checkForwardRef(loc))
13503                     return ErrorExp.get();
13504 
13505                 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
13506                 {
13507                     error(loc, "%s `%s` cannot retrieve its `.mangleof` while inferring attributes", f.kind, f.toPrettyChars);
13508                     return ErrorExp.get();
13509                 }
13510             }
13511             OutBuffer buf;
13512             mangleToBuffer(ds, buf);
13513             Expression e = new StringExp(loc, buf.extractSlice());
13514             return e.expressionSemantic(sc);
13515         }
13516 
13517         Dsymbol ds;
13518         switch (exp.e1.op)
13519         {
13520             case EXP.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
13521             case EXP.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
13522             case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
13523             case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
13524             case EXP.template_:
13525             {
13526                 TemplateExp te = exp.e1.isTemplateExp();
13527                 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
13528             }
13529 
13530             default:
13531                 break;
13532         }
13533     }
13534 
13535     if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
13536     {
13537         // bypass checkPurity
13538         return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
13539     }
13540 
13541     if (!exp.e1.isDotExp())
13542     {
13543         exp.e1 = resolvePropertiesX(sc, exp.e1);
13544     }
13545 
13546     if (auto te = exp.e1.isTupleExp())
13547     {
13548         if (exp.ident == Id.offsetof)
13549         {
13550             /* 'distribute' the .offsetof to each of the tuple elements.
13551              */
13552             auto exps = new Expressions(te.exps.length);
13553             foreach (i, e; (*te.exps)[])
13554             {
13555                 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
13556             }
13557             // Don't evaluate te.e0 in runtime
13558             Expression e = new TupleExp(exp.loc, null, exps);
13559             e = e.expressionSemantic(sc);
13560             return e;
13561         }
13562         if (exp.ident == Id.length)
13563         {
13564             // Don't evaluate te.e0 in runtime
13565             return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
13566         }
13567     }
13568 
13569     // https://issues.dlang.org/show_bug.cgi?id=14416
13570     // Template has no built-in properties except for 'stringof'.
13571     if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
13572     {
13573         error(exp.loc, "template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
13574         return ErrorExp.get();
13575     }
13576     if (!exp.e1.type)
13577     {
13578         error(exp.loc, "expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
13579         return ErrorExp.get();
13580     }
13581 
13582     return exp;
13583 }
13584 
13585 /******************************
13586  * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
13587  * Params:
13588  *      exp = expression to resolve
13589  *      sc = context
13590  *      gag = do not emit error messages, just return `null`
13591  * Returns:
13592  *      resolved expression, null if error
13593  */
13594 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
13595 {
13596     //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
13597 
13598     //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
13599 
13600     const cfile = (sc.flags & SCOPE.Cfile) != 0;
13601 
13602     /* Special case: rewrite this.id and super.id
13603      * to be classtype.id and baseclasstype.id
13604      * if we have no this pointer.
13605      */
13606     if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
13607     {
13608         if (AggregateDeclaration ad = sc.getStructClassScope())
13609         {
13610             if (exp.e1.isThisExp())
13611             {
13612                 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
13613             }
13614             else
13615             {
13616                 if (auto cd = ad.isClassDeclaration())
13617                 {
13618                     if (cd.baseClass)
13619                         exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
13620                 }
13621             }
13622         }
13623     }
13624 
13625     {
13626         Expression e = dotIdSemanticPropX(exp, sc);
13627         if (e != exp)
13628             return e;
13629     }
13630 
13631     Expression eleft;
13632     Expression eright;
13633     if (auto de = exp.e1.isDotExp())
13634     {
13635         eleft = de.e1;
13636         eright = de.e2;
13637     }
13638     else
13639     {
13640         eleft = null;
13641         eright = exp.e1;
13642     }
13643 
13644     Type t1b = exp.e1.type.toBasetype();
13645 
13646     if (auto ie = eright.isScopeExp()) // also used for template alias's
13647     {
13648         auto flags = SearchLocalsOnly;
13649         /* Disable access to another module's private imports.
13650          * The check for 'is sds our current module' is because
13651          * the current module should have access to its own imports.
13652          */
13653         if (ie.sds.isModule() && ie.sds != sc._module)
13654             flags |= IgnorePrivateImports;
13655         if (sc.flags & SCOPE.ignoresymbolvisibility)
13656             flags |= IgnoreSymbolVisibility;
13657         Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
13658         /* Check for visibility before resolving aliases because public
13659          * aliases to private symbols are public.
13660          */
13661         if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
13662         {
13663             s = null;
13664         }
13665         if (s)
13666         {
13667             auto p = s.isPackage();
13668             if (p && checkAccess(sc, p))
13669             {
13670                 s = null;
13671             }
13672         }
13673         if (s)
13674         {
13675             // if 's' is a tuple variable, the tuple is returned.
13676             s = s.toAlias();
13677 
13678             exp.checkDeprecated(sc, s);
13679             exp.checkDisabled(sc, s);
13680 
13681             if (auto em = s.isEnumMember())
13682             {
13683                 return em.getVarExp(exp.loc, sc);
13684             }
13685             if (auto v = s.isVarDeclaration())
13686             {
13687                 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
13688                 if (!v.type ||
13689                     !v.type.deco && v.inuse)
13690                 {
13691                     if (v.inuse)
13692                         error(exp.loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
13693                     else
13694                         error(exp.loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
13695                     return ErrorExp.get();
13696                 }
13697                 if (v.type.isTypeError())
13698                     return ErrorExp.get();
13699 
13700                 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
13701                 {
13702                     /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
13703                      * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
13704                      * be reverted. `wantsym` is the hack to work around the problem.
13705                      */
13706                     if (v.inuse)
13707                     {
13708                         error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
13709                         return ErrorExp.get();
13710                     }
13711                     auto e = v.expandInitializer(exp.loc);
13712                     v.inuse++;
13713                     e = e.expressionSemantic(sc);
13714                     v.inuse--;
13715                     return e;
13716                 }
13717 
13718                 Expression e;
13719                 if (v.needThis())
13720                 {
13721                     if (!eleft)
13722                         eleft = new ThisExp(exp.loc);
13723                     e = new DotVarExp(exp.loc, eleft, v);
13724                     e = e.expressionSemantic(sc);
13725                 }
13726                 else
13727                 {
13728                     e = new VarExp(exp.loc, v);
13729                     if (eleft)
13730                     {
13731                         e = new CommaExp(exp.loc, eleft, e);
13732                         e.type = v.type;
13733                     }
13734                 }
13735                 e = e.deref();
13736                 return e.expressionSemantic(sc);
13737             }
13738 
13739             if (auto f = s.isFuncDeclaration())
13740             {
13741                 //printf("it's a function\n");
13742                 if (!f.functionSemantic())
13743                     return ErrorExp.get();
13744                 Expression e;
13745                 if (f.needThis())
13746                 {
13747                     if (!eleft)
13748                         eleft = new ThisExp(exp.loc);
13749                     e = new DotVarExp(exp.loc, eleft, f, true);
13750                     e = e.expressionSemantic(sc);
13751                 }
13752                 else
13753                 {
13754                     e = new VarExp(exp.loc, f, true);
13755                     if (eleft)
13756                     {
13757                         e = new CommaExp(exp.loc, eleft, e);
13758                         e.type = f.type;
13759                     }
13760                 }
13761                 return e;
13762             }
13763             if (auto td = s.isTemplateDeclaration())
13764             {
13765                 Expression e;
13766                 if (eleft)
13767                     e = new DotTemplateExp(exp.loc, eleft, td);
13768                 else
13769                     e = new TemplateExp(exp.loc, td);
13770                 e = e.expressionSemantic(sc);
13771                 return e;
13772             }
13773             if (OverDeclaration od = s.isOverDeclaration())
13774             {
13775                 Expression e = new VarExp(exp.loc, od, true);
13776                 if (eleft)
13777                 {
13778                     e = new CommaExp(exp.loc, eleft, e);
13779                     e.type = Type.tvoid; // ambiguous type?
13780                 }
13781                 return e.expressionSemantic(sc);
13782             }
13783             if (auto o = s.isOverloadSet())
13784             {
13785                 //printf("'%s' is an overload set\n", o.toChars());
13786                 return new OverExp(exp.loc, o);
13787             }
13788 
13789             if (auto t = s.getType())
13790             {
13791                 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
13792             }
13793 
13794             if (auto tup = s.isTupleDeclaration())
13795             {
13796                 if (eleft)
13797                 {
13798                     Expression e = new DotVarExp(exp.loc, eleft, tup);
13799                     e = e.expressionSemantic(sc);
13800                     return e;
13801                 }
13802                 Expression e = new TupleExp(exp.loc, tup);
13803                 e = e.expressionSemantic(sc);
13804                 return e;
13805             }
13806 
13807             if (auto sds = s.isScopeDsymbol())
13808             {
13809                 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
13810                 Expression e = new ScopeExp(exp.loc, sds);
13811                 e = e.expressionSemantic(sc);
13812                 if (eleft)
13813                     e = new DotExp(exp.loc, eleft, e);
13814                 return e;
13815             }
13816 
13817             if (auto imp = s.isImport())
13818             {
13819                 Expression se = new ScopeExp(exp.loc, imp.pkg);
13820                 return se.expressionSemantic(sc);
13821             }
13822 
13823             if (auto attr = s.isAttribDeclaration())
13824             {
13825                 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
13826                 {
13827                     auto es = new DsymbolExp(exp.loc, sm);
13828                     return es;
13829                 }
13830             }
13831 
13832             // BUG: handle other cases like in IdentifierExp::semantic()
13833             debug
13834             {
13835                 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
13836             }
13837             assert(0);
13838         }
13839         else if (exp.ident == Id.stringof)
13840         {
13841             Expression e = new StringExp(exp.loc, ie.toString());
13842             e = e.expressionSemantic(sc);
13843             return e;
13844         }
13845         if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
13846         {
13847             gag = false;
13848         }
13849         if (gag)
13850             return null;
13851         s = ie.sds.search_correct(exp.ident);
13852         if (s && symbolIsVisible(sc, s))
13853         {
13854             if (s.isPackage())
13855                 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());
13856             else
13857                 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());
13858         }
13859         else
13860             error(exp.loc, "undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
13861         return ErrorExp.get();
13862     }
13863     else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
13864              !(
13865                exp.ident == Id.__sizeof ||
13866                exp.ident == Id.__xalignof ||
13867                !cfile &&
13868                 (exp.ident == Id._mangleof ||
13869                  exp.ident == Id.offsetof ||
13870                  exp.ident == Id._init ||
13871                  exp.ident == Id.stringof)
13872               ))
13873     {
13874         Type t1bn = t1b.nextOf();
13875         if (gag)
13876         {
13877             if (AggregateDeclaration ad = isAggregate(t1bn))
13878             {
13879                 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
13880                     return null;
13881             }
13882         }
13883 
13884         /* Rewrite:
13885          *   p.ident
13886          * as:
13887          *   (*p).ident
13888          */
13889         if (gag && t1bn.ty == Tvoid)
13890             return null;
13891         Expression e = new PtrExp(exp.loc, exp.e1);
13892         e = e.expressionSemantic(sc);
13893         const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
13894         return e.type.dotExp(sc, e, exp.ident, newFlag);
13895     }
13896     else if (exp.ident == Id.__xalignof &&
13897              exp.e1.isVarExp() &&
13898              exp.e1.isVarExp().var.isVarDeclaration() &&
13899              !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
13900     {
13901         // For `x.alignof` get the alignment of the variable, not the alignment of its type
13902         const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
13903         const naturalAlignment = exp.e1.type.alignsize();
13904         const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
13905         Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
13906         return e;
13907     }
13908     else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13909              exp.e1.isVarExp() &&
13910              exp.e1.isVarExp().var.isBitFieldDeclaration())
13911     {
13912         // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13913         auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
13914         return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13915     }
13916     else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13917              exp.e1.isDotVarExp() &&
13918              exp.e1.isDotVarExp().var.isBitFieldDeclaration())
13919     {
13920         // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13921         auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
13922         return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13923     }
13924     else
13925     {
13926         if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
13927             gag = false;
13928 
13929         const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
13930 
13931         Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
13932         if (e)
13933         {
13934             e = e.expressionSemantic(sc);
13935         }
13936         return e;
13937     }
13938 }
13939 
13940 /**
13941  * Resolve `e1.ident!tiargs` without seeing UFCS.
13942  * Params:
13943  *     exp = the `DotTemplateInstanceExp` to resolve
13944  *     sc = the semantic scope
13945  *     gag = stop "not a property" error and return `null`.
13946  * Returns:
13947  *     `null` if error or not found, or the resolved expression.
13948  */
13949 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
13950 {
13951     static if (LOGSEMANTIC)
13952     {
13953         printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
13954     }
13955 
13956     static Expression errorExp()
13957     {
13958         return ErrorExp.get();
13959     }
13960 
13961     Expression e1 = exp.e1;
13962 
13963     if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
13964     {
13965         // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13966         // and do the symbol search in that context (Issue: 19476)
13967         auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
13968         e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
13969     }
13970 
13971     auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
13972 
13973     Expression e = die.dotIdSemanticPropX(sc);
13974     if (e == die)
13975     {
13976         exp.e1 = die.e1; // take back
13977         Type t1b = exp.e1.type.toBasetype();
13978         if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
13979         {
13980             /* No built-in type has templatized properties, so do shortcut.
13981              * It is necessary in: 1024.max!"a < b"
13982              */
13983             if (gag)
13984                 return null;
13985         }
13986         e = die.dotIdSemanticProp(sc, gag);
13987         if (gag)
13988         {
13989             if (!e ||
13990                 isDotOpDispatch(e))
13991             {
13992                 /* opDispatch!tiargs would be a function template that needs IFTI,
13993                  * so it's not a template
13994                  */
13995                 return null;
13996             }
13997         }
13998     }
13999     assert(e);
14000 
14001     if (e.op == EXP.error)
14002         return e;
14003     if (DotVarExp dve = e.isDotVarExp())
14004     {
14005         if (FuncDeclaration fd = dve.var.isFuncDeclaration())
14006         {
14007             if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14008             {
14009                 e = new DotTemplateExp(dve.loc, dve.e1, td);
14010                 e = e.expressionSemantic(sc);
14011             }
14012         }
14013         else if (OverDeclaration od = dve.var.isOverDeclaration())
14014         {
14015             exp.e1 = dve.e1; // pull semantic() result
14016 
14017             if (!exp.findTempDecl(sc))
14018                 goto Lerr;
14019             if (exp.ti.needsTypeInference(sc))
14020                 return exp;
14021             exp.ti.dsymbolSemantic(sc);
14022             if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14023                 return errorExp();
14024 
14025             if (Declaration v = exp.ti.toAlias().isDeclaration())
14026             {
14027                 if (v.type && !v.type.deco)
14028                     v.type = v.type.typeSemantic(v.loc, sc);
14029                 return new DotVarExp(exp.loc, exp.e1, v)
14030                        .expressionSemantic(sc);
14031             }
14032             return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14033                    .expressionSemantic(sc);
14034         }
14035     }
14036     else if (e.op == EXP.variable)
14037     {
14038         VarExp ve = cast(VarExp)e;
14039         if (FuncDeclaration fd = ve.var.isFuncDeclaration())
14040         {
14041             if (TemplateDeclaration td = fd.findTemplateDeclRoot())
14042             {
14043                 e = new TemplateExp(ve.loc, td)
14044                     .expressionSemantic(sc);
14045             }
14046         }
14047         else if (OverDeclaration od = ve.var.isOverDeclaration())
14048         {
14049             exp.ti.tempdecl = od;
14050             return new ScopeExp(exp.loc, exp.ti)
14051                    .expressionSemantic(sc);
14052         }
14053     }
14054 
14055     if (DotTemplateExp dte = e.isDotTemplateExp())
14056     {
14057         exp.e1 = dte.e1; // pull semantic() result
14058 
14059         exp.ti.tempdecl = dte.td;
14060         if (!exp.ti.semanticTiargs(sc))
14061             return errorExp();
14062         if (exp.ti.needsTypeInference(sc))
14063             return exp;
14064         exp.ti.dsymbolSemantic(sc);
14065         if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14066             return errorExp();
14067 
14068         if (Declaration v = exp.ti.toAlias().isDeclaration())
14069         {
14070             return new DotVarExp(exp.loc, exp.e1, v)
14071                    .expressionSemantic(sc);
14072         }
14073         return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14074                .expressionSemantic(sc);
14075     }
14076     else if (e.op == EXP.template_)
14077     {
14078         exp.ti.tempdecl = (cast(TemplateExp)e).td;
14079         return new ScopeExp(exp.loc, exp.ti)
14080                .expressionSemantic(sc);
14081     }
14082     else if (DotExp de = e.isDotExp())
14083     {
14084         if (de.e2.op == EXP.overloadSet)
14085         {
14086             if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
14087             {
14088                 return errorExp();
14089             }
14090             if (exp.ti.needsTypeInference(sc))
14091                 return exp;
14092             exp.ti.dsymbolSemantic(sc);
14093             if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
14094                 return errorExp();
14095 
14096             if (Declaration v = exp.ti.toAlias().isDeclaration())
14097             {
14098                 if (v.type && !v.type.deco)
14099                     v.type = v.type.typeSemantic(v.loc, sc);
14100                 return new DotVarExp(exp.loc, exp.e1, v)
14101                        .expressionSemantic(sc);
14102             }
14103             return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
14104                    .expressionSemantic(sc);
14105         }
14106     }
14107     else if (OverExp oe = e.isOverExp())
14108     {
14109         exp.ti.tempdecl = oe.vars;
14110         return new ScopeExp(exp.loc, exp.ti)
14111                .expressionSemantic(sc);
14112     }
14113 
14114 Lerr:
14115     error(exp.loc, "`%s` isn't a template", e.toChars());
14116     return errorExp();
14117 }
14118 
14119 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
14120 {
14121     auto loc = funcExp.loc;
14122     auto tok = funcExp.tok;
14123     auto td = funcExp.td;
14124     auto fd = funcExp.fd;
14125     auto type = funcExp.type;
14126 
14127     MATCH cannotInfer()
14128     {
14129         eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
14130         return MATCH.nomatch;
14131     }
14132 
14133     //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
14134     if (presult)
14135         *presult = null;
14136 
14137     TypeFunction tof = null;
14138     if (to.ty == Tdelegate)
14139     {
14140         if (tok == TOK.function_)
14141         {
14142             eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
14143             return MATCH.nomatch;
14144         }
14145         tof = cast(TypeFunction)to.nextOf();
14146     }
14147     else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
14148     {
14149         if (tok == TOK.delegate_)
14150         {
14151             eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
14152             return MATCH.nomatch;
14153         }
14154     }
14155 
14156     if (td)
14157     {
14158         if (!tof)
14159         {
14160             return cannotInfer();
14161         }
14162 
14163         // Parameter types inference from 'tof'
14164         assert(td._scope);
14165         TypeFunction tf = fd.type.isTypeFunction();
14166         //printf("\ttof = %s\n", tof.toChars());
14167         //printf("\ttf  = %s\n", tf.toChars());
14168         const dim = tf.parameterList.length;
14169 
14170         if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
14171             return cannotInfer();
14172 
14173         auto tiargs = new Objects();
14174         tiargs.reserve(td.parameters.length);
14175 
14176         foreach (tp; *td.parameters)
14177         {
14178             size_t u = 0;
14179             foreach (i, p; tf.parameterList)
14180             {
14181                 if (auto ti = p.type.isTypeIdentifier())
14182                     if (ti && ti.ident == tp.ident)
14183                         break;
14184 
14185                 ++u;
14186             }
14187             assert(u < dim);
14188             Parameter pto = tof.parameterList[u];
14189             Type t = pto.type;
14190             if (t.ty == Terror)
14191                 return cannotInfer();
14192             tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
14193             tiargs.push(t);
14194         }
14195 
14196         // Set target of return type inference
14197         if (!tf.next && tof.next)
14198             fd.treq = to;
14199 
14200         auto ti = new TemplateInstance(loc, td, tiargs);
14201         Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
14202 
14203         // Reset inference target for the later re-semantic
14204         fd.treq = null;
14205 
14206         if (ex.op == EXP.error)
14207             return MATCH.nomatch;
14208         if (auto ef = ex.isFuncExp())
14209             return ef.matchType(to, sc, presult, eSink);
14210         else
14211             return cannotInfer();
14212     }
14213 
14214     if (!tof || !tof.next)
14215         return MATCH.nomatch;
14216 
14217     assert(type && type != Type.tvoid);
14218     if (fd.type.ty == Terror)
14219         return MATCH.nomatch;
14220     auto tfx = fd.type.isTypeFunction();
14221     bool convertMatch = (type.ty != to.ty);
14222 
14223     if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
14224     {
14225         /* If return type is inferred and covariant return,
14226          * tweak return statements to required return type.
14227          *
14228          * interface I {}
14229          * class C : Object, I{}
14230          *
14231          * I delegate() dg = delegate() { return new class C(); }
14232          */
14233         convertMatch = true;
14234 
14235         auto tfy = new TypeFunction(tfx.parameterList, tof.next,
14236                     tfx.linkage, STC.undefined_);
14237         tfy.mod = tfx.mod;
14238         tfy.trust = tfx.trust;
14239         tfy.isnothrow = tfx.isnothrow;
14240         tfy.isnogc = tfx.isnogc;
14241         tfy.purity = tfx.purity;
14242         tfy.isproperty = tfx.isproperty;
14243         tfy.isref = tfx.isref;
14244         tfy.isInOutParam = tfx.isInOutParam;
14245         tfy.isInOutQual = tfx.isInOutQual;
14246         tfy.deco = tfy.merge().deco;
14247 
14248         tfx = tfy;
14249     }
14250     Type tx;
14251     if (tok == TOK.delegate_ ||
14252         tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
14253     {
14254         // Allow conversion from implicit function pointer to delegate
14255         tx = new TypeDelegate(tfx);
14256         tx.deco = tx.merge().deco;
14257     }
14258     else
14259     {
14260         assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
14261         tx = tfx.pointerTo();
14262     }
14263     //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
14264 
14265     MATCH m = tx.implicitConvTo(to);
14266     if (m > MATCH.nomatch)
14267     {
14268         // MATCH.exact:      exact type match
14269         // MATCH.constant:      covairiant type match (eg. attributes difference)
14270         // MATCH.convert:    context conversion
14271         m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
14272 
14273         if (presult)
14274         {
14275             (*presult) = cast(FuncExp)funcExp.copy();
14276             (*presult).type = to;
14277 
14278             // https://issues.dlang.org/show_bug.cgi?id=12508
14279             // Tweak function body for covariant returns.
14280             (*presult).fd.modifyReturns(sc, tof.next);
14281         }
14282     }
14283     else if (!cast(ErrorSinkNull)eSink)
14284     {
14285         auto ts = toAutoQualChars(tx, to);
14286         eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
14287             funcExp.toChars(), ts[0], ts[1]);
14288     }
14289     return m;
14290 }
14291 
14292 private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
14293 {
14294     const r1 = binExp.e1.checkSharedAccess(sc);
14295     const r2 = binExp.e2.checkSharedAccess(sc);
14296     return (r1 || r2);
14297 }
14298 
14299 /***************************************
14300  * If expression is shared, check that we can access it.
14301  * Give error message if not.
14302  *
14303  * Params:
14304  *      e = expression to check
14305  *      sc = context
14306  *      returnRef = Whether this expression is for a `return` statement
14307  *                  off a `ref` function, in which case a single level
14308  *                  of dereference is allowed (e.g. `shared(int)*`).
14309  * Returns:
14310  *      true on error
14311  */
14312 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
14313 {
14314     if (global.params.noSharedAccess != FeatureState.enabled ||
14315         !sc ||
14316         sc.intypeof ||
14317         sc.flags & SCOPE.ctfe)
14318     {
14319         return false;
14320     }
14321 
14322     //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
14323 
14324     bool check(Expression e, bool allowRef)
14325     {
14326         bool sharedError(Expression e)
14327         {
14328             // https://dlang.org/phobos/core_atomic.html
14329             error(e.loc, "direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
14330             return true;
14331         }
14332 
14333         // Error by default
14334         bool visit(Expression e)
14335         {
14336             // https://issues.dlang.org/show_bug.cgi?id=23639
14337             // Should be able to cast(shared)
14338             if (!e.isCastExp() && e.type.isShared())
14339                 return sharedError(e);
14340             return false;
14341         }
14342 
14343         bool visitNew(NewExp e)
14344         {
14345             if (e.thisexp)
14346                 check(e.thisexp, false);
14347             return false;
14348         }
14349 
14350         bool visitVar(VarExp e)
14351         {
14352             // https://issues.dlang.org/show_bug.cgi?id=20908
14353             // direct access to init symbols is ok as they
14354             // cannot be modified.
14355             if (e.var.isSymbolDeclaration())
14356                 return false;
14357 
14358             // https://issues.dlang.org/show_bug.cgi?id=22626
14359             // Synchronized functions don't need to use core.atomic
14360             // when accessing `this`.
14361             if (sc.func && sc.func.isSynchronized())
14362             {
14363                 if (e.var.isThisDeclaration())
14364                     return false;
14365                 else
14366                     return sharedError(e);
14367             }
14368             else if (!allowRef && e.var.type.isShared())
14369                 return sharedError(e);
14370 
14371             return false;
14372         }
14373 
14374         bool visitAddr(AddrExp e)
14375         {
14376             return check(e.e1, true);
14377         }
14378 
14379         bool visitPtr(PtrExp e)
14380         {
14381             if (!allowRef && e.type.isShared())
14382                 return sharedError(e);
14383 
14384             if (e.e1.type.isShared())
14385                 return sharedError(e);
14386 
14387             return check(e.e1, false);
14388         }
14389 
14390         bool visitDotVar(DotVarExp e)
14391         {
14392             //printf("dotvarexp = %s\n", e.toChars());
14393             if (e.type.isShared())
14394             {
14395                 if (e.e1.isThisExp())
14396                 {
14397                     // https://issues.dlang.org/show_bug.cgi?id=22626
14398                     if (sc.func && sc.func.isSynchronized())
14399                         return false;
14400 
14401                     // https://issues.dlang.org/show_bug.cgi?id=23790
14402                     if (e.e1.type.isTypeStruct())
14403                         return false;
14404                 }
14405 
14406                 auto fd = e.var.isFuncDeclaration();
14407                 const sharedFunc = fd && fd.type.isShared;
14408                 if (!allowRef && !sharedFunc)
14409                     return sharedError(e);
14410 
14411                 // Allow using `DotVarExp` within value types
14412                 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
14413                     return check(e.e1, allowRef);
14414 
14415                 // If we end up with a single `VarExp`, it might be a `ref` param
14416                 // `shared ref T` param == `shared(T)*`.
14417                 if (auto ve = e.e1.isVarExp())
14418                 {
14419                     return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
14420                 }
14421 
14422                 return sharedError(e);
14423             }
14424 
14425             return check(e.e1, false);
14426         }
14427 
14428         bool visitIndex(IndexExp e)
14429         {
14430             if (!allowRef && e.type.isShared())
14431                 return sharedError(e);
14432 
14433             if (e.e1.type.isShared())
14434                 return sharedError(e);
14435 
14436             return check(e.e1, false);
14437         }
14438 
14439         bool visitComma(CommaExp e)
14440         {
14441             // Cannot be `return ref` since we can't use the return,
14442             // but it's better to show that error than an unrelated `shared` one
14443             return check(e.e2, true);
14444         }
14445 
14446         switch (e.op)
14447         {
14448             default:              return visit(e);
14449 
14450             // Those have no indirections / can be ignored
14451             case EXP.call:
14452             case EXP.error:
14453             case EXP.complex80:
14454             case EXP.int64:
14455             case EXP.null_:       return false;
14456 
14457             case EXP.variable:    return visitVar(e.isVarExp());
14458             case EXP.new_:        return visitNew(e.isNewExp());
14459             case EXP.address:     return visitAddr(e.isAddrExp());
14460             case EXP.star:        return visitPtr(e.isPtrExp());
14461             case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
14462             case EXP.index:       return visitIndex(e.isIndexExp());
14463         }
14464     }
14465 
14466     return check(e, returnRef);
14467 }
14468 
14469 /************************************************
14470  * Destructors are attached to VarDeclarations.
14471  * Hence, if expression returns a temp that needs a destructor,
14472  * make sure and create a VarDeclaration for that temp.
14473  */
14474 Expression addDtorHook(Expression e, Scope* sc)
14475 {
14476     Expression visit(Expression exp)
14477     {
14478         return exp;
14479     }
14480 
14481     Expression visitStructLiteral(StructLiteralExp exp)
14482     {
14483         auto sd = exp.sd;
14484         /* If struct requires a destructor, rewrite as:
14485          *    (S tmp = S()),tmp
14486          * so that the destructor can be hung on tmp.
14487          */
14488         if (sd.dtor && sc.func)
14489         {
14490             /* Make an identifier for the temporary of the form:
14491              *   __sl%s%d, where %s is the struct name
14492              */
14493             char[10] buf = void;
14494             const prefix = "__sl";
14495             const ident = sd.ident.toString;
14496             const fullLen = prefix.length + ident.length;
14497             const len = fullLen < buf.length ? fullLen : buf.length;
14498             buf[0 .. prefix.length] = prefix;
14499             buf[prefix.length .. len] = ident[0 .. len - prefix.length];
14500 
14501             auto tmp = copyToTemp(0, buf[0 .. len], exp);
14502             Expression ae = new DeclarationExp(exp.loc, tmp);
14503             Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
14504             e = e.expressionSemantic(sc);
14505             return e;
14506         }
14507 
14508         return exp;
14509     }
14510 
14511     Expression visitCall(CallExp exp)
14512     {
14513         auto e1 = exp.e1;
14514         auto type = exp.type;
14515         /* Only need to add dtor hook if it's a type that needs destruction.
14516          * Use same logic as VarDeclaration::callScopeDtor()
14517          */
14518 
14519         if (auto tf = e1.type.isTypeFunction())
14520         {
14521             if (tf.isref)
14522                 return exp;
14523         }
14524 
14525         Type tv = type.baseElemOf();
14526         if (auto ts = tv.isTypeStruct())
14527         {
14528             StructDeclaration sd = ts.sym;
14529             if (sd.dtor)
14530             {
14531                 /* Type needs destruction, so declare a tmp
14532                  * which the back end will recognize and call dtor on
14533                  */
14534                 auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
14535                 auto de = new DeclarationExp(exp.loc, tmp);
14536                 auto ve = new VarExp(exp.loc, tmp);
14537                 Expression e = new CommaExp(exp.loc, de, ve);
14538                 e = e.expressionSemantic(sc);
14539                 return e;
14540             }
14541         }
14542 
14543         return exp;
14544     }
14545 
14546     Expression visitCast(CastExp exp)
14547     {
14548         if (exp.to.toBasetype().ty == Tvoid)        // look past the cast(void)
14549             exp.e1 = exp.e1.addDtorHook(sc);
14550         return exp;
14551     }
14552 
14553     Expression visitComma(CommaExp exp)
14554     {
14555         exp.e2 = exp.e2.addDtorHook(sc);
14556         return exp;
14557     }
14558 
14559     switch(e.op)
14560     {
14561         default: return visit(e);
14562 
14563         case EXP.structLiteral:    return visitStructLiteral(e.isStructLiteralExp());
14564         case EXP.call:             return visitCall(e.isCallExp());
14565         case EXP.cast_:            return visitCast(e.isCastExp());
14566         case EXP.comma:            return visitComma(e.isCommaExp());
14567     }
14568 }
14569 
14570 /****************************************************
14571  * Determine if `exp`, which gets its address taken, can do so safely.
14572  * Params:
14573  *      sc = context
14574  *      exp = expression having its address taken
14575  *      v = the variable getting its address taken
14576  * Returns:
14577  *      `true` if ok, `false` for error
14578  */
14579 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
14580 {
14581     //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
14582     if (v is null)
14583         return true;
14584 
14585     if (!v.canTakeAddressOf())
14586     {
14587         error(exp.loc, "cannot take address of `%s`", exp.toChars());
14588         return false;
14589     }
14590     if (sc.func && !sc.intypeof && !v.isDataseg())
14591     {
14592         if (global.params.useDIP1000 != FeatureState.enabled &&
14593             !(v.storage_class & STC.temp) &&
14594             sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
14595         {
14596             return false;
14597         }
14598     }
14599     return true;
14600 }
14601 
14602 /**************************************
14603  * This check ensures that the object in `exp` can have its address taken, or
14604  * issue a diagnostic error.
14605  * Params:
14606  *      e = expression to check
14607  *      sc = context
14608  * Returns:
14609  *      true if the expression is addressable
14610  */
14611 bool checkAddressable(Expression e, Scope* sc)
14612 {
14613     Expression ex = e;
14614     while (true)
14615     {
14616         switch (ex.op)
14617         {
14618             case EXP.dotVariable:
14619                 // https://issues.dlang.org/show_bug.cgi?id=22749
14620                 // Error about taking address of any bit-field, regardless of
14621                 // whether SCOPE.Cfile is set.
14622                 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
14623                 {
14624                     error(e.loc, "cannot take address of bit-field `%s`", bf.toChars());
14625                     return false;
14626                 }
14627                 goto case EXP.cast_;
14628 
14629             case EXP.index:
14630                 ex = ex.isBinExp().e1;
14631                 continue;
14632 
14633             case EXP.address:
14634             case EXP.array:
14635             case EXP.cast_:
14636                 ex = ex.isUnaExp().e1;
14637                 continue;
14638 
14639             case EXP.variable:
14640                 if (sc.flags & SCOPE.Cfile)
14641                 {
14642                     // C11 6.5.3.2: A variable that has its address taken cannot be
14643                     // stored in a register.
14644                     // C11 6.3.2.1: An array that has its address computed with `[]`
14645                     // or cast to an lvalue pointer cannot be stored in a register.
14646                     if (ex.isVarExp().var.storage_class & STC.register)
14647                     {
14648                         if (e.isIndexExp())
14649                             error(e.loc, "cannot index through register variable `%s`", ex.toChars());
14650                         else
14651                             error(e.loc, "cannot take address of register variable `%s`", ex.toChars());
14652                         return false;
14653                     }
14654                 }
14655                 break;
14656 
14657             default:
14658                 break;
14659         }
14660         break;
14661     }
14662     return true;
14663 }
14664 
14665 
14666 /*******************************
14667  * Checks the attributes of a function.
14668  * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
14669  * and usage of `deprecated` and `@disabled`-ed symbols are checked.
14670  *
14671  * Params:
14672  *  exp = expression to check attributes for
14673  *  sc  = scope of the function
14674  *  f   = function to be checked
14675  * Returns: `true` if error occur.
14676  */
14677 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
14678 {
14679     with(exp)
14680     {
14681         bool error = checkDisabled(sc, f);
14682         error |= checkDeprecated(sc, f);
14683         error |= checkPurity(sc, f);
14684         error |= checkSafety(sc, f);
14685         error |= checkNogc(sc, f);
14686         return error;
14687     }
14688 }
14689 
14690 /*******************************
14691  * Helper function for `getRightThis()`.
14692  * Gets `this` of the next outer aggregate.
14693  * Params:
14694  *      loc = location to use for error messages
14695  *      sc = context
14696  *      s = the parent symbol of the existing `this`
14697  *      ad = struct or class we need the correct `this` for
14698  *      e1 = existing `this`
14699  *      t = type of the existing `this`
14700  *      var = the specific member of ad we're accessing
14701  *      flag = if true, return `null` instead of throwing an error
14702  * Returns:
14703  *      Expression representing the `this` for the var
14704  */
14705 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
14706 {
14707     int n = 0;
14708     while (s && s.isFuncDeclaration())
14709     {
14710         FuncDeclaration f = s.isFuncDeclaration();
14711         if (f.vthis)
14712         {
14713             n++;
14714             e1 = new VarExp(loc, f.vthis);
14715             if (f.hasDualContext())
14716             {
14717                 // (*__this)[i]
14718                 if (n > 1)
14719                     e1 = e1.expressionSemantic(sc);
14720                 e1 = new PtrExp(loc, e1);
14721                 uint i = f.followInstantiationContext(ad);
14722                 e1 = new IndexExp(loc, e1, new IntegerExp(i));
14723                 s = f.toParentP(ad);
14724                 continue;
14725             }
14726         }
14727         else
14728         {
14729             if (flag)
14730                 return null;
14731             error(e1.loc, "need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
14732             e1 = ErrorExp.get();
14733             return e1;
14734         }
14735         s = s.toParent2();
14736     }
14737     if (n > 1 || e1.op == EXP.index)
14738         e1 = e1.expressionSemantic(sc);
14739     if (s && e1.type.equivalent(Type.tvoidptr))
14740     {
14741         if (auto sad = s.isAggregateDeclaration())
14742         {
14743             Type ta = sad.handleType();
14744             if (ta.ty == Tstruct)
14745                 ta = ta.pointerTo();
14746             e1.type = ta;
14747         }
14748     }
14749     e1.type = e1.type.addMod(t.mod);
14750     return e1;
14751 }
14752 
14753 /*******************************
14754  * Make a dual-context container for use as a `this` argument.
14755  * Params:
14756  *      loc = location to use for error messages
14757  *      sc = current scope
14758  *      fd = target function that will take the `this` argument
14759  * Returns:
14760  *      Temporary closure variable.
14761  * Note:
14762  *      The function `fd` is added to the nested references of the
14763  *      newly created variable such that a closure is made for the variable when
14764  *      the address of `fd` is taken.
14765  */
14766 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
14767 {
14768     Type tthis2 = Type.tvoidptr.sarrayOf(2);
14769     VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
14770     vthis2.storage_class |= STC.temp;
14771     vthis2.dsymbolSemantic(sc);
14772     vthis2.parent = sc.parent;
14773     // make it a closure var
14774     assert(sc.func);
14775     sc.func.closureVars.push(vthis2);
14776     // add `fd` to the nested refs
14777     vthis2.nestedrefs.push(fd);
14778     return vthis2;
14779 }
14780 
14781 /*******************************
14782  * Make sure that the runtime hook `id` exists.
14783  * Params:
14784  *      loc = location to use for error messages
14785  *      sc = current scope
14786  *      id = the hook identifier
14787  *      description = what the hook does
14788  *      module_ = what module the hook is located in
14789  * Returns:
14790  *      a `bool` indicating if the hook is present.
14791  */
14792 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
14793 {
14794     auto rootSymbol = sc.search(loc, Id.empty, null);
14795     if (auto moduleSymbol = rootSymbol.search(loc, module_))
14796         if (moduleSymbol.search(loc, id))
14797           return true;
14798     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);
14799     return false;
14800 }
14801 
14802 /***************************************
14803  * Fit elements[] to the corresponding types of the `sd`'s fields.
14804  *
14805  * Params:
14806  *      sd = the struct declaration
14807  *      loc = location to use for error messages
14808  *      sc = context
14809  *      elements = explicit arguments used to construct object
14810  *      stype = the constructed object type.
14811  * Returns:
14812  *      false if any errors occur,
14813  *      otherwise true and elements[] are rewritten for the output.
14814  */
14815 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
14816 {
14817     if (!elements)
14818         return true;
14819 
14820     const nfields = sd.nonHiddenFields();
14821     size_t offset = 0;
14822     for (size_t i = 0; i < elements.length; i++)
14823     {
14824         Expression e = (*elements)[i];
14825         if (!e)
14826             continue;
14827 
14828         e = resolveProperties(sc, e);
14829         if (i >= nfields)
14830         {
14831             if (i < sd.fields.length && e.op == EXP.null_)
14832             {
14833                 // CTFE sometimes creates null as hidden pointer; we'll allow this.
14834                 continue;
14835             }
14836                 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
14837             return false;
14838         }
14839         VarDeclaration v = sd.fields[i];
14840         if (v.offset < offset)
14841         {
14842             .error(loc, "overlapping initialization for `%s`", v.toChars());
14843             if (!sd.isUnionDeclaration())
14844             {
14845                 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
14846                     " must initialize only the first member of a `union`. All subsequent" ~
14847                     " non-overlapping fields are default initialized";
14848                 .errorSupplemental(loc, errorMsg);
14849             }
14850             return false;
14851         }
14852         const vsize = v.type.size();
14853         if (vsize == SIZE_INVALID)
14854             return false;
14855         offset = cast(uint)(v.offset + vsize);
14856 
14857         Type t = v.type;
14858         if (stype)
14859             t = t.addMod(stype.mod);
14860         Type origType = t;
14861         Type tb = t.toBasetype();
14862 
14863         const hasPointers = tb.hasPointers();
14864         if (hasPointers)
14865         {
14866             if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
14867                  (v.offset & (target.ptrsize - 1))) &&
14868                 (sc.setUnsafe(false, loc,
14869                     "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
14870             {
14871                 return false;
14872             }
14873         }
14874 
14875         /* Look for case of initializing a static array with a too-short
14876          * string literal, such as:
14877          *  char[5] foo = "abc";
14878          * Allow this by doing an explicit cast, which will lengthen the string
14879          * literal.
14880          */
14881         if (e.op == EXP.string_ && tb.ty == Tsarray)
14882         {
14883             StringExp se = cast(StringExp)e;
14884             Type typeb = se.type.toBasetype();
14885             TY tynto = tb.nextOf().ty;
14886             if (!se.committed &&
14887                 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
14888                 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
14889             {
14890                 e = se.castTo(sc, t);
14891                 goto L1;
14892             }
14893         }
14894 
14895         while (!e.implicitConvTo(t) && tb.ty == Tsarray)
14896         {
14897             /* Static array initialization, as in:
14898              *  T[3][5] = e;
14899              */
14900             t = tb.nextOf();
14901             tb = t.toBasetype();
14902         }
14903         if (!e.implicitConvTo(t))
14904             t = origType; // restore type for better diagnostic
14905 
14906         e = e.implicitCastTo(sc, t);
14907     L1:
14908         if (e.op == EXP.error)
14909             return false;
14910 
14911         (*elements)[i] = doCopyOrMove(sc, e);
14912     }
14913     return true;
14914 }
14915 
14916 
14917 /**
14918  * Returns `em` as a VariableExp
14919  * Params:
14920  *     em = the EnumMember to wrap
14921  *     loc = location of use of em
14922  *     sc = scope of use of em
14923  * Returns:
14924  *     VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
14925  */
14926 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
14927 {
14928     dsymbolSemantic(em, sc);
14929     if (em.errors)
14930         return ErrorExp.get();
14931     em.checkDisabled(loc, sc);
14932 
14933     if (em.depdecl && !em.depdecl._scope)
14934         em.depdecl._scope = sc;
14935     em.checkDeprecated(loc, sc);
14936 
14937     if (em.errors)
14938         return ErrorExp.get();
14939     Expression e = new VarExp(loc, em);
14940     e = e.expressionSemantic(sc);
14941     if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
14942     {
14943         /* C11 types them as int. But if in D file,
14944          * type qualified names as the enum
14945          */
14946         e.type = em.parent.isEnumDeclaration().type;
14947         assert(e.type);
14948     }
14949     return e;
14950 }
14951 
14952 
14953 /*****************************
14954  * Try to treat `exp` as a boolean,
14955  * Params:
14956  *     exp = the expression
14957  *     sc = scope to evalute `exp` in
14958  * Returns:
14959  *     Modified expression on success, ErrorExp on error
14960  */
14961 Expression toBoolean(Expression exp, Scope* sc)
14962 {
14963     switch(exp.op)
14964     {
14965         case EXP.delete_:
14966             error(exp.loc, "`delete` does not give a boolean result");
14967             return ErrorExp.get();
14968 
14969         case EXP.comma:
14970             auto ce = exp.isCommaExp();
14971             auto ex2 = ce.e2.toBoolean(sc);
14972             if (ex2.op == EXP.error)
14973                 return ex2;
14974             ce.e2 = ex2;
14975             ce.type = ce.e2.type;
14976             return ce;
14977 
14978         case EXP.assign:
14979         case EXP.construct:
14980         case EXP.blit:
14981         case EXP.loweredAssignExp:
14982             if (sc.flags & SCOPE.Cfile)
14983                 return exp;
14984             // Things like:
14985             //  if (a = b) ...
14986             // are usually mistakes.
14987             error(exp.loc, "assignment cannot be used as a condition, perhaps `==` was meant?");
14988             return ErrorExp.get();
14989 
14990         //LogicalExp
14991         case EXP.andAnd:
14992         case EXP.orOr:
14993             auto le = exp.isLogicalExp();
14994             auto ex2 = le.e2.toBoolean(sc);
14995             if (ex2.op == EXP.error)
14996                 return ex2;
14997             le.e2 = ex2;
14998             return le;
14999 
15000         case EXP.question:
15001             auto ce = exp.isCondExp();
15002             auto ex1 = ce.e1.toBoolean(sc);
15003             auto ex2 = ce.e2.toBoolean(sc);
15004             if (ex1.op == EXP.error)
15005                 return ex1;
15006             if (ex2.op == EXP.error)
15007                 return ex2;
15008             ce.e1 = ex1;
15009             ce.e2 = ex2;
15010             return ce;
15011 
15012 
15013         default:
15014             // Default is 'yes' - do nothing
15015             Expression e = arrayFuncConv(exp, sc);
15016             Type t = e.type;
15017             Type tb = t.toBasetype();
15018             Type att = null;
15019 
15020             while (1)
15021             {
15022                 // Structs can be converted to bool using opCast(bool)()
15023                 if (auto ts = tb.isTypeStruct())
15024                 {
15025                     AggregateDeclaration ad = ts.sym;
15026                     /* Don't really need to check for opCast first, but by doing so we
15027                      * get better error messages if it isn't there.
15028                      */
15029                     if (Dsymbol fd = search_function(ad, Id._cast))
15030                     {
15031                         e = new CastExp(exp.loc, e, Type.tbool);
15032                         e = e.expressionSemantic(sc);
15033                         return e;
15034                     }
15035 
15036                     // Forward to aliasthis.
15037                     if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
15038                     {
15039                         e = resolveAliasThis(sc, e);
15040                         t = e.type;
15041                         tb = e.type.toBasetype();
15042                         continue;
15043                     }
15044                 }
15045                 break;
15046             }
15047 
15048             if (!t.isBoolean())
15049             {
15050                 if (tb != Type.terror)
15051                     error(exp.loc, "expression `%s` of type `%s` does not have a boolean value",
15052                               exp.toChars(), t.toChars());
15053                 return ErrorExp.get();
15054             }
15055             return e;
15056     }
15057 }