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.escape;
45 import dmd.expression;
46 import dmd.file_manager;
47 import dmd.func;
48 import dmd.globals;
49 import dmd.hdrgen;
50 import dmd.id;
51 import dmd.identifier;
52 import dmd.imphint;
53 import dmd.importc;
54 import dmd.init;
55 import dmd.initsem;
56 import dmd.inline;
57 import dmd.intrange;
58 import dmd.location;
59 import dmd.mtype;
60 import dmd.mustuse;
61 import dmd.nspace;
62 import dmd.opover;
63 import dmd.optimize;
64 import dmd.parse;
65 import dmd.printast;
66 import dmd.root.array;
67 import dmd.root.ctfloat;
68 import dmd.root.filename;
69 import dmd.common.outbuffer;
70 import dmd.root.rootobject;
71 import dmd.root.string;
72 import dmd.root.utf;
73 import dmd.semantic2;
74 import dmd.semantic3;
75 import dmd.sideeffect;
76 import dmd.safe;
77 import dmd.target;
78 import dmd.tokens;
79 import dmd.traits;
80 import dmd.typesem;
81 import dmd.typinf;
82 import dmd.utils;
83 import dmd.visitor;
84 
85 enum LOGSEMANTIC = false;
86 
87 /********************************************************
88  * Perform semantic analysis and CTFE on expressions to produce
89  * a string.
90  * Params:
91  *      buf = append generated string to buffer
92  *      sc = context
93  *      exps = array of Expressions
94  * Returns:
95  *      true on error
96  */
97 bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
98 {
99     if (!exps)
100         return false;
101 
102     foreach (ex; *exps)
103     {
104         if (!ex)
105             continue;
106         auto sc2 = sc.startCTFE();
107         sc2.tinst = null;
108         sc2.minst = null;       // prevents emission of any instantiated templates to object file
109         auto e2 = ex.expressionSemantic(sc2);
110         auto e3 = resolveProperties(sc2, e2);
111         sc2.endCTFE();
112 
113         // allowed to contain types as well as expressions
114         auto e4 = ctfeInterpretForPragmaMsg(e3);
115         if (!e4 || e4.op == EXP.error)
116             return true;
117 
118         // expand tuple
119         if (auto te = e4.isTupleExp())
120         {
121             if (expressionsToString(buf, sc, te.exps))
122                 return true;
123             continue;
124         }
125         // char literals exp `.toStringExp` return `null` but we cant override it
126         // because in most contexts we don't want the conversion to succeed.
127         IntegerExp ie = e4.isIntegerExp();
128         const ty = (ie && ie.type) ? ie.type.ty : Terror;
129         if (ty.isSomeChar)
130         {
131             auto tsa = new TypeSArray(ie.type, IntegerExp.literal!1);
132             e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
133         }
134 
135         if (StringExp se = e4.toStringExp())
136             buf.writestring(se.toUTF8(sc).peekString());
137         else
138             buf.writestring(e4.toString());
139     }
140     return false;
141 }
142 
143 
144 /***********************************************************
145  * Resolve `exp` as a compile-time known string.
146  * Params:
147  *  sc  = scope
148  *  exp = Expression which expected as a string
149  *  s   = What the string is expected for, will be used in error diagnostic.
150  * Returns:
151  *  String literal, or `null` if error happens.
152  */
153 StringExp semanticString(Scope *sc, Expression exp, const char* s)
154 {
155     sc = sc.startCTFE();
156     exp = exp.expressionSemantic(sc);
157     exp = resolveProperties(sc, exp);
158     sc = sc.endCTFE();
159 
160     if (exp.op == EXP.error)
161         return null;
162 
163     auto e = exp;
164     if (exp.type.isString())
165     {
166         e = e.ctfeInterpret();
167         if (e.op == EXP.error)
168             return null;
169     }
170 
171     auto se = e.toStringExp();
172     if (!se)
173     {
174         exp.error("`string` expected for %s, not `(%s)` of type `%s`",
175             s, exp.toChars(), exp.type.toChars());
176         return null;
177     }
178     return se;
179 }
180 
181 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
182 {
183     Expression e0;
184     Expression e1 = Expression.extractLast(ue.e1, e0);
185     // https://issues.dlang.org/show_bug.cgi?id=12585
186     // Extract the side effect part if ue.e1 is comma.
187 
188     if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
189     {
190         /* Even if opDollar is needed, 'e1' should be evaluate only once. So
191          * Rewrite:
192          *      e1.opIndex( ... use of $ ... )
193          *      e1.opSlice( ... use of $ ... )
194          * as:
195          *      (ref __dop = e1, __dop).opIndex( ... __dop.opDollar ...)
196          *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
197          */
198         e1 = extractSideEffect(sc, "__dop", e0, e1, false);
199         assert(e1.isVarExp());
200         e1.isVarExp().var.storage_class |= STC.exptemp;     // lifetime limited to expression
201     }
202     ue.e1 = e1;
203     return e0;
204 }
205 
206 /**************************************
207  * Runs semantic on ae.arguments. Declares temporary variables
208  * if '$' was used.
209  */
210 Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
211 {
212     assert(!ae.lengthVar);
213     *pe0 = null;
214     AggregateDeclaration ad = isAggregate(ae.e1.type);
215     Dsymbol slice = search_function(ad, Id.slice);
216     //printf("slice = %s %s\n", slice.kind(), slice.toChars());
217     foreach (i, e; *ae.arguments)
218     {
219         if (i == 0)
220             *pe0 = extractOpDollarSideEffect(sc, ae);
221 
222         if (e.op == EXP.interval && !(slice && slice.isTemplateDeclaration()))
223         {
224         Lfallback:
225             if (ae.arguments.length == 1)
226                 return null;
227             ae.error("multi-dimensional slicing requires template `opSlice`");
228             return ErrorExp.get();
229         }
230         //printf("[%d] e = %s\n", i, e.toChars());
231 
232         // Create scope for '$' variable for this dimension
233         auto sym = new ArrayScopeSymbol(sc, ae);
234         sym.parent = sc.scopesym;
235         sc = sc.push(sym);
236         ae.lengthVar = null; // Create it only if required
237         ae.currentDimension = i; // Dimension for $, if required
238 
239         e = e.expressionSemantic(sc);
240         e = resolveProperties(sc, e);
241 
242         if (ae.lengthVar && sc.func)
243         {
244             // If $ was used, declare it now
245             Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
246             de = de.expressionSemantic(sc);
247             *pe0 = Expression.combine(*pe0, de);
248         }
249         sc = sc.pop();
250 
251         if (auto ie = e.isIntervalExp())
252         {
253             auto tiargs = new Objects();
254             Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
255             edim = edim.expressionSemantic(sc);
256             tiargs.push(edim);
257 
258             auto fargs = new Expressions(2);
259             (*fargs)[0] = ie.lwr;
260             (*fargs)[1] = ie.upr;
261 
262             uint xerrors = global.startGagging();
263             sc = sc.push();
264             FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
265             sc = sc.pop();
266             global.endGagging(xerrors);
267             if (!fslice)
268                 goto Lfallback;
269 
270             e = new DotTemplateInstanceExp(ae.loc, ae.e1, slice.ident, tiargs);
271             e = new CallExp(ae.loc, e, fargs);
272             e = e.expressionSemantic(sc);
273         }
274 
275         if (!e.type)
276         {
277             ae.error("`%s` has no value", e.toChars());
278             e = ErrorExp.get();
279         }
280         if (e.op == EXP.error)
281             return e;
282 
283         (*ae.arguments)[i] = e;
284     }
285     return ae;
286 }
287 
288 /**************************************
289  * Runs semantic on se.lwr and se.upr. Declares a temporary variable
290  * if '$' was used.
291  * Returns:
292  *      ae, or ErrorExp if errors occurred
293  */
294 Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, Expression* pe0)
295 {
296     //assert(!ae.lengthVar);
297     if (!ie)
298         return ae;
299 
300     VarDeclaration lengthVar = ae.lengthVar;
301     bool errors = false;
302 
303     // create scope for '$'
304     auto sym = new ArrayScopeSymbol(sc, ae);
305     sym.parent = sc.scopesym;
306     sc = sc.push(sym);
307 
308     Expression sem(Expression e)
309     {
310         e = e.expressionSemantic(sc);
311         e = resolveProperties(sc, e);
312         if (!e.type)
313         {
314             ae.error("`%s` has no value", e.toChars());
315             errors = true;
316         }
317         return e;
318     }
319 
320     ie.lwr = sem(ie.lwr);
321     ie.upr = sem(ie.upr);
322 
323     if (ie.lwr.isErrorExp() || ie.upr.isErrorExp())
324         errors = true;
325 
326     if (lengthVar != ae.lengthVar && sc.func)
327     {
328         // If $ was used, declare it now
329         Expression de = new DeclarationExp(ae.loc, ae.lengthVar);
330         de = de.expressionSemantic(sc);
331         *pe0 = Expression.combine(*pe0, de);
332     }
333 
334     sc = sc.pop();
335 
336     return errors ? ErrorExp.get() : ae;
337 }
338 
339 /******************************
340  * Perform semantic() on an array of Expressions.
341  */
342 extern(D) bool arrayExpressionSemantic(
343     Expression[] exps, Scope* sc, bool preserveErrors = false)
344 {
345     bool err = false;
346     foreach (ref e; exps)
347     {
348         if (e is null) continue;
349         auto e2 = e.expressionSemantic(sc);
350         if (e2.op == EXP.error)
351             err = true;
352         if (preserveErrors || e2.op != EXP.error)
353             e = e2;
354     }
355     return err;
356 }
357 
358 /*
359 Checks if `exp` contains a direct access to a `noreturn`
360 variable. If that is the case, an `assert(0)` expression
361 is generated and returned. This function should be called
362 only after semantic analysis has been performed on `exp`.
363 
364 Params:
365     exp = expression that is checked
366 
367 Returns:
368     An `assert(0)` expression if `exp` contains a `noreturn`
369     variable access, `exp` otherwise.
370 */
371 
372 Expression checkNoreturnVarAccess(Expression exp)
373 {
374     assert(exp.type);
375 
376     Expression result = exp;
377     if (exp.type.isTypeNoreturn() && !exp.isAssertExp() &&
378         !exp.isThrowExp() && !exp.isCallExp())
379     {
380         auto msg = new StringExp(exp.loc, "Accessed expression of type `noreturn`");
381         msg.type = Type.tstring;
382         result = new AssertExp(exp.loc, IntegerExp.literal!0, msg);
383         result.type = exp.type;
384     }
385 
386     return result;
387 }
388 
389 /******************************
390  * Check the tail CallExp is really property function call.
391  * Bugs:
392  * This doesn't appear to do anything.
393  */
394 private bool checkPropertyCall(Expression e)
395 {
396     e = lastComma(e);
397 
398     if (auto ce = e.isCallExp())
399     {
400         if (ce.f)
401         {
402             auto tf = ce.f.type.isTypeFunction();
403             /* If a forward reference to ce.f, try to resolve it
404              */
405             if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
406             {
407                 ce.f.dsymbolSemantic(null);
408                 tf = ce.f.type.isTypeFunction();
409             }
410         }
411         else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
412             assert(0);
413     }
414     return false;
415 }
416 
417 /******************************
418  * Find symbol in accordance with the UFCS name look up rule
419  */
420 private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
421 {
422     //printf("searchUFCS(ident = %s)\n", ident.toChars());
423     Loc loc = ue.loc;
424 
425     // TODO: merge with Scope.search.searchScopes()
426     Dsymbol searchScopes(int flags)
427     {
428         Dsymbol s = null;
429         for (Scope* scx = sc; scx; scx = scx.enclosing)
430         {
431             if (!scx.scopesym)
432                 continue;
433             if (scx.scopesym.isModule())
434                 flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
435             s = scx.scopesym.search(loc, ident, flags);
436             if (s)
437             {
438                 // overload set contains only module scope symbols.
439                 if (s.isOverloadSet())
440                     break;
441                 // selective/renamed imports also be picked up
442                 if (AliasDeclaration ad = s.isAliasDeclaration())
443                 {
444                     if (ad._import)
445                         break;
446                 }
447                 // See only module scope symbols for UFCS target.
448                 Dsymbol p = s.toParent2();
449                 if (p && p.isModule())
450                     break;
451             }
452             s = null;
453 
454             // Stop when we hit a module, but keep going if that is not just under the global scope
455             if (scx.scopesym.isModule() && !(scx.enclosing && !scx.enclosing.enclosing))
456                 break;
457         }
458         return s;
459     }
460 
461     int flags = 0;
462     Dsymbol s;
463 
464     if (sc.flags & SCOPE.ignoresymbolvisibility)
465         flags |= IgnoreSymbolVisibility;
466 
467     // First look in local scopes
468     s = searchScopes(flags | SearchLocalsOnly);
469     if (!s)
470     {
471         // Second look in imported modules
472         s = searchScopes(flags | SearchImportsOnly);
473     }
474 
475     if (!s)
476         return ue.e1.type.getProperty(sc, loc, ident, 0, ue.e1);
477 
478     FuncDeclaration f = s.isFuncDeclaration();
479     if (f)
480     {
481         TemplateDeclaration td = getFuncTemplateDecl(f);
482         if (td)
483         {
484             if (td.overroot)
485                 td = td.overroot;
486             s = td;
487         }
488     }
489 
490     if (auto dti = ue.isDotTemplateInstanceExp())
491     {
492         auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
493         if (!ti.updateTempDecl(sc, s))
494             return ErrorExp.get();
495         return new ScopeExp(loc, ti);
496     }
497     else
498     {
499         //printf("-searchUFCS() %s\n", s.toChars());
500         return new DsymbolExp(loc, s);
501     }
502 }
503 
504 /******************************
505  * Pull out callable entity with UFCS.
506  */
507 private Expression resolveUFCS(Scope* sc, CallExp ce)
508 {
509     Loc loc = ce.loc;
510     Expression eleft;
511     Expression e;
512 
513     if (auto die = ce.e1.isDotIdExp())
514     {
515         Identifier ident = die.ident;
516 
517         Expression ex = die.dotIdSemanticPropX(sc);
518         if (ex != die)
519         {
520             ce.e1 = ex;
521             return null;
522         }
523         eleft = die.e1;
524 
525         Type t = eleft.type.toBasetype();
526         if (t.ty == Tarray || t.ty == Tsarray || t.ty == Tnull || (t.isTypeBasic() && t.ty != Tvoid))
527         {
528             /* Built-in types and arrays have no callable properties, so do shortcut.
529              * It is necessary in: e.init()
530              */
531         }
532         else if (t.ty == Taarray)
533         {
534             if (ident == Id.remove)
535             {
536                 /* Transform:
537                  *  aa.remove(arg) into delete aa[arg]
538                  */
539                 if (!ce.arguments || ce.arguments.length != 1)
540                 {
541                     ce.error("expected key as argument to `aa.remove()`");
542                     return ErrorExp.get();
543                 }
544                 if (!eleft.type.isMutable())
545                 {
546                     ce.error("cannot remove key from `%s` associative array `%s`", MODtoChars(t.mod), eleft.toChars());
547                     return ErrorExp.get();
548                 }
549                 Expression key = (*ce.arguments)[0];
550                 key = key.expressionSemantic(sc);
551                 key = resolveProperties(sc, key);
552 
553                 TypeAArray taa = t.isTypeAArray();
554                 key = key.implicitCastTo(sc, taa.index);
555 
556                 if (key.checkValue() || key.checkSharedAccess(sc))
557                     return ErrorExp.get();
558 
559                 semanticTypeInfo(sc, taa.index);
560 
561                 return new RemoveExp(loc, eleft, key);
562             }
563         }
564         else
565         {
566             if (Expression ey = die.dotIdSemanticProp(sc, 1))
567             {
568                 if (ey.op == EXP.error)
569                     return ey;
570                 ce.e1 = ey;
571                 if (isDotOpDispatch(ey))
572                 {
573                     // even opDispatch and UFCS must have valid arguments,
574                     // so now that we've seen indication of a problem,
575                     // check them for issues.
576                     Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
577 
578                     uint errors = global.startGagging();
579                     e = ce.expressionSemantic(sc);
580                     if (!global.endGagging(errors))
581                         return e;
582 
583                     if (arrayExpressionSemantic(originalArguments.peekSlice(), sc))
584                         return ErrorExp.get();
585 
586                     /* fall down to UFCS */
587                 }
588                 else
589                     return null;
590             }
591         }
592 
593         /* https://issues.dlang.org/show_bug.cgi?id=13953
594          *
595          * If a struct has an alias this to an associative array
596          * and remove is used on a struct instance, we have to
597          * check first if there is a remove function that can be called
598          * on the struct. If not we must check the alias this.
599          *
600          * struct A
601          * {
602          *      string[string] a;
603          *      alias a this;
604          * }
605          *
606          * void fun()
607          * {
608          *      A s;
609          *      s.remove("foo");
610          * }
611          */
612         const errors = global.startGagging();
613         e = searchUFCS(sc, die, ident);
614         // if there were any errors and the identifier was remove
615         if (global.endGagging(errors))
616         {
617             if (ident == Id.remove)
618             {
619                 // check alias this
620                 Expression alias_e = resolveAliasThis(sc, die.e1, 1);
621                 if (alias_e && alias_e != die.e1)
622                 {
623                     die.e1 = alias_e;
624                     CallExp ce2 = ce.syntaxCopy();
625                     ce2.e1 = die;
626                     e = ce2.isCallExp().trySemantic(sc);
627                     if (e)
628                         return e;
629                 }
630             }
631             // if alias this did not work out, print the initial errors
632             searchUFCS(sc, die, ident);
633         }
634     }
635     else if (auto dti = ce.e1.isDotTemplateInstanceExp())
636     {
637         if (Expression ey = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag))
638         {
639             ce.e1 = ey;
640             return null;
641         }
642         eleft = dti.e1;
643         e = searchUFCS(sc, dti, dti.ti.name);
644     }
645     else
646         return null;
647 
648     // Rewrite
649     ce.e1 = e;
650     if (!ce.arguments)
651         ce.arguments = new Expressions();
652     ce.arguments.shift(eleft);
653     if (!ce.names)
654         ce.names = new Identifiers();
655     ce.names.shift(null);
656 
657     return null;
658 }
659 
660 /******************************
661  * Pull out property with UFCS.
662  */
663 private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2 = null)
664 {
665     Loc loc = e1.loc;
666     Expression eleft;
667     Expression e;
668 
669     if (auto die = e1.isDotIdExp())
670     {
671         eleft = die.e1;
672         e = searchUFCS(sc, die, die.ident);
673     }
674     else if (auto dti = e1.isDotTemplateInstanceExp())
675     {
676         eleft = dti.e1;
677         e = searchUFCS(sc, dti, dti.ti.name);
678     }
679     else
680         return null;
681 
682     if (e is null)
683         return null;
684 
685     // Rewrite
686     if (e2)
687     {
688         // run semantic without gagging
689         e2 = e2.expressionSemantic(sc);
690 
691         /* f(e1) = e2
692          */
693         Expression ex = e.copy();
694         auto a1 = new Expressions(1);
695         (*a1)[0] = eleft;
696         ex = new CallExp(loc, ex, a1);
697         auto e1PassSemantic = ex.trySemantic(sc);
698 
699         /* f(e1, e2)
700          */
701         auto a2 = new Expressions(2);
702         (*a2)[0] = eleft;
703         (*a2)[1] = e2;
704         e = new CallExp(loc, e, a2);
705         e = e.trySemantic(sc);
706         if (!e1PassSemantic && !e)
707         {
708             /* https://issues.dlang.org/show_bug.cgi?id=20448
709              *
710              * If both versions have failed to pass semantic,
711              * f(e1) = e2 gets priority in error printing
712              * because f might be a templated function that
713              * failed to instantiate and we have to print
714              * the instantiation errors.
715              */
716             return e1.expressionSemantic(sc);
717         }
718         else if (ex && !e)
719         {
720             checkPropertyCall(ex);
721             ex = new AssignExp(loc, ex, e2);
722             return ex.expressionSemantic(sc);
723         }
724         else
725         {
726             // strict setter prints errors if fails
727             e = e.expressionSemantic(sc);
728         }
729         checkPropertyCall(e);
730         return e;
731     }
732     else
733     {
734         /* f(e1)
735          */
736         auto arguments = new Expressions(1);
737         (*arguments)[0] = eleft;
738         e = new CallExp(loc, e, arguments);
739         e = e.expressionSemantic(sc);
740         checkPropertyCall(e);
741         return e.expressionSemantic(sc);
742     }
743 }
744 
745 /******************************
746  * If e1 is a property function (template), resolve it.
747  */
748 Expression resolvePropertiesOnly(Scope* sc, Expression e1)
749 {
750     //printf("e1 = %s %s\n", Token.toChars(e1.op), e1.toChars());
751 
752     Expression handleOverloadSet(OverloadSet os)
753     {
754         assert(os);
755         foreach (s; os.a)
756         {
757             auto fd = s.isFuncDeclaration();
758             auto td = s.isTemplateDeclaration();
759             if (fd)
760             {
761                 if (fd.type.isTypeFunction().isproperty)
762                     return resolveProperties(sc, e1);
763             }
764             else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
765             {
766                 if (fd.type.isTypeFunction().isproperty ||
767                     (fd.storage_class2 & STC.property) ||
768                     (td._scope.stc & STC.property))
769                     return resolveProperties(sc, e1);
770             }
771         }
772         return e1;
773     }
774 
775     Expression handleTemplateDecl(TemplateDeclaration td)
776     {
777         assert(td);
778         if (td.onemember)
779         {
780             if (auto fd = td.onemember.isFuncDeclaration())
781             {
782                 if (fd.type.isTypeFunction().isproperty ||
783                     (fd.storage_class2 & STC.property) ||
784                     (td._scope.stc & STC.property))
785                     return resolveProperties(sc, e1);
786             }
787         }
788         return e1;
789     }
790 
791     Expression handleFuncDecl(FuncDeclaration fd)
792     {
793         assert(fd);
794         if (fd.type.isTypeFunction().isproperty)
795             return resolveProperties(sc, e1);
796         return e1;
797     }
798 
799     if (auto de = e1.isDotExp())
800     {
801         if (auto os = de.e2.isOverExp())
802             return handleOverloadSet(os.vars);
803     }
804     else if (auto oe = e1.isOverExp())
805         return handleOverloadSet(oe.vars);
806     else if (auto dti = e1.isDotTemplateInstanceExp())
807     {
808         if (dti.ti.tempdecl)
809             if (auto td = dti.ti.tempdecl.isTemplateDeclaration())
810                 return handleTemplateDecl(td);
811     }
812     else if (auto dte = e1.isDotTemplateExp())
813         return handleTemplateDecl(dte.td);
814     else if (auto se = e1.isScopeExp())
815     {
816         Dsymbol s = se.sds;
817         TemplateInstance ti = s.isTemplateInstance();
818         if (ti && !ti.semanticRun && ti.tempdecl)
819             if (auto td = ti.tempdecl.isTemplateDeclaration())
820                 return handleTemplateDecl(td);
821     }
822     else if (auto et = e1.isTemplateExp())
823         return handleTemplateDecl(et.td);
824     else if (e1.isDotVarExp() && e1.type.isTypeFunction())
825     {
826         DotVarExp dve = e1.isDotVarExp();
827         return handleFuncDecl(dve.var.isFuncDeclaration());
828     }
829     else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
830         return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
831     return e1;
832 }
833 
834 /****************************************
835  * Turn symbol `s` into the expression it represents.
836  *
837  * Params:
838  *      s = symbol to resolve
839  *      loc = location of use of `s`
840  *      sc = context
841  *      hasOverloads = applies if `s` represents a function.
842  *          true means it's overloaded and will be resolved later,
843  *          false means it's the exact function symbol.
844  * Returns:
845  *      `s` turned into an expression, `ErrorExp` if an error occurred
846  */
847 Expression symbolToExp(Dsymbol s, const ref Loc loc, Scope *sc, bool hasOverloads)
848 {
849     static if (LOGSEMANTIC)
850     {
851         printf("DsymbolExp::resolve(%s %s)\n", s.kind(), s.toChars());
852     }
853 
854 Lagain:
855     Expression e;
856 
857     //printf("DsymbolExp:: %p '%s' is a symbol\n", this, toChars());
858     //printf("s = '%s', s.kind = '%s'\n", s.toChars(), s.kind());
859     Dsymbol olds = s;
860     Declaration d = s.isDeclaration();
861     if (d && (d.storage_class & STC.templateparameter))
862     {
863         s = s.toAlias();
864     }
865     else
866     {
867         // functions are checked after overloading
868         // templates are checked after matching constraints
869         if (!s.isFuncDeclaration() && !s.isTemplateDeclaration())
870         {
871             s.checkDeprecated(loc, sc);
872             if (d)
873                 d.checkDisabled(loc, sc);
874         }
875 
876         // https://issues.dlang.org/show_bug.cgi?id=12023
877         // if 's' is a tuple variable, the tuple is returned.
878         s = s.toAlias();
879 
880         //printf("s = '%s', s.kind = '%s', s.needThis() = %p\n", s.toChars(), s.kind(), s.needThis());
881         if (s != olds && !s.isFuncDeclaration() && !s.isTemplateDeclaration())
882         {
883             s.checkDeprecated(loc, sc);
884             if (d)
885                 d.checkDisabled(loc, sc);
886         }
887 
888         if (auto sd = s.isDeclaration())
889         {
890             if (sd.isSystem())
891             {
892                 if (sc.setUnsafePreview(global.params.systemVariables, false, loc,
893                     "cannot access `@system` variable `%s` in @safe code", sd))
894                 {
895                     return ErrorExp.get();
896                 }
897             }
898         }
899     }
900 
901     if (auto em = s.isEnumMember())
902     {
903         return em.getVarExp(loc, sc);
904     }
905     if (auto v = s.isVarDeclaration())
906     {
907         //printf("Identifier '%s' is a variable, type '%s'\n", s.toChars(), v.type.toChars());
908         if (sc.intypeof == 1 && !v.inuse)
909             v.dsymbolSemantic(sc);
910         if (!v.type ||                  // during variable type inference
911             !v.type.deco && v.inuse)    // during variable type semantic
912         {
913             if (v.inuse)    // variable type depends on the variable itself
914                 error(loc, "circular reference to %s `%s`", v.kind(), v.toPrettyChars());
915             else            // variable type cannot be determined
916                 error(loc, "forward reference to %s `%s`", v.kind(), v.toPrettyChars());
917             return ErrorExp.get();
918         }
919         if (v.type.ty == Terror)
920             return ErrorExp.get();
921 
922         if ((v.storage_class & STC.manifest) && v._init)
923         {
924             if (v.inuse)
925             {
926                 error(loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
927                 return ErrorExp.get();
928             }
929             e = v.expandInitializer(loc);
930             v.inuse++;
931             e = e.expressionSemantic(sc);
932             v.inuse--;
933             return e;
934         }
935 
936         // We need to run semantics to correctly set 'STC.field' if it is a member variable
937         // that could be forward referenced. This is needed for 'v.needThis()' to work
938         if (v.isThis())
939             v.dsymbolSemantic(sc);
940 
941         // Change the ancestor lambdas to delegate before hasThis(sc) call.
942         if (v.checkNestedReference(sc, loc))
943             return ErrorExp.get();
944 
945         if (v.needThis() && hasThis(sc))
946             e = new DotVarExp(loc, new ThisExp(loc), v);
947         else
948             e = new VarExp(loc, v);
949         e = e.expressionSemantic(sc);
950         return e;
951     }
952     if (auto fld = s.isFuncLiteralDeclaration())
953     {
954         //printf("'%s' is a function literal\n", fld.toChars());
955         e = new FuncExp(loc, fld);
956         return e.expressionSemantic(sc);
957     }
958     if (auto f = s.isFuncDeclaration())
959     {
960         f = f.toAliasFunc();
961         if (!f.functionSemantic())
962             return ErrorExp.get();
963 
964         if (!hasOverloads && f.checkForwardRef(loc))
965             return ErrorExp.get();
966 
967         auto fd = s.isFuncDeclaration();
968         fd.type = f.type;
969         return new VarExp(loc, fd, hasOverloads);
970     }
971     if (OverDeclaration od = s.isOverDeclaration())
972     {
973         e = new VarExp(loc, od, true);
974         e.type = Type.tvoid;
975         return e;
976     }
977     if (OverloadSet o = s.isOverloadSet())
978     {
979         //printf("'%s' is an overload set\n", o.toChars());
980         return new OverExp(loc, o);
981     }
982 
983     if (Import imp = s.isImport())
984     {
985         if (!imp.pkg)
986         {
987             .error(loc, "forward reference of import `%s`", imp.toChars());
988             return ErrorExp.get();
989         }
990         auto ie = new ScopeExp(loc, imp.pkg);
991         return ie.expressionSemantic(sc);
992     }
993     if (Package pkg = s.isPackage())
994     {
995         auto ie = new ScopeExp(loc, pkg);
996         return ie.expressionSemantic(sc);
997     }
998     if (Module mod = s.isModule())
999     {
1000         auto ie = new ScopeExp(loc, mod);
1001         return ie.expressionSemantic(sc);
1002     }
1003     if (Nspace ns = s.isNspace())
1004     {
1005         auto ie = new ScopeExp(loc, ns);
1006         return ie.expressionSemantic(sc);
1007     }
1008 
1009     if (Type t = s.getType())
1010     {
1011         return (new TypeExp(loc, t)).expressionSemantic(sc);
1012     }
1013 
1014     if (TupleDeclaration tup = s.isTupleDeclaration())
1015     {
1016         if (tup.needThis() && hasThis(sc))
1017             e = new DotVarExp(loc, new ThisExp(loc), tup);
1018         else
1019             e = new TupleExp(loc, tup);
1020         e = e.expressionSemantic(sc);
1021         return e;
1022     }
1023 
1024     if (TemplateInstance ti = s.isTemplateInstance())
1025     {
1026         ti.dsymbolSemantic(sc);
1027         if (!ti.inst || ti.errors)
1028             return ErrorExp.get();
1029         s = ti.toAlias();
1030         if (!s.isTemplateInstance())
1031             goto Lagain;
1032         e = new ScopeExp(loc, ti);
1033         e = e.expressionSemantic(sc);
1034         return e;
1035     }
1036     if (TemplateDeclaration td = s.isTemplateDeclaration())
1037     {
1038         Dsymbol p = td.toParentLocal();
1039         FuncDeclaration fdthis = hasThis(sc);
1040         AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
1041         if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
1042         {
1043             e = new DotTemplateExp(loc, new ThisExp(loc), td);
1044         }
1045         else
1046             e = new TemplateExp(loc, td);
1047         e = e.expressionSemantic(sc);
1048         return e;
1049     }
1050 
1051     .error(loc, "%s `%s` is not a variable", s.kind(), s.toChars());
1052     return ErrorExp.get();
1053 }
1054 
1055 /*************************************************************
1056  * Given var, get the
1057  * right `this` pointer if var is in an outer class, but our
1058  * existing `this` pointer is in an inner class.
1059  * Params:
1060  *      loc = location to use for error messages
1061  *      sc = context
1062  *      ad = struct or class we need the correct `this` for
1063  *      e1 = existing `this`
1064  *      var = the specific member of ad we're accessing
1065  *      flag = if true, return `null` instead of throwing an error
1066  * Returns:
1067  *      Expression representing the `this` for the var
1068  */
1069 private Expression getRightThis(const ref Loc loc, Scope* sc, AggregateDeclaration ad, Expression e1, Dsymbol var, int flag = 0)
1070 {
1071     //printf("\ngetRightThis(e1 = %s, ad = %s, var = %s)\n", e1.toChars(), ad.toChars(), var.toChars());
1072 L1:
1073     Type t = e1.type.toBasetype();
1074     //printf("e1.type = %s, var.type = %s\n", e1.type.toChars(), var.type.toChars());
1075 
1076     if (e1.op == EXP.objcClassReference)
1077     {
1078         // We already have an Objective-C class reference, just use that as 'this'.
1079         return e1;
1080     }
1081     else if (ad && ad.isClassDeclaration && ad.isClassDeclaration.classKind == ClassKind.objc &&
1082              var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
1083              var.isFuncDeclaration.objc.selector)
1084     {
1085         return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
1086     }
1087 
1088     /* Access of a member which is a template parameter in dual-scope scenario
1089      * class A { inc(alias m)() { ++m; } } // `m` needs `this` of `B`
1090      * class B {int m; inc() { new A().inc!m(); } }
1091      */
1092     if (e1.op == EXP.this_)
1093     {
1094         FuncDeclaration f = hasThis(sc);
1095         if (f && f.hasDualContext())
1096         {
1097             if (f.followInstantiationContext(ad))
1098             {
1099                 e1 = new VarExp(loc, f.vthis);
1100                 e1 = new PtrExp(loc, e1);
1101                 e1 = new IndexExp(loc, e1, IntegerExp.literal!1);
1102                 e1 = getThisSkipNestedFuncs(loc, sc, f.toParent2(), ad, e1, t, var);
1103                 if (e1.op == EXP.error)
1104                     return e1;
1105                 goto L1;
1106             }
1107         }
1108     }
1109 
1110     /* If e1 is not the 'this' pointer for ad
1111      */
1112     if (ad &&
1113         !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
1114         !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
1115     {
1116         ClassDeclaration cd = ad.isClassDeclaration();
1117         ClassDeclaration tcd = t.isClassHandle();
1118 
1119         /* e1 is the right this if ad is a base class of e1
1120          */
1121         if (!cd || !tcd || !(tcd == cd || cd.isBaseOf(tcd, null)))
1122         {
1123             /* Only classes can be inner classes with an 'outer'
1124              * member pointing to the enclosing class instance
1125              */
1126             if (tcd && tcd.isNested())
1127             {
1128                 /* e1 is the 'this' pointer for an inner class: tcd.
1129                  * Rewrite it as the 'this' pointer for the outer class.
1130                  */
1131                 auto vthis = tcd.followInstantiationContext(ad) ? tcd.vthis2 : tcd.vthis;
1132                 e1 = new DotVarExp(loc, e1, vthis);
1133                 e1.type = vthis.type;
1134                 e1.type = e1.type.addMod(t.mod);
1135                 // Do not call ensureStaticLinkTo()
1136                 //e1 = e1.semantic(sc);
1137 
1138                 // Skip up over nested functions, and get the enclosing
1139                 // class type.
1140                 e1 = getThisSkipNestedFuncs(loc, sc, tcd.toParentP(ad), ad, e1, t, var);
1141                 if (e1.op == EXP.error)
1142                     return e1;
1143                 goto L1;
1144             }
1145 
1146             /* Can't find a path from e1 to ad
1147              */
1148             if (flag)
1149                 return null;
1150             e1.error("`this` for `%s` needs to be type `%s` not type `%s`", var.toChars(), ad.toChars(), t.toChars());
1151             return ErrorExp.get();
1152         }
1153     }
1154     return e1;
1155 }
1156 
1157 /*
1158  * Check whether `outerFunc` and `calledFunc` have the same `this`.
1159  * If `calledFunc` is the member of a base class of the class that contains
1160  * `outerFunc` we consider that they have the same this.
1161  *
1162  * This function is used to test whether `this` needs to be prepended to
1163  * a function call or function symbol. For example:
1164  *
1165  * struct X
1166  * {
1167  *    void gun() {}
1168  * }
1169  * struct A
1170  * {
1171  *      void fun() {}
1172  *      void sun()
1173  *      {
1174  *          fun();
1175  *          X.gun();  // error
1176  *      }
1177  * }
1178  *
1179  * When `fun` is called, `outerfunc` = `sun` and `calledFunc = `fun`.
1180  * `sun` is a member of `A` and `fun` is also a member of `A`, therefore
1181  * `this` can be prepended to `fun`. When `gun` is called (it will result
1182  * in an error, but that is not relevant here), which is a member of `X`,
1183  * no `this` is needed because the outer function does not have the same
1184  * `this` as `gun`.
1185  *
1186  * Returns:
1187  *  `true` if outerFunc and calledFunc may use the same `this` pointer.
1188  * `false` otherwise.
1189  */
1190 private bool haveSameThis(FuncDeclaration outerFunc, FuncDeclaration calledFunc)
1191 {
1192     auto thisAd = outerFunc.isMemberLocal();
1193     if (!thisAd)
1194         return false;
1195 
1196     auto requiredAd = calledFunc.isMemberLocal();
1197     if (!requiredAd)
1198         return false;
1199 
1200     if (thisAd == requiredAd)
1201         return true;
1202 
1203     // outerfunc is the member of a base class that contains calledFunc,
1204     // then we consider that they have the same this.
1205     auto cd = requiredAd.isClassDeclaration();
1206     if (!cd)
1207         return false;
1208 
1209     if (cd.isBaseOf2(thisAd.isClassDeclaration()))
1210         return true;
1211 
1212     // if outerfunc is the member of a nested aggregate, then let
1213     // getRightThis take care of this.
1214     if (thisAd.isNested())
1215         return true;
1216 
1217     return false;
1218 }
1219 
1220 /***************************************
1221  * Pull out any properties.
1222  */
1223 private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 = null, BinExp saveAtts = null)
1224 {
1225     //printf("resolvePropertiesX, e1 = %s %s, e2 = %s\n", EXPtoString(e1.op).ptr, e1.toChars(), e2 ? e2.toChars() : null);
1226     Loc loc = e1.loc;
1227 
1228     OverloadSet os;
1229     Dsymbol s;
1230     Objects* tiargs;
1231     Type tthis;
1232     if (auto de = e1.isDotExp())
1233     {
1234         if (auto oe = de.e2.isOverExp())
1235         {
1236             tiargs = null;
1237             tthis = de.e1.type;
1238             os = oe.vars;
1239             goto Los;
1240         }
1241     }
1242     else if (e1.isOverExp())
1243     {
1244         tiargs = null;
1245         tthis = null;
1246         os = e1.isOverExp().vars;
1247     Los:
1248         assert(os);
1249         FuncDeclaration fd = null;
1250         if (e2)
1251         {
1252             e2 = e2.expressionSemantic(sc);
1253             if (e2.op == EXP.error)
1254                 return ErrorExp.get();
1255             e2 = resolveProperties(sc, e2);
1256 
1257             Expressions a;
1258             a.push(e2);
1259 
1260             for (size_t i = 0; i < os.a.length; i++)
1261             {
1262                 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet))
1263                 {
1264                     if (f.errors)
1265                         return ErrorExp.get();
1266                     fd = f;
1267                     assert(fd.type.ty == Tfunction);
1268                 }
1269             }
1270             if (fd)
1271             {
1272                 Expression e = new CallExp(loc, e1, e2);
1273                 return e.expressionSemantic(sc);
1274             }
1275         }
1276         {
1277             for (size_t i = 0; i < os.a.length; i++)
1278             {
1279                 if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
1280                 {
1281                     if (f.errors)
1282                         return ErrorExp.get();
1283                     fd = f;
1284                     assert(fd.type.ty == Tfunction);
1285                     auto tf = fd.type.isTypeFunction();
1286                     if (!tf.isref && e2)
1287                     {
1288                         error(loc, "%s is not an lvalue", e1.toChars());
1289                         return ErrorExp.get();
1290                     }
1291                 }
1292             }
1293             if (fd)
1294             {
1295                 Expression e = new CallExp(loc, e1);
1296                 if (e2)
1297                 {
1298                     e = new AssignExp(loc, e, e2);
1299                     if (saveAtts)
1300                     {
1301                         (cast(BinExp)e).att1 = saveAtts.att1;
1302                         (cast(BinExp)e).att2 = saveAtts.att2;
1303                     }
1304                 }
1305                 return e.expressionSemantic(sc);
1306             }
1307         }
1308         if (e2)
1309             goto Leprop;
1310     }
1311     else if (auto dti = e1.isDotTemplateInstanceExp())
1312     {
1313         if (!dti.findTempDecl(sc))
1314             goto Leprop;
1315         if (!dti.ti.semanticTiargs(sc))
1316             goto Leprop;
1317         tiargs = dti.ti.tiargs;
1318         tthis = dti.e1.type;
1319         if ((os = dti.ti.tempdecl.isOverloadSet()) !is null)
1320             goto Los;
1321         if ((s = dti.ti.tempdecl) !is null)
1322             goto Lfd;
1323     }
1324     else if (auto dte = e1.isDotTemplateExp())
1325     {
1326         s = dte.td;
1327         tiargs = null;
1328         tthis = dte.e1.type;
1329         goto Lfd;
1330     }
1331     else if (auto se = e1.isScopeExp())
1332     {
1333         s = se.sds;
1334         TemplateInstance ti = s.isTemplateInstance();
1335         if (ti && !ti.semanticRun && ti.tempdecl)
1336         {
1337             //assert(ti.needsTypeInference(sc));
1338             if (!ti.semanticTiargs(sc))
1339                 goto Leprop;
1340             tiargs = ti.tiargs;
1341             tthis = null;
1342             if ((os = ti.tempdecl.isOverloadSet()) !is null)
1343                 goto Los;
1344             if ((s = ti.tempdecl) !is null)
1345                 goto Lfd;
1346         }
1347     }
1348     else if (auto te = e1.isTemplateExp())
1349     {
1350         s = te.td;
1351         tiargs = null;
1352         tthis = null;
1353         goto Lfd;
1354     }
1355     else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
1356     {
1357         DotVarExp dve = e1.isDotVarExp();
1358         s = dve.var;
1359         tiargs = null;
1360         tthis = dve.e1.type;
1361         goto Lfd;
1362     }
1363     else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
1364     {
1365         // ImportC: do not implicitly call function if no ( ) are present
1366     }
1367     else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
1368     {
1369         s = e1.isVarExp().var;
1370         tiargs = null;
1371         tthis = null;
1372     Lfd:
1373         assert(s);
1374         if (e2)
1375         {
1376             e2 = e2.expressionSemantic(sc);
1377             if (e2.op == EXP.error)
1378                 return ErrorExp.get();
1379             e2 = resolveProperties(sc, e2);
1380 
1381             Expressions a;
1382             a.push(e2);
1383 
1384             FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(&a), FuncResolveFlag.quiet);
1385             if (fd && fd.type)
1386             {
1387                 if (fd.errors)
1388                     return ErrorExp.get();
1389                 if (!checkSymbolAccess(sc, fd))
1390                 {
1391                     // @@@DEPRECATED_2.105@@@
1392                     // When turning into error, uncomment the return statement
1393                     TypeFunction tf = fd.type.isTypeFunction();
1394                     deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
1395                                 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1396                     //return ErrorExp.get();
1397                 }
1398                 assert(fd.type.ty == Tfunction);
1399                 Expression e = new CallExp(loc, e1, e2);
1400                 return e.expressionSemantic(sc);
1401             }
1402         }
1403         {
1404             FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
1405             if (fd && fd.type)
1406             {
1407                 if (fd.errors)
1408                     return ErrorExp.get();
1409                 TypeFunction tf = fd.type.isTypeFunction();
1410                 if (!e2 || tf.isref)
1411                 {
1412                     if (!checkSymbolAccess(sc, fd))
1413                     {
1414                         // @@@DEPRECATED_2.105@@@
1415                         // When turning into error, uncomment the return statement
1416                         deprecation(loc, "function `%s` of type `%s` is not accessible from module `%s`",
1417                                     fd.toPrettyChars(), tf.toChars, sc._module.toChars);
1418                         //return ErrorExp.get();
1419                     }
1420                     Expression e = new CallExp(loc, e1);
1421                     if (e2)
1422                     {
1423                         e = new AssignExp(loc, e, e2);
1424                         if (saveAtts)
1425                         {
1426                             (cast(BinExp)e).att1 = saveAtts.att1;
1427                             (cast(BinExp)e).att2 = saveAtts.att2;
1428                         }
1429                     }
1430                     return e.expressionSemantic(sc);
1431                 }
1432             }
1433         }
1434         if (FuncDeclaration fd = s.isFuncDeclaration())
1435         {
1436             // Keep better diagnostic message for invalid property usage of functions
1437             assert(fd.type.ty == Tfunction);
1438             Expression e = new CallExp(loc, e1, e2);
1439             return e.expressionSemantic(sc);
1440         }
1441         if (e2)
1442             goto Leprop;
1443     }
1444     if (auto ve = e1.isVarExp())
1445     {
1446         if (auto v = ve.var.isVarDeclaration())
1447         {
1448             if (ve.checkPurity(sc, v))
1449                 return ErrorExp.get();
1450         }
1451     }
1452     if (e2)
1453         return null;
1454 
1455     if (e1.type && !e1.isTypeExp()) // function type is not a property
1456     {
1457         /* Look for e1 being a lazy parameter; rewrite as delegate call
1458          * only if the symbol wasn't already treated as a delegate
1459          */
1460         auto ve = e1.isVarExp();
1461         if (ve && ve.var.storage_class & STC.lazy_ && !ve.delegateWasExtracted)
1462         {
1463                 Expression e = new CallExp(loc, e1);
1464                 return e.expressionSemantic(sc);
1465         }
1466         else if (e1.isDotVarExp())
1467         {
1468             // Check for reading overlapped pointer field in @safe code.
1469             if (checkUnsafeAccess(sc, e1, true, true))
1470                 return ErrorExp.get();
1471         }
1472         else if (auto ce = e1.isCallExp())
1473         {
1474             // Check for reading overlapped pointer field in @safe code.
1475             if (checkUnsafeAccess(sc, ce.e1, true, true))
1476                 return ErrorExp.get();
1477         }
1478     }
1479 
1480     if (!e1.type)
1481     {
1482         error(loc, "cannot resolve type for %s", e1.toChars());
1483         e1 = ErrorExp.get();
1484     }
1485     return e1;
1486 
1487 Leprop:
1488     error(loc, "not a property %s", e1.toChars());
1489     return ErrorExp.get();
1490 }
1491 
1492 extern (C++) Expression resolveProperties(Scope* sc, Expression e)
1493 {
1494     //printf("resolveProperties(%s)\n", e.toChars());
1495     e = resolvePropertiesX(sc, e);
1496     if (e.checkRightThis(sc))
1497         return ErrorExp.get();
1498     return e;
1499 }
1500 
1501 /****************************************
1502  * The common type is determined by applying ?: to each pair.
1503  * Output:
1504  *      exps[]  properties resolved, implicitly cast to common type, rewritten in place
1505  * Returns:
1506  *      The common type, or `null` if an error has occured
1507  */
1508 private Type arrayExpressionToCommonType(Scope* sc, ref Expressions exps)
1509 {
1510     /* Still have a problem with:
1511      *  ubyte[][] = [ cast(ubyte[])"hello", [1]];
1512      * which works if the array literal is initialized top down with the ubyte[][]
1513      * type, but fails with this function doing bottom up typing.
1514      */
1515 
1516     //printf("arrayExpressionToCommonType()\n");
1517     scope IntegerExp integerexp = IntegerExp.literal!0;
1518     scope CondExp condexp = new CondExp(Loc.initial, integerexp, null, null);
1519 
1520     Type t0 = null;
1521     Expression e0 = null;
1522     bool foundType;
1523 
1524     for (size_t i = 0; i < exps.length; i++)
1525     {
1526         Expression e = exps[i];
1527         if (!e)
1528             continue;
1529 
1530         e = resolveProperties(sc, e);
1531         if (!e.type)
1532         {
1533             e.error("`%s` has no value", e.toChars());
1534             t0 = Type.terror;
1535             continue;
1536         }
1537         if (e.op == EXP.type)
1538         {
1539             foundType = true; // do not break immediately, there might be more errors
1540             e.checkValue(); // report an error "type T has no value"
1541             t0 = Type.terror;
1542             continue;
1543         }
1544         if (e.type.ty == Tvoid)
1545         {
1546             // void expressions do not concur to the determination of the common
1547             // type.
1548             continue;
1549         }
1550         if (checkNonAssignmentArrayOp(e))
1551         {
1552             t0 = Type.terror;
1553             continue;
1554         }
1555 
1556         e = doCopyOrMove(sc, e);
1557 
1558         if (!foundType && t0 && !t0.equals(e.type))
1559         {
1560             /* This applies ?: to merge the types. It's backwards;
1561              * ?: should call this function to merge types.
1562              */
1563             condexp.type = null;
1564             condexp.e1 = e0;
1565             condexp.e2 = e;
1566             condexp.loc = e.loc;
1567             Expression ex = condexp.expressionSemantic(sc);
1568             if (ex.op == EXP.error)
1569                 e = ex;
1570             else
1571             {
1572                 // Convert to common type
1573                 exps[i] = condexp.e1.castTo(sc, condexp.type);
1574                 e = condexp.e2.castTo(sc, condexp.type);
1575             }
1576         }
1577         e0 = e;
1578         t0 = e.type;
1579         if (e.op != EXP.error)
1580             exps[i] = e;
1581     }
1582 
1583     // [] is typed as void[]
1584     if (!t0)
1585         return Type.tvoid;
1586 
1587     // It's an error, don't do the cast
1588     if (t0.ty == Terror)
1589         return null;
1590 
1591     for (size_t i = 0; i < exps.length; i++)
1592     {
1593         Expression e = exps[i];
1594         if (!e)
1595             continue;
1596 
1597         e = e.implicitCastTo(sc, t0);
1598         if (e.op == EXP.error)
1599         {
1600             /* https://issues.dlang.org/show_bug.cgi?id=13024
1601              * a workaround for the bug in typeMerge -
1602              * it should paint e1 and e2 by deduced common type,
1603              * but doesn't in this particular case.
1604              */
1605             return null;
1606         }
1607         exps[i] = e;
1608     }
1609     return t0;
1610 }
1611 
1612 private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expression e2)
1613 {
1614     Expression e;
1615     switch (op)
1616     {
1617     case EXP.addAssign:
1618         e = new AddExp(loc, e1, e2);
1619         break;
1620 
1621     case EXP.minAssign:
1622         e = new MinExp(loc, e1, e2);
1623         break;
1624 
1625     case EXP.mulAssign:
1626         e = new MulExp(loc, e1, e2);
1627         break;
1628 
1629     case EXP.divAssign:
1630         e = new DivExp(loc, e1, e2);
1631         break;
1632 
1633     case EXP.modAssign:
1634         e = new ModExp(loc, e1, e2);
1635         break;
1636 
1637     case EXP.andAssign:
1638         e = new AndExp(loc, e1, e2);
1639         break;
1640 
1641     case EXP.orAssign:
1642         e = new OrExp(loc, e1, e2);
1643         break;
1644 
1645     case EXP.xorAssign:
1646         e = new XorExp(loc, e1, e2);
1647         break;
1648 
1649     case EXP.leftShiftAssign:
1650         e = new ShlExp(loc, e1, e2);
1651         break;
1652 
1653     case EXP.rightShiftAssign:
1654         e = new ShrExp(loc, e1, e2);
1655         break;
1656 
1657     case EXP.unsignedRightShiftAssign:
1658         e = new UshrExp(loc, e1, e2);
1659         break;
1660 
1661     default:
1662         assert(0);
1663     }
1664     return e;
1665 }
1666 
1667 /*********************
1668  * Rewrite:
1669  *    array.length op= e2
1670  */
1671 private Expression rewriteOpAssign(BinExp exp)
1672 {
1673     ArrayLengthExp ale = exp.e1.isArrayLengthExp();
1674     if (ale.e1.isVarExp())
1675     {
1676         // array.length = array.length op e2
1677         Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
1678         e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
1679         return e;
1680     }
1681     else
1682     {
1683         // (ref tmp = array;), tmp.length = tmp.length op e2
1684         auto tmp = copyToTemp(STC.ref_, "__arraylength", ale.e1);
1685         Expression e1 = new ArrayLengthExp(ale.loc, new VarExp(ale.loc, tmp));
1686         Expression elvalue = e1.syntaxCopy();
1687         Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
1688         e = new AssignExp(exp.loc, elvalue, e);
1689         e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
1690         return e;
1691     }
1692 }
1693 
1694 /****************************************
1695  * Preprocess arguments to function.
1696  *
1697  * Tuples in argumentList get expanded, properties resolved, rewritten in place
1698  *
1699  * Params:
1700  *     sc           =  scope
1701  *     argumentList =  arguments to function
1702  *     reportErrors =  whether or not to report errors here. Some callers are not
1703  *                      checking actual function params, so they'll do their own error reporting
1704  * Returns:
1705  *     `true` when a semantic error occurred
1706  */
1707 private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
1708 {
1709     Expressions* exps = argumentList.arguments;
1710     bool err = false;
1711     if (exps)
1712     {
1713         expandTuples(exps, argumentList.names);
1714 
1715         for (size_t i = 0; i < exps.length; i++)
1716         {
1717             Expression arg = (*exps)[i];
1718             arg = resolveProperties(sc, arg);
1719             arg = arg.arrayFuncConv(sc);
1720             if (arg.op == EXP.type)
1721             {
1722                 // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
1723                 arg = resolveAliasThis(sc, arg);
1724 
1725                 if (arg.op == EXP.type)
1726                 {
1727                     if (reportErrors)
1728                     {
1729                         arg.error("cannot pass type `%s` as a function argument", arg.toChars());
1730                         arg = ErrorExp.get();
1731                     }
1732                     err = true;
1733                 }
1734             }
1735             else if (arg.type.toBasetype().ty == Tfunction)
1736             {
1737                 if (reportErrors)
1738                 {
1739                     arg.error("cannot pass function `%s` as a function argument", arg.toChars());
1740                     arg = ErrorExp.get();
1741                 }
1742                 err = true;
1743             }
1744             else if (checkNonAssignmentArrayOp(arg))
1745             {
1746                 arg = ErrorExp.get();
1747                 err = true;
1748             }
1749             (*exps)[i] = arg;
1750         }
1751     }
1752     return err;
1753 }
1754 
1755 /********************************************
1756  * Issue an error if default construction is disabled for type t.
1757  * Default construction is required for arrays and 'out' parameters.
1758  * Returns:
1759  *      true    an error was issued
1760  */
1761 private bool checkDefCtor(Loc loc, Type t)
1762 {
1763     if (auto ts = t.baseElemOf().isTypeStruct())
1764     {
1765         StructDeclaration sd = ts.sym;
1766         if (sd.noDefaultCtor)
1767         {
1768             sd.error(loc, "default construction is disabled");
1769             return true;
1770         }
1771     }
1772     return false;
1773 }
1774 
1775 /****************************************
1776  * Now that we know the exact type of the function we're calling,
1777  * the arguments[] need to be adjusted:
1778  *      1. implicitly convert argument to the corresponding parameter type
1779  *      2. add default arguments for any missing arguments
1780  *      3. do default promotions on arguments corresponding to ...
1781  *      4. add hidden _arguments[] argument
1782  *      5. call copy constructor for struct value arguments
1783  * Params:
1784  *      loc       = location of function call
1785  *      sc        = context
1786  *      tf        = type of the function
1787  *      ethis     = `this` argument, `null` if none or not known
1788  *      tthis     = type of `this` argument, `null` if no `this` argument
1789  *      argumentsList = array of actual arguments to function call
1790  *      fd        = the function being called, `null` if called indirectly
1791  *      prettype  = set to return type of function
1792  *      peprefix  = set to expression to execute before `arguments[]` are evaluated, `null` if none
1793  * Returns:
1794  *      true    errors happened
1795  */
1796 private bool functionParameters(const ref Loc loc, Scope* sc,
1797     TypeFunction tf, Expression ethis, Type tthis, ArgumentList argumentList, FuncDeclaration fd,
1798     Type* prettype, Expression* peprefix)
1799 {
1800     Expressions* arguments = argumentList.arguments;
1801     //printf("functionParameters() %s\n", fd ? fd.toChars() : "");
1802     assert(arguments);
1803     assert(fd || tf.next);
1804     const size_t nparams = tf.parameterList.length;
1805     const olderrors = global.errors;
1806     bool err = false;
1807     Expression eprefix = null;
1808     *peprefix = null;
1809 
1810     if (argumentList.names)
1811     {
1812         const(char)* msg = null;
1813         auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
1814         if (!resolvedArgs)
1815         {
1816             // while errors are usually already caught by `tf.callMatch`,
1817             // this can happen when calling `typeof(freefunc)`
1818             if (msg)
1819                 error(loc, "%s", msg);
1820             return true;
1821         }
1822         // note: the argument list should be mutated with named arguments / default arguments,
1823         // so we can't simply change the pointer like `arguments = resolvedArgs;`
1824         arguments.setDim(0);
1825         arguments.pushSlice((*resolvedArgs)[]);
1826     }
1827     size_t nargs = arguments ? arguments.length : 0;
1828 
1829     if (nargs > nparams && tf.parameterList.varargs == VarArg.none)
1830     {
1831         error(loc, "expected %llu arguments, not %llu for non-variadic function type `%s`", cast(ulong)nparams, cast(ulong)nargs, tf.toChars());
1832         return true;
1833     }
1834 
1835     // If inferring return type, and semantic3() needs to be run if not already run
1836     if (!tf.next && fd.inferRetType)
1837     {
1838         fd.functionSemantic();
1839     }
1840     else if (fd && fd.parent)
1841     {
1842         TemplateInstance ti = fd.parent.isTemplateInstance();
1843         if (ti && ti.tempdecl)
1844         {
1845             fd.functionSemantic3();
1846         }
1847     }
1848 
1849     /* If calling a pragma(inline, true) function,
1850      * set flag to later scan for inlines.
1851      */
1852     if (fd && fd.inlining == PINLINE.always)
1853     {
1854         if (sc._module)
1855             sc._module.hasAlwaysInlines = true;
1856         if (sc.func)
1857             sc.func.hasAlwaysInlines = true;
1858     }
1859 
1860     const isCtorCall = fd && fd.needThis() && fd.isCtorDeclaration();
1861 
1862     const size_t n = (nargs > nparams) ? nargs : nparams; // n = max(nargs, nparams)
1863 
1864     /* If the function return type has wildcards in it, we'll need to figure out the actual type
1865      * based on the actual argument types.
1866      * Start with the `this` argument, later on merge into wildmatch the mod bits of the rest
1867      * of the arguments.
1868      */
1869     MOD wildmatch = (tthis && !isCtorCall) ? tthis.Type.deduceWild(tf, false) : 0;
1870 
1871     bool done = false;
1872     foreach (const i; 0 .. n)
1873     {
1874         Expression arg = (i < nargs) ? (*arguments)[i] : null;
1875 
1876         if (i < nparams)
1877         {
1878             bool errorArgs()
1879             {
1880                 error(loc, "expected %llu function arguments, not %llu", cast(ulong)nparams, cast(ulong)nargs);
1881                 return true;
1882             }
1883 
1884             Parameter p = tf.parameterList[i];
1885 
1886             if (!arg)
1887             {
1888                 if (!p.defaultArg)
1889                 {
1890                     if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams)
1891                         goto L2;
1892                     return errorArgs();
1893                 }
1894                 arg = p.defaultArg;
1895                 if (!arg.type)
1896                     arg = arg.expressionSemantic(sc);
1897                 arg = inlineCopy(arg, sc);
1898                 // __FILE__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__
1899                 arg = arg.resolveLoc(loc, sc);
1900                 if (i >= nargs)
1901                 {
1902                     arguments.push(arg);
1903                     nargs++;
1904                 }
1905                 else
1906                     (*arguments)[i] = arg;
1907             }
1908             else
1909             {
1910                 if (isDefaultInitOp(arg.op))
1911                 {
1912                     arg = arg.resolveLoc(loc, sc);
1913                     (*arguments)[i] = arg;
1914                 }
1915             }
1916 
1917 
1918             if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
1919             {
1920                 //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
1921                 {
1922                     MATCH m;
1923                     if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
1924                     {
1925                         if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
1926                             goto L2;
1927                         else if (nargs != nparams)
1928                             return errorArgs();
1929                         goto L1;
1930                     }
1931                 }
1932             L2:
1933                 Type tb = p.type.toBasetype();
1934                 switch (tb.ty)
1935                 {
1936                 case Tsarray:
1937                 case Tarray:
1938                     {
1939                         /* Create a static array variable v of type arg.type:
1940                          *  T[dim] __arrayArg = [ arguments[i], ..., arguments[nargs-1] ];
1941                          *
1942                          * The array literal in the initializer of the hidden variable
1943                          * is now optimized.
1944                          * https://issues.dlang.org/show_bug.cgi?id=2356
1945                          */
1946                         Type tbn = (cast(TypeArray)tb).next;    // array element type
1947                         Type tret = p.isLazyArray();
1948 
1949                         auto elements = new Expressions(nargs - i);
1950                         foreach (u; 0 .. elements.length)
1951                         {
1952                             Expression a = (*arguments)[i + u];
1953                             if (tret && a.implicitConvTo(tret))
1954                             {
1955                                 // p is a lazy array of delegates, tret is return type of the delegates
1956                                 a = a.implicitCastTo(sc, tret)
1957                                      .optimize(WANTvalue)
1958                                      .toDelegate(tret, sc);
1959                             }
1960                             else
1961                                 a = a.implicitCastTo(sc, tbn);
1962                             a = a.addDtorHook(sc);
1963                             (*elements)[u] = a;
1964                         }
1965                         // https://issues.dlang.org/show_bug.cgi?id=14395
1966                         // Convert to a static array literal, or its slice.
1967                         arg = new ArrayLiteralExp(loc, tbn.sarrayOf(nargs - i), elements);
1968                         if (tb.ty == Tarray)
1969                         {
1970                             arg = new SliceExp(loc, arg, null, null);
1971                             arg.type = p.type;
1972                         }
1973                         break;
1974                     }
1975                 case Tclass:
1976                     {
1977                         /* Set arg to be:
1978                          *      new Tclass(arg0, arg1, ..., argn)
1979                          */
1980                         auto args = new Expressions(nargs - i);
1981                         foreach (u; i .. nargs)
1982                             (*args)[u - i] = (*arguments)[u];
1983                         arg = new NewExp(loc, null, p.type, args);
1984                         break;
1985                     }
1986                 default:
1987                     if (!arg)
1988                     {
1989                         error(loc, "not enough arguments");
1990                         return true;
1991                     }
1992                     break;
1993                 }
1994                 arg = arg.expressionSemantic(sc);
1995                 //printf("\targ = '%s'\n", arg.toChars());
1996                 arguments.setDim(i + 1);
1997                 (*arguments)[i] = arg;
1998                 nargs = i + 1;
1999                 done = true;
2000             }
2001 
2002         L1:
2003             if (!(p.isLazy() && p.type.ty == Tvoid))
2004             {
2005                 if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
2006                 {
2007                     wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
2008                     //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
2009                 }
2010             }
2011         }
2012         if (done)
2013             break;
2014     }
2015     if ((wildmatch == MODFlags.mutable || wildmatch == MODFlags.immutable_) &&
2016         tf.next && tf.next.hasWild() &&
2017         (tf.isref || !tf.next.implicitConvTo(tf.next.immutableOf())))
2018     {
2019         bool errorInout(MOD wildmatch)
2020         {
2021             const(char)* s = wildmatch == MODFlags.mutable ? "mutable" : MODtoChars(wildmatch);
2022             error(loc, "modify `inout` to `%s` is not allowed inside `inout` function", s);
2023             return true;
2024         }
2025 
2026         if (fd)
2027         {
2028             /* If the called function may return the reference to
2029              * outer inout data, it should be rejected.
2030              *
2031              * void foo(ref inout(int) x) {
2032              *   ref inout(int) bar(inout(int)) { return x; }
2033              *   struct S {
2034              *      ref inout(int) bar() inout { return x; }
2035              *      ref inout(int) baz(alias a)() inout { return x; }
2036              *   }
2037              *   bar(int.init) = 1;  // bad!
2038              *   S().bar() = 1;      // bad!
2039              * }
2040              * void test() {
2041              *   int a;
2042              *   auto s = foo(a);
2043              *   s.baz!a() = 1;      // bad!
2044              * }
2045              *
2046              */
2047             bool checkEnclosingWild(Dsymbol s)
2048             {
2049                 bool checkWild(Dsymbol s)
2050                 {
2051                     if (!s)
2052                         return false;
2053                     if (auto ad = s.isAggregateDeclaration())
2054                     {
2055                         if (ad.isNested())
2056                             return checkEnclosingWild(s);
2057                     }
2058                     else if (auto ff = s.isFuncDeclaration())
2059                     {
2060                         if (ff.type.isTypeFunction().iswild)
2061                             return errorInout(wildmatch);
2062 
2063                         if (ff.isNested() || ff.isThis())
2064                             return checkEnclosingWild(s);
2065                     }
2066                     return false;
2067                 }
2068 
2069                 Dsymbol ctx0 = s.toParent2();
2070                 Dsymbol ctx1 = s.toParentLocal();
2071                 if (checkWild(ctx0))
2072                     return true;
2073                 if (ctx0 != ctx1)
2074                     return checkWild(ctx1);
2075                 return false;
2076             }
2077             if ((fd.isThis() || fd.isNested()) && checkEnclosingWild(fd))
2078                 return true;
2079         }
2080         else if (tf.isWild())
2081             return errorInout(wildmatch);
2082     }
2083 
2084     Expression firstArg = null;
2085     final switch (returnParamDest(tf, tthis))
2086     {
2087         case ReturnParamDest.returnVal:
2088             break;
2089         case ReturnParamDest.firstArg:
2090             firstArg = nargs > 0 ? (*arguments)[0] : null;
2091             break;
2092         case ReturnParamDest.this_:
2093             firstArg = ethis;
2094             break;
2095     }
2096 
2097     assert(nargs >= nparams);
2098     foreach (const i, arg; (*arguments)[0 .. nargs])
2099     {
2100         assert(arg);
2101         if (i < nparams)
2102         {
2103             Parameter p = tf.parameterList[i];
2104             Type targ = arg.type;               // keep original type for isCopyable() because alias this
2105                                                 // resolution may hide an uncopyable type
2106 
2107             if (!(p.isLazy() && p.type.ty == Tvoid))
2108             {
2109                 Type tprm = p.type.hasWild()
2110                     ? p.type.substWildTo(wildmatch)
2111                     : p.type;
2112 
2113                 const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
2114                 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
2115                 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
2116                 {
2117                     //printf("arg.type = %s, p.type = %s\n", arg.type.toChars(), p.type.toChars());
2118                     arg = arg.implicitCastTo(sc, tprm);
2119                     arg = arg.optimize(WANTvalue, p.isReference());
2120                 }
2121             }
2122 
2123             // Support passing rvalue to `in` parameters
2124             if ((p.storageClass & (STC.in_ | STC.ref_)) == (STC.in_ | STC.ref_))
2125             {
2126                 if (!arg.isLvalue())
2127                 {
2128                     auto v = copyToTemp(STC.exptemp, "__rvalue", arg);
2129                     Expression ev = new DeclarationExp(arg.loc, v);
2130                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2131                     arg = ev.expressionSemantic(sc);
2132                 }
2133                 arg = arg.toLvalue(sc, arg);
2134 
2135                 // Look for mutable misaligned pointer, etc., in @safe mode
2136                 err |= checkUnsafeAccess(sc, arg, false, true);
2137             }
2138             else if (p.storageClass & STC.ref_)
2139             {
2140                 if (global.params.rvalueRefParam == FeatureState.enabled &&
2141                     !arg.isLvalue() &&
2142                     targ.isCopyable())
2143                 {   /* allow rvalues to be passed to ref parameters by copying
2144                      * them to a temp, then pass the temp as the argument
2145                      */
2146                     auto v = copyToTemp(0, "__rvalue", arg);
2147                     Expression ev = new DeclarationExp(arg.loc, v);
2148                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
2149                     arg = ev.expressionSemantic(sc);
2150                 }
2151                 arg = arg.toLvalue(sc, arg);
2152 
2153                 // Look for mutable misaligned pointer, etc., in @safe mode
2154                 err |= checkUnsafeAccess(sc, arg, false, true);
2155             }
2156             else if (p.storageClass & STC.out_)
2157             {
2158                 Type t = arg.type;
2159                 if (!t.isMutable() || !t.isAssignable()) // check blit assignable
2160                 {
2161                     arg.error("cannot modify struct `%s` with immutable members", arg.toChars());
2162                     err = true;
2163                 }
2164                 else
2165                 {
2166                     // Look for misaligned pointer, etc., in @safe mode
2167                     err |= checkUnsafeAccess(sc, arg, false, true);
2168                     err |= checkDefCtor(arg.loc, t); // t must be default constructible
2169                 }
2170                 arg = arg.toLvalue(sc, arg);
2171             }
2172             else if (p.isLazy())
2173             {
2174                 // Convert lazy argument to a delegate
2175                 auto t = (p.type.ty == Tvoid) ? p.type : arg.type;
2176                 arg = toDelegate(arg, t, sc);
2177             }
2178             //printf("arg: %s\n", arg.toChars());
2179             //printf("type: %s\n", arg.type.toChars());
2180             //printf("param: %s\n", p.toChars());
2181 
2182             const pStc = tf.parameterStorageClass(tthis, p);
2183 
2184             if (firstArg && (pStc & STC.return_))
2185             {
2186                 /* Argument value can be assigned to firstArg.
2187                  * Check arg to see if it matters.
2188                  */
2189                 err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
2190             }
2191             // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
2192             // as lazy parameters to the next function, but that isn't escaping.
2193             // The arguments of `_d_arraycatnTX` are already handled in
2194             // expressionsem.d, via `checkNewEscape`. Without `-dip1000`, the
2195             // check does not return an error, so the lowering of `a ~ b` to
2196             // `_d_arraycatnTX(a, b)` still occurs.
2197             else if (!(pStc & STC.lazy_) && (!fd ||  fd.ident != Id._d_arraycatnTX))
2198             {
2199                 /* Argument value can escape from the called function.
2200                  * Check arg to see if it matters.
2201                  */
2202                 VarDeclaration vPar = fd ? (fd.parameters ? (*fd.parameters)[i] : null) : null;
2203                 err |= checkParamArgumentEscape(sc, fd, p.ident, vPar, cast(STC) pStc, arg, false, false);
2204             }
2205 
2206             // Turning heap allocations into stack allocations is dangerous without dip1000, since `scope` inference
2207             // may be unreliable when scope violations only manifest as deprecation warnings.
2208             // However, existing `@nogc` code may rely on it, so still do it when the parameter is explicitly marked `scope`
2209             const explicitScope = p.isLazy() ||
2210                 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
2211             if ((pStc & (STC.scope_ | STC.lazy_)) &&
2212                 ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
2213                 !(pStc & STC.return_))
2214             {
2215                 /* Argument value cannot escape from the called function.
2216                  */
2217                 Expression a = arg;
2218                 if (auto ce = a.isCastExp())
2219                     a = ce.e1;
2220 
2221                 ArrayLiteralExp ale;
2222                 if (p.type.toBasetype().ty == Tarray &&
2223                     (ale = a.isArrayLiteralExp()) !is null && ale.elements && ale.elements.length > 0)
2224                 {
2225                     // allocate the array literal as temporary static array on the stack
2226                     ale.type = ale.type.nextOf().sarrayOf(ale.elements.length);
2227                     auto tmp = copyToTemp(0, "__arrayliteral_on_stack", ale);
2228                     tmp.storage_class |= STC.exptemp;
2229                     auto declareTmp = new DeclarationExp(ale.loc, tmp);
2230                     auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp),
2231                         p.type.substWildTo(MODFlags.mutable));
2232                     arg = CommaExp.combine(declareTmp, castToSlice);
2233                     arg = arg.expressionSemantic(sc);
2234                 }
2235                 else if (auto fe = a.isFuncExp())
2236                 {
2237                     /* Function literals can only appear once, so if this
2238                      * appearance was scoped, there cannot be any others.
2239                      */
2240                     fe.fd.tookAddressOf = 0;
2241                 }
2242                 else if (auto de = a.isDelegateExp())
2243                 {
2244                     /* For passing a delegate to a scoped parameter,
2245                      * this doesn't count as taking the address of it.
2246                      * We only worry about 'escaping' references to the function.
2247                      */
2248                     if (auto ve = de.e1.isVarExp())
2249                     {
2250                         if (auto f = ve.var.isFuncDeclaration())
2251                         {
2252                             if (f.tookAddressOf)
2253                                 --f.tookAddressOf;
2254                             //printf("--tookAddressOf = %d\n", f.tookAddressOf);
2255                         }
2256                     }
2257                 }
2258             }
2259             if (!p.isReference())
2260                 err |= arg.checkSharedAccess(sc);
2261 
2262             arg = arg.optimize(WANTvalue, p.isReference());
2263         }
2264         else
2265         {
2266             // These will be the trailing ... arguments
2267             // If not D linkage, do promotions
2268             if (tf.linkage != LINK.d)
2269             {
2270                 // Promote bytes, words, etc., to ints
2271                 arg = integralPromotions(arg, sc);
2272 
2273                 // Promote floats to doubles
2274                 switch (arg.type.ty)
2275                 {
2276                 case Tfloat32:
2277                     arg = arg.castTo(sc, Type.tfloat64);
2278                     break;
2279 
2280                 case Timaginary32:
2281                     arg = arg.castTo(sc, Type.timaginary64);
2282                     break;
2283 
2284                 default:
2285                     break;
2286                 }
2287                 if (tf.parameterList.varargs == VarArg.variadic ||
2288                     tf.parameterList.varargs == VarArg.KRvariadic)
2289                 {
2290                     const(char)* p = tf.linkage == LINK.c ? "extern(C)" : "extern(C++)";
2291                     if (arg.type.ty == Tarray)
2292                     {
2293                         arg.error("cannot pass dynamic arrays to `%s` vararg functions", p);
2294                         err = true;
2295                     }
2296                     if (arg.type.ty == Tsarray)
2297                     {
2298                         arg.error("cannot pass static arrays to `%s` vararg functions", p);
2299                         err = true;
2300                     }
2301                 }
2302             }
2303 
2304             // Do not allow types that need destructors or copy constructors.
2305             if (arg.type.needsDestruction())
2306             {
2307                 arg.error("cannot pass types that need destruction as variadic arguments");
2308                 err = true;
2309             }
2310             if (arg.type.needsCopyOrPostblit())
2311             {
2312                 arg.error("cannot pass types with postblits or copy constructors as variadic arguments");
2313                 err = true;
2314             }
2315 
2316             // Convert static arrays to dynamic arrays
2317             // BUG: I don't think this is right for D2
2318             Type tb = arg.type.toBasetype();
2319             if (auto ts = tb.isTypeSArray())
2320             {
2321                 Type ta = ts.next.arrayOf();
2322                 if (ts.size(arg.loc) == 0)
2323                     arg = new NullExp(arg.loc, ta);
2324                 else
2325                     arg = arg.castTo(sc, ta);
2326             }
2327             if (tb.ty == Tstruct)
2328             {
2329                 //arg = callCpCtor(sc, arg);
2330             }
2331             // Give error for overloaded function addresses
2332             if (auto se = arg.isSymOffExp())
2333             {
2334                 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
2335                 {
2336                     arg.error("function `%s` is overloaded", arg.toChars());
2337                     err = true;
2338                 }
2339             }
2340             err |= arg.checkValue();
2341             err |= arg.checkSharedAccess(sc);
2342             arg = arg.optimize(WANTvalue);
2343         }
2344         (*arguments)[i] = arg;
2345     }
2346 
2347     /* If calling C scanf(), printf(), or any variants, check the format string against the arguments
2348      */
2349     const isVa_list = tf.parameterList.varargs == VarArg.none;
2350     if (fd && fd.printf)
2351     {
2352         if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2353         {
2354             checkPrintfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2355         }
2356     }
2357     else if (fd && fd.scanf)
2358     {
2359         if (auto se = (*arguments)[nparams - 1 - isVa_list].isStringExp())
2360         {
2361             checkScanfFormat(se.loc, se.peekString(), (*arguments)[nparams .. nargs], isVa_list);
2362         }
2363     }
2364     else
2365     {
2366         // TODO: not checking the "v" functions yet (for those, check format string only, not args)
2367     }
2368 
2369     /* Remaining problems:
2370      * 1. value structs (or static arrays of them) that need to be copy constructed
2371      * 2. value structs (or static arrays of them) that have destructors, and subsequent arguments that may throw before the
2372      *    function gets called.
2373      * 3. value structs need to be destructed after the function call for platforms where the caller destroys the arguments.
2374      * Those are handled by doing the argument construction in 'eprefix' so that if a later argument throws, they are cleaned
2375      * up properly. Pushing arguments on the stack then cannot fail.
2376      */
2377      {
2378         /* Does Problem (3) apply?
2379          */
2380         const bool callerDestroysArgs = !target.isCalleeDestroyingArgs(tf);
2381 
2382         /* Compute indices of last throwing argument and first arg needing destruction.
2383          * Used to not set up destructors unless an arg needs destruction on a throw
2384          * in a later argument.
2385          */
2386         ptrdiff_t lastthrow = -1;   // last argument that may throw
2387         ptrdiff_t firstdtor = -1;   // first argument that needs destruction
2388         ptrdiff_t lastdtor  = -1;   // last argument that needs destruction
2389         for (ptrdiff_t i = 0; i != nargs; i++)
2390         {
2391             Expression arg = (*arguments)[i];
2392             if (canThrow(arg, sc.func, false))
2393                 lastthrow = i;
2394             if (arg.type.needsDestruction())
2395             {
2396                 Parameter p = (i >= nparams ? null : tf.parameterList[i]);
2397                 if (!(p && (p.isLazy() || p.isReference())))
2398                 {
2399                     if (firstdtor == -1)
2400                         firstdtor = i;
2401                     lastdtor = i;
2402                 }
2403             }
2404         }
2405 
2406         /* Do we need 'eprefix' for problems 2 or 3?
2407          */
2408         const bool needsPrefix = callerDestroysArgs
2409             ? firstdtor >= 0 // true if any argument needs destruction
2410             : firstdtor >= 0 && lastthrow >= 0 &&
2411               (lastthrow - firstdtor) > 0; // last throw after first destruction
2412         const ptrdiff_t lastPrefix = callerDestroysArgs
2413             ? lastdtor   // up to last argument requiring destruction
2414             : lastthrow; // up to last potentially throwing argument
2415 
2416         /* Problem 3: initialize 'eprefix' by declaring the gate
2417          */
2418         VarDeclaration gate;
2419         if (needsPrefix && !callerDestroysArgs)
2420         {
2421             // eprefix => bool __gate [= false]
2422             Identifier idtmp = Identifier.generateId("__gate");
2423             gate = new VarDeclaration(loc, Type.tbool, idtmp, null);
2424             gate.storage_class |= STC.temp | STC.ctfe | STC.volatile_;
2425             gate.dsymbolSemantic(sc);
2426 
2427             auto ae = new DeclarationExp(loc, gate);
2428             eprefix = ae.expressionSemantic(sc);
2429         }
2430 
2431         for (ptrdiff_t i = 0; i != nargs; i++)
2432         {
2433             Expression arg = (*arguments)[i];
2434             //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
2435 
2436             Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
2437             const bool isRef = parameter && parameter.isReference();
2438             const bool isLazy = parameter && parameter.isLazy();
2439 
2440             /* Skip lazy parameters
2441              */
2442             if (isLazy)
2443                 continue;
2444 
2445             /* Do we have 'eprefix' and aren't past 'lastPrefix' yet?
2446              * Then declare a temporary variable for this arg and append that declaration
2447              * to 'eprefix', which will implicitly take care of potential problem 1) for
2448              * this arg.
2449              * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
2450              * excluding all lazy parameters.
2451              */
2452             if (needsPrefix && (lastPrefix - i) >= 0)
2453             {
2454                 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
2455                                        // Problem 3: last throwing arg doesn't require dtor patching
2456                                        (callerDestroysArgs || i != lastPrefix);
2457 
2458                 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
2459                  */
2460                 auto tmp = copyToTemp(
2461                     (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
2462                     needsDtor ? "__pfx" : "__pfy",
2463                     !isRef ? arg : arg.addressOf());
2464                 tmp.dsymbolSemantic(sc);
2465 
2466                 if (callerDestroysArgs)
2467                 {
2468                     /* Problem 4: Normal temporary, destructed after the call
2469                      */
2470                     if (needsDtor)
2471                         tmp.isArgDtorVar = true;   // mark it so that the backend passes it by ref to the function being called
2472                 }
2473                 else
2474                 {
2475                     /* Problem 2: Modify the destructor so it only runs if gate==false,
2476                      * i.e., only if there was a throw while constructing the args
2477                      */
2478                     if (!needsDtor)
2479                     {
2480                         if (tmp.edtor)
2481                         {
2482                             assert(i == lastPrefix);
2483                             tmp.edtor = null;
2484                         }
2485                     }
2486                     else
2487                     {
2488                         // edtor => (__gate || edtor)
2489                         assert(tmp.edtor);
2490                         Expression e = tmp.edtor;
2491                         e = new LogicalExp(e.loc, EXP.orOr, new VarExp(e.loc, gate), e);
2492                         tmp.edtor = e.expressionSemantic(sc);
2493                         //printf("edtor: %s\n", tmp.edtor.toChars());
2494                     }
2495                 }
2496 
2497                 // eprefix => (eprefix, auto __pfx/y = arg)
2498                 auto ae = new DeclarationExp(loc, tmp);
2499                 eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc));
2500 
2501                 // arg => __pfx/y
2502                 arg = new VarExp(loc, tmp);
2503                 arg = arg.expressionSemantic(sc);
2504                 if (isRef)
2505                 {
2506                     arg = new PtrExp(loc, arg);
2507                     arg = arg.expressionSemantic(sc);
2508                 }
2509 
2510                 /* Problem 2: Last throwing arg?
2511                  * Then finalize eprefix => (eprefix, gate = true), i.e., disable the
2512                  * dtors right after constructing the last throwing arg.
2513                  * From now on, the callee will take care of destructing the args because
2514                  * the args are implicitly moved into function parameters.
2515                  */
2516                 if (!callerDestroysArgs && i == lastPrefix)
2517                 {
2518                     auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true));
2519                     eprefix = Expression.combine(eprefix, e.expressionSemantic(sc));
2520                 }
2521             }
2522             else // not part of 'eprefix'
2523             {
2524                 /* Handle problem 1) by calling the copy constructor for value structs
2525                  * (or static arrays of them) if appropriate.
2526                  */
2527                 Type tv = arg.type.baseElemOf();
2528                 if (!isRef && tv.ty == Tstruct)
2529                     arg = doCopyOrMove(sc, arg, parameter ? parameter.type : null);
2530             }
2531 
2532             (*arguments)[i] = arg;
2533         }
2534     }
2535     //if (eprefix) printf("eprefix: %s\n", eprefix.toChars());
2536 
2537     /* Test compliance with DIP1021 Argument Ownership and Function Calls
2538      */
2539     if (global.params.useDIP1021 && (tf.trust == TRUST.safe || tf.trust == TRUST.default_) ||
2540         tf.islive)
2541         err |= checkMutableArguments(sc, fd, tf, ethis, arguments, false);
2542 
2543     // If D linkage and variadic, add _arguments[] as first argument
2544     if (tf.isDstyleVariadic())
2545     {
2546         assert(arguments.length >= nparams);
2547 
2548         auto args = new Parameters(arguments.length - nparams);
2549         for (size_t i = 0; i < arguments.length - nparams; i++)
2550         {
2551             auto arg = new Parameter(STC.in_, (*arguments)[nparams + i].type, null, null, null);
2552             (*args)[i] = arg;
2553         }
2554         auto tup = new TypeTuple(args);
2555         Expression e = (new TypeidExp(loc, tup)).expressionSemantic(sc);
2556         arguments.insert(0, e);
2557     }
2558 
2559     /* Determine function return type: tret
2560      */
2561     Type tret = tf.next;
2562     if (isCtorCall)
2563     {
2564         //printf("[%s] fd = %s %s, %d %d %d\n", loc.toChars(), fd.toChars(), fd.type.toChars(),
2565         //    wildmatch, tf.isWild(), fd.isReturnIsolated());
2566         if (!tthis)
2567         {
2568             assert(sc.intypeof || global.errors);
2569             tthis = fd.isThis().type.addMod(fd.type.mod);
2570         }
2571         if (tf.isWild() && !fd.isReturnIsolated())
2572         {
2573             if (wildmatch)
2574                 tret = tret.substWildTo(wildmatch);
2575             int offset;
2576             if (!tret.implicitConvTo(tthis) && !(MODimplicitConv(tret.mod, tthis.mod) && tret.isBaseOf(tthis, &offset) && offset == 0))
2577             {
2578                 const(char)* s1 = tret.isNaked() ? " mutable" : tret.modToChars();
2579                 const(char)* s2 = tthis.isNaked() ? " mutable" : tthis.modToChars();
2580                 .error(loc, "`inout` constructor `%s` creates%s object, not%s", fd.toPrettyChars(), s1, s2);
2581                 err = true;
2582             }
2583         }
2584         tret = tthis;
2585     }
2586     else if (wildmatch && tret)
2587     {
2588         /* Adjust function return type based on wildmatch
2589          */
2590         //printf("wildmatch = x%x, tret = %s\n", wildmatch, tret.toChars());
2591         tret = tret.substWildTo(wildmatch);
2592     }
2593 
2594     *prettype = tret;
2595     *peprefix = eprefix;
2596     return (err || olderrors != global.errors);
2597 }
2598 
2599 /**
2600  * Determines whether a symbol represents a module or package
2601  * (Used as a helper for is(type == module) and is(type == package))
2602  *
2603  * Params:
2604  *  sym = the symbol to be checked
2605  *
2606  * Returns:
2607  *  the symbol which `sym` represents (or `null` if it doesn't represent a `Package`)
2608  */
2609 Package resolveIsPackage(Dsymbol sym)
2610 {
2611     Package pkg;
2612     if (Import imp = sym.isImport())
2613     {
2614         if (imp.pkg is null)
2615         {
2616             .error(sym.loc, "internal compiler error: unable to process forward-referenced import `%s`",
2617                     imp.toChars());
2618             assert(0);
2619         }
2620         pkg = imp.pkg;
2621     }
2622     else if (auto mod = sym.isModule())
2623         pkg = mod.isPackageFile ? mod.pkg : sym.isPackage();
2624     else
2625         pkg = sym.isPackage();
2626     if (pkg)
2627         pkg.resolvePKGunknown();
2628     return pkg;
2629 }
2630 
2631 
2632 private extern (C++) final class ExpressionSemanticVisitor : Visitor
2633 {
2634     alias visit = Visitor.visit;
2635 
2636     Scope* sc;
2637     Expression result;
2638 
2639     this(Scope* sc) scope
2640     {
2641         this.sc = sc;
2642     }
2643 
2644     private void setError()
2645     {
2646         result = ErrorExp.get();
2647     }
2648 
2649     /**************************
2650      * Semantically analyze Expression.
2651      * Determine types, fold constants, etc.
2652      */
2653     override void visit(Expression e)
2654     {
2655         static if (LOGSEMANTIC)
2656         {
2657             printf("Expression::semantic() %s\n", e.toChars());
2658         }
2659         if (e.type)
2660             e.type = e.type.typeSemantic(e.loc, sc);
2661         else
2662             e.type = Type.tvoid;
2663         result = e;
2664     }
2665 
2666     override void visit(IntegerExp e)
2667     {
2668         assert(e.type);
2669         if (e.type.ty == Terror)
2670             return setError();
2671 
2672         assert(e.type.deco);
2673         e.setInteger(e.getInteger());
2674         result = e;
2675     }
2676 
2677     override void visit(RealExp e)
2678     {
2679         if (!e.type)
2680             e.type = Type.tfloat64;
2681         else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
2682         {
2683             /* Convert to core.stdc.config.complex
2684              */
2685             Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
2686             if (t.ty == Terror)
2687                 return setError();
2688 
2689             Type tf;
2690             switch (e.type.ty)
2691             {
2692                 case Timaginary32: tf = Type.tfloat32; break;
2693                 case Timaginary64: tf = Type.tfloat64; break;
2694                 case Timaginary80: tf = Type.tfloat80; break;
2695                 default:
2696                     assert(0);
2697             }
2698 
2699             /* Construct ts{re : 0.0, im : e}
2700              */
2701             TypeStruct ts = t.isTypeStruct;
2702             Expressions* elements = new Expressions(2);
2703             (*elements)[0] = new RealExp(e.loc,    CTFloat.zero, tf);
2704             (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
2705             Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
2706             result = sle.expressionSemantic(sc);
2707             return;
2708         }
2709         else
2710             e.type = e.type.typeSemantic(e.loc, sc);
2711         result = e;
2712     }
2713 
2714     override void visit(ComplexExp e)
2715     {
2716         if (!e.type)
2717             e.type = Type.tcomplex80;
2718         else
2719             e.type = e.type.typeSemantic(e.loc, sc);
2720         result = e;
2721     }
2722 
2723     override void visit(IdentifierExp exp)
2724     {
2725         static if (LOGSEMANTIC)
2726         {
2727             printf("IdentifierExp::semantic('%s')\n", exp.ident.toChars());
2728         }
2729         if (exp.type) // This is used as the dummy expression
2730         {
2731             result = exp;
2732             return;
2733         }
2734 
2735         Dsymbol scopesym;
2736         Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
2737         if (s)
2738         {
2739             if (s.errors)
2740                 return setError();
2741 
2742             Expression e;
2743 
2744             /* See if the symbol was a member of an enclosing 'with'
2745              */
2746             WithScopeSymbol withsym = scopesym.isWithScopeSymbol();
2747             if (withsym && withsym.withstate.wthis && symbolIsVisible(sc, s))
2748             {
2749                 /* Disallow shadowing
2750                  */
2751                 // First find the scope of the with
2752                 Scope* scwith = sc;
2753                 while (scwith.scopesym != scopesym)
2754                 {
2755                     scwith = scwith.enclosing;
2756                     assert(scwith);
2757                 }
2758                 // Look at enclosing scopes for symbols with the same name,
2759                 // in the same function
2760                 for (Scope* scx = scwith; scx && scx.func == scwith.func; scx = scx.enclosing)
2761                 {
2762                     Dsymbol s2;
2763                     if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
2764                     {
2765                         exp.error("with symbol `%s` is shadowing local symbol `%s`", s.toPrettyChars(), s2.toPrettyChars());
2766                         return setError();
2767                     }
2768                 }
2769                 s = s.toAlias();
2770 
2771                 // Same as wthis.ident
2772                 //  TODO: DotIdExp.semantic will find 'ident' from 'wthis' again.
2773                 //  The redudancy should be removed.
2774                 e = new VarExp(exp.loc, withsym.withstate.wthis);
2775                 e = new DotIdExp(exp.loc, e, exp.ident);
2776                 e = e.expressionSemantic(sc);
2777             }
2778             else
2779             {
2780                 if (withsym)
2781                 {
2782                     if (withsym.withstate.exp.type.ty != Tvoid)
2783                     {
2784                         // 'with (exp)' is a type expression
2785                         // or 's' is not visible there (for error message)
2786                         e = new TypeExp(exp.loc, withsym.withstate.exp.type);
2787                     }
2788                     else
2789                     {
2790                         // 'with (exp)' is a Package/Module
2791                         e = withsym.withstate.exp;
2792                     }
2793                     e = new DotIdExp(exp.loc, e, exp.ident);
2794                     result = e.expressionSemantic(sc);
2795                     return;
2796                 }
2797 
2798                 /* If f is really a function template,
2799                  * then replace f with the function template declaration.
2800                  */
2801                 FuncDeclaration f = s.isFuncDeclaration();
2802                 if (f)
2803                 {
2804                     TemplateDeclaration td = getFuncTemplateDecl(f);
2805                     if (td)
2806                     {
2807                         if (td.overroot) // if not start of overloaded list of TemplateDeclaration's
2808                             td = td.overroot; // then get the start
2809                         e = new TemplateExp(exp.loc, td, f);
2810                         e = e.expressionSemantic(sc);
2811                         result = e;
2812                         return;
2813                     }
2814                 }
2815 
2816                 if (global.params.fixAliasThis)
2817                 {
2818                     ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
2819                     if (expDsym)
2820                     {
2821                         //printf("expDsym = %s\n", expDsym.exp.toChars());
2822                         result = expDsym.exp.expressionSemantic(sc);
2823                         return;
2824                     }
2825                 }
2826                 // Haven't done overload resolution yet, so pass 1
2827                 e = symbolToExp(s, exp.loc, sc, true);
2828             }
2829             result = e;
2830             return;
2831         }
2832 
2833         if (!global.params.fixAliasThis && hasThis(sc))
2834         {
2835             for (AggregateDeclaration ad = sc.getStructClassScope(); ad;)
2836             {
2837                 if (ad.aliasthis)
2838                 {
2839                     Expression e;
2840                     e = new ThisExp(exp.loc);
2841                     e = new DotIdExp(exp.loc, e, ad.aliasthis.ident);
2842                     e = new DotIdExp(exp.loc, e, exp.ident);
2843                     e = e.trySemantic(sc);
2844                     if (e)
2845                     {
2846                         result = e;
2847                         return;
2848                     }
2849                 }
2850 
2851                 auto cd = ad.isClassDeclaration();
2852                 if (cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
2853                 {
2854                     ad = cd.baseClass;
2855                     continue;
2856                 }
2857                 break;
2858             }
2859         }
2860 
2861         if (exp.ident == Id.ctfe)
2862         {
2863             if (sc.flags & SCOPE.ctfe)
2864             {
2865                 exp.error("variable `__ctfe` cannot be read at compile time");
2866                 return setError();
2867             }
2868 
2869             // Create the magic __ctfe bool variable
2870             auto vd = new VarDeclaration(exp.loc, Type.tbool, Id.ctfe, null);
2871             vd.storage_class |= STC.temp;
2872             vd.semanticRun = PASS.semanticdone;
2873             Expression e = new VarExp(exp.loc, vd);
2874             e = e.expressionSemantic(sc);
2875             result = e;
2876             return;
2877         }
2878 
2879         // If we've reached this point and are inside a with() scope then we may
2880         // try one last attempt by checking whether the 'wthis' object supports
2881         // dynamic dispatching via opDispatch.
2882         // This is done by rewriting this expression as wthis.ident.
2883         // The innermost with() scope of the hierarchy to satisfy the condition
2884         // above wins.
2885         // https://issues.dlang.org/show_bug.cgi?id=6400
2886         for (Scope* sc2 = sc; sc2; sc2 = sc2.enclosing)
2887         {
2888             if (!sc2.scopesym)
2889                 continue;
2890 
2891             if (auto ss = sc2.scopesym.isWithScopeSymbol())
2892             {
2893                 if (ss.withstate.wthis)
2894                 {
2895                     Expression e;
2896                     e = new VarExp(exp.loc, ss.withstate.wthis);
2897                     e = new DotIdExp(exp.loc, e, exp.ident);
2898                     e = e.trySemantic(sc);
2899                     if (e)
2900                     {
2901                         result = e;
2902                         return;
2903                     }
2904                 }
2905                 // Try Type.opDispatch (so the static version)
2906                 else if (ss.withstate.exp && ss.withstate.exp.op == EXP.type)
2907                 {
2908                     if (Type t = ss.withstate.exp.isTypeExp().type)
2909                     {
2910                         Expression e;
2911                         e = new TypeExp(exp.loc, t);
2912                         e = new DotIdExp(exp.loc, e, exp.ident);
2913                         e = e.trySemantic(sc);
2914                         if (e)
2915                         {
2916                             result = e;
2917                             return;
2918                         }
2919                     }
2920                 }
2921             }
2922         }
2923 
2924         /* Look for what user might have meant
2925          */
2926         if (const n = importHint(exp.ident.toString()))
2927             exp.error("`%s` is not defined, perhaps `import %.*s;` is needed?", exp.ident.toChars(), cast(int)n.length, n.ptr);
2928         else if (auto s2 = sc.search_correct(exp.ident))
2929             exp.error("undefined identifier `%s`, did you mean %s `%s`?", exp.ident.toChars(), s2.kind(), s2.toChars());
2930         else if (const p = Scope.search_correct_C(exp.ident))
2931             exp.error("undefined identifier `%s`, did you mean `%s`?", exp.ident.toChars(), p);
2932         else if (exp.ident == Id.dollar)
2933             exp.error("undefined identifier `$`");
2934         else
2935             exp.error("undefined identifier `%s`", exp.ident.toChars());
2936 
2937         result = ErrorExp.get();
2938     }
2939 
2940     override void visit(DsymbolExp e)
2941     {
2942         result = symbolToExp(e.s, e.loc, sc, e.hasOverloads);
2943     }
2944 
2945     override void visit(ThisExp e)
2946     {
2947         static if (LOGSEMANTIC)
2948         {
2949             printf("ThisExp::semantic()\n");
2950         }
2951         if (e.type)
2952         {
2953             result = e;
2954             return;
2955         }
2956 
2957         FuncDeclaration fd = hasThis(sc); // fd is the uplevel function with the 'this' variable
2958         AggregateDeclaration ad;
2959 
2960         /* Special case for typeof(this) and typeof(super) since both
2961          * should work even if they are not inside a non-static member function
2962          */
2963         if (!fd && sc.intypeof == 1)
2964         {
2965             // Find enclosing struct or class
2966             for (Dsymbol s = sc.getStructClassScope(); 1; s = s.parent)
2967             {
2968                 if (!s)
2969                 {
2970                     e.error("`%s` is not in a class or struct scope", e.toChars());
2971                     return setError();
2972                 }
2973                 ClassDeclaration cd = s.isClassDeclaration();
2974                 if (cd)
2975                 {
2976                     e.type = cd.type;
2977                     result = e;
2978                     return;
2979                 }
2980                 StructDeclaration sd = s.isStructDeclaration();
2981                 if (sd)
2982                 {
2983                     e.type = sd.type;
2984                     result = e;
2985                     return;
2986                 }
2987             }
2988         }
2989         if (!fd)
2990         {
2991             e.error("`this` is only defined in non-static member functions, not `%s`", sc.parent.toChars());
2992             return setError();
2993         }
2994 
2995         assert(fd.vthis);
2996         e.var = fd.vthis;
2997         assert(e.var.parent);
2998         ad = fd.isMemberLocal();
2999         if (!ad)
3000             ad = fd.isMember2();
3001         assert(ad);
3002         e.type = ad.type.addMod(e.var.type.mod);
3003 
3004         if (e.var.checkNestedReference(sc, e.loc))
3005             return setError();
3006 
3007         result = e;
3008     }
3009 
3010     override void visit(SuperExp e)
3011     {
3012         static if (LOGSEMANTIC)
3013         {
3014             printf("SuperExp::semantic('%s')\n", e.toChars());
3015         }
3016         if (e.type)
3017         {
3018             result = e;
3019             return;
3020         }
3021 
3022         FuncDeclaration fd = hasThis(sc);
3023         ClassDeclaration cd;
3024         Dsymbol s;
3025 
3026         /* Special case for typeof(this) and typeof(super) since both
3027          * should work even if they are not inside a non-static member function
3028          */
3029         if (!fd && sc.intypeof == 1)
3030         {
3031             // Find enclosing class
3032             for (s = sc.getStructClassScope(); 1; s = s.parent)
3033             {
3034                 if (!s)
3035                 {
3036                     e.error("`%s` is not in a class scope", e.toChars());
3037                     return setError();
3038                 }
3039                 cd = s.isClassDeclaration();
3040                 if (cd)
3041                 {
3042                     cd = cd.baseClass;
3043                     if (!cd)
3044                     {
3045                         e.error("class `%s` has no `super`", s.toChars());
3046                         return setError();
3047                     }
3048                     e.type = cd.type;
3049                     result = e;
3050                     return;
3051                 }
3052             }
3053         }
3054         if (!fd)
3055             goto Lerr;
3056 
3057         e.var = fd.vthis;
3058         assert(e.var && e.var.parent);
3059 
3060         s = fd.toParentDecl();
3061         if (s.isTemplateDeclaration()) // allow inside template constraint
3062             s = s.toParent();
3063         assert(s);
3064         cd = s.isClassDeclaration();
3065         //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
3066         if (!cd)
3067             goto Lerr;
3068         if (!cd.baseClass)
3069         {
3070             e.error("no base class for `%s`", cd.toChars());
3071             e.type = cd.type.addMod(e.var.type.mod);
3072         }
3073         else
3074         {
3075             e.type = cd.baseClass.type;
3076             e.type = e.type.castMod(e.var.type.mod);
3077         }
3078 
3079         if (e.var.checkNestedReference(sc, e.loc))
3080             return setError();
3081 
3082         result = e;
3083         return;
3084 
3085     Lerr:
3086         e.error("`super` is only allowed in non-static class member functions");
3087         result = ErrorExp.get();
3088     }
3089 
3090     override void visit(NullExp e)
3091     {
3092         static if (LOGSEMANTIC)
3093         {
3094             printf("NullExp::semantic('%s')\n", e.toChars());
3095         }
3096         // NULL is the same as (void *)0
3097         if (e.type)
3098         {
3099             result = e;
3100             return;
3101         }
3102         e.type = Type.tnull;
3103         result = e;
3104     }
3105 
3106     override void visit(StringExp e)
3107     {
3108         static if (LOGSEMANTIC)
3109         {
3110             printf("StringExp::semantic() %s\n", e.toChars());
3111         }
3112         if (e.type)
3113         {
3114             result = e;
3115             return;
3116         }
3117 
3118         OutBuffer buffer;
3119         size_t newlen = 0;
3120         size_t u;
3121         dchar c;
3122 
3123         switch (e.postfix)
3124         {
3125         case 'd':
3126             for (u = 0; u < e.len;)
3127             {
3128                 if (const p = utf_decodeChar(e.peekString(), u, c))
3129                 {
3130                     e.error("%.*s", cast(int)p.length, p.ptr);
3131                     return setError();
3132                 }
3133                 else
3134                 {
3135                     buffer.write4(c);
3136                     newlen++;
3137                 }
3138             }
3139             buffer.write4(0);
3140             e.setData(buffer.extractData(), newlen, 4);
3141             if (sc && sc.flags & SCOPE.Cfile)
3142                 e.type = Type.tuns32.sarrayOf(e.len + 1);
3143             else
3144                 e.type = Type.tdchar.immutableOf().arrayOf();
3145             e.committed = true;
3146             break;
3147 
3148         case 'w':
3149             for (u = 0; u < e.len;)
3150             {
3151                 if (const p = utf_decodeChar(e.peekString(), u, c))
3152                 {
3153                     e.error("%.*s", cast(int)p.length, p.ptr);
3154                     return setError();
3155                 }
3156                 else
3157                 {
3158                     buffer.writeUTF16(c);
3159                     newlen++;
3160                     if (c >= 0x10000)
3161                         newlen++;
3162                 }
3163             }
3164             buffer.writeUTF16(0);
3165             e.setData(buffer.extractData(), newlen, 2);
3166             if (sc && sc.flags & SCOPE.Cfile)
3167                 e.type = Type.tuns16.sarrayOf(e.len + 1);
3168             else
3169                 e.type = Type.twchar.immutableOf().arrayOf();
3170             e.committed = true;
3171             break;
3172 
3173         case 'c':
3174             e.committed = true;
3175             goto default;
3176 
3177         default:
3178             if (sc && sc.flags & SCOPE.Cfile)
3179                 e.type = Type.tchar.sarrayOf(e.len + 1);
3180             else
3181                 e.type = Type.tchar.immutableOf().arrayOf();
3182             break;
3183         }
3184         e.type = e.type.typeSemantic(e.loc, sc);
3185         //type = type.immutableOf();
3186         //printf("type = %s\n", type.toChars());
3187 
3188         result = e;
3189     }
3190 
3191     override void visit(TupleExp exp)
3192     {
3193         static if (LOGSEMANTIC)
3194         {
3195             printf("+TupleExp::semantic(%s)\n", exp.toChars());
3196         }
3197         if (exp.type)
3198         {
3199             result = exp;
3200             return;
3201         }
3202 
3203         if (exp.e0)
3204             exp.e0 = exp.e0.expressionSemantic(sc);
3205 
3206         // Run semantic() on each argument
3207         bool err = false;
3208         for (size_t i = 0; i < exp.exps.length; i++)
3209         {
3210             Expression e = (*exp.exps)[i];
3211             e = e.expressionSemantic(sc);
3212             if (!e.type)
3213             {
3214                 exp.error("`%s` has no value", e.toChars());
3215                 err = true;
3216             }
3217             else if (e.op == EXP.error)
3218                 err = true;
3219             else
3220                 (*exp.exps)[i] = e;
3221         }
3222         if (err)
3223             return setError();
3224 
3225         expandTuples(exp.exps);
3226 
3227         exp.type = new TypeTuple(exp.exps);
3228         exp.type = exp.type.typeSemantic(exp.loc, sc);
3229         //printf("-TupleExp::semantic(%s)\n", toChars());
3230         result = exp;
3231     }
3232 
3233     override void visit(ArrayLiteralExp e)
3234     {
3235         static if (LOGSEMANTIC)
3236         {
3237             printf("ArrayLiteralExp::semantic('%s')\n", e.toChars());
3238         }
3239         if (e.type)
3240         {
3241             result = e;
3242             return;
3243         }
3244 
3245         /* Perhaps an empty array literal [ ] should be rewritten as null?
3246          */
3247 
3248         if (e.basis)
3249             e.basis = e.basis.expressionSemantic(sc);
3250         if (arrayExpressionSemantic(e.elements.peekSlice(), sc) || (e.basis && e.basis.op == EXP.error))
3251             return setError();
3252 
3253         expandTuples(e.elements);
3254 
3255         if (e.basis)
3256             e.elements.push(e.basis);
3257         Type t0 = arrayExpressionToCommonType(sc, *e.elements);
3258         if (e.basis)
3259             e.basis = e.elements.pop();
3260         if (t0 is null)
3261             return setError();
3262 
3263         e.type = t0.arrayOf();
3264         e.type = e.type.typeSemantic(e.loc, sc);
3265 
3266         /* Disallow array literals of type void being used.
3267          */
3268         if (e.elements.length > 0 && t0.ty == Tvoid)
3269         {
3270             e.error("`%s` of type `%s` has no value", e.toChars(), e.type.toChars());
3271             return setError();
3272         }
3273 
3274         if (global.params.useTypeInfo && Type.dtypeinfo)
3275             semanticTypeInfo(sc, e.type);
3276 
3277         result = e;
3278     }
3279 
3280     override void visit(AssocArrayLiteralExp e)
3281     {
3282         static if (LOGSEMANTIC)
3283         {
3284             printf("AssocArrayLiteralExp::semantic('%s')\n", e.toChars());
3285         }
3286         if (e.type)
3287         {
3288             result = e;
3289             return;
3290         }
3291 
3292         // Run semantic() on each element
3293         bool err_keys = arrayExpressionSemantic(e.keys.peekSlice(), sc);
3294         bool err_vals = arrayExpressionSemantic(e.values.peekSlice(), sc);
3295         if (err_keys || err_vals)
3296             return setError();
3297 
3298         expandTuples(e.keys);
3299         expandTuples(e.values);
3300         if (e.keys.length != e.values.length)
3301         {
3302             e.error("number of keys is %llu, must match number of values %llu",
3303                         cast(ulong) e.keys.length, cast(ulong) e.values.length);
3304             return setError();
3305         }
3306 
3307         Type tkey = arrayExpressionToCommonType(sc, *e.keys);
3308         Type tvalue = arrayExpressionToCommonType(sc, *e.values);
3309         if (tkey is null || tvalue is null)
3310             return setError();
3311 
3312         e.type = new TypeAArray(tvalue, tkey);
3313         e.type = e.type.typeSemantic(e.loc, sc);
3314 
3315         semanticTypeInfo(sc, e.type);
3316 
3317         if (checkAssocArrayLiteralEscape(sc, e, false))
3318             return setError();
3319 
3320         result = e;
3321     }
3322 
3323     override void visit(StructLiteralExp e)
3324     {
3325         static if (LOGSEMANTIC)
3326         {
3327             printf("StructLiteralExp::semantic('%s')\n", e.toChars());
3328         }
3329         if (e.type)
3330         {
3331             result = e;
3332             return;
3333         }
3334 
3335         e.sd.size(e.loc);
3336         if (e.sd.sizeok != Sizeok.done)
3337             return setError();
3338 
3339         // run semantic() on each element
3340         if (arrayExpressionSemantic(e.elements.peekSlice(), sc))
3341             return setError();
3342 
3343         expandTuples(e.elements);
3344 
3345         /* Fit elements[] to the corresponding type of field[].
3346          */
3347         if (!e.sd.fit(e.loc, sc, e.elements, e.stype))
3348             return setError();
3349 
3350         /* Fill out remainder of elements[] with default initializers for fields[]
3351          */
3352         if (!e.sd.fill(e.loc, *e.elements, false))
3353         {
3354             /* An error in the initializer needs to be recorded as an error
3355              * in the enclosing function or template, since the initializer
3356              * will be part of the stuct declaration.
3357              */
3358             global.increaseErrorCount();
3359             return setError();
3360         }
3361 
3362         if (checkFrameAccess(e.loc, sc, e.sd, e.elements.length))
3363             return setError();
3364 
3365         e.type = e.stype ? e.stype : e.sd.type;
3366         result = e;
3367     }
3368 
3369     override void visit(CompoundLiteralExp cle)
3370     {
3371         static if (LOGSEMANTIC)
3372         {
3373             printf("CompoundLiteralExp::semantic('%s')\n", cle.toChars());
3374         }
3375         Type t = cle.type.typeSemantic(cle.loc, sc);
3376         auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
3377         auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
3378         if (!e)
3379         {
3380             error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
3381             return setError();
3382         }
3383         result = e;
3384         return;
3385     }
3386 
3387     override void visit(TypeExp exp)
3388     {
3389         if (exp.type.ty == Terror)
3390             return setError();
3391 
3392         //printf("TypeExp::semantic(%s)\n", exp.type.toChars());
3393         Expression e;
3394         Type t;
3395         Dsymbol s;
3396 
3397         dmd.typesem.resolve(exp.type, exp.loc, sc, e, t, s, true);
3398         if (e)
3399         {
3400             // `(Type)` is actually `(var)` so if `(var)` is a member requiring `this`
3401             // then rewrite as `(this.var)` in case it would be followed by a DotVar
3402             // to fix https://issues.dlang.org/show_bug.cgi?id=9490
3403             VarExp ve = e.isVarExp();
3404             if (ve && ve.var && exp.parens && !ve.var.isStatic() && !(sc.stc & STC.static_) &&
3405                 sc.func && sc.func.needThis && ve.var.isMember2())
3406             {
3407                 // printf("apply fix for issue 9490: add `this.` to `%s`...\n", e.toChars());
3408                 e = new DotVarExp(exp.loc, new ThisExp(exp.loc), ve.var, false);
3409             }
3410             //printf("e = %s %s\n", Token.toChars(e.op), e.toChars());
3411             e = e.expressionSemantic(sc);
3412         }
3413         else if (t)
3414         {
3415             //printf("t = %d %s\n", t.ty, t.toChars());
3416             exp.type = t.typeSemantic(exp.loc, sc);
3417             e = exp;
3418         }
3419         else if (s)
3420         {
3421             //printf("s = %s %s\n", s.kind(), s.toChars());
3422             e = symbolToExp(s, exp.loc, sc, true);
3423         }
3424         else
3425             assert(0);
3426 
3427         exp.type.checkComplexTransition(exp.loc, sc);
3428 
3429         result = e;
3430     }
3431 
3432     override void visit(ScopeExp exp)
3433     {
3434         static if (LOGSEMANTIC)
3435         {
3436             printf("+ScopeExp::semantic(%p '%s')\n", exp, exp.toChars());
3437         }
3438         if (exp.type)
3439         {
3440             result = exp;
3441             return;
3442         }
3443 
3444         ScopeDsymbol sds2 = exp.sds;
3445         TemplateInstance ti = sds2.isTemplateInstance();
3446         while (ti)
3447         {
3448             WithScopeSymbol withsym;
3449             if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
3450                 return setError();
3451             if (withsym && withsym.withstate.wthis)
3452             {
3453                 Expression e = new VarExp(exp.loc, withsym.withstate.wthis);
3454                 e = new DotTemplateInstanceExp(exp.loc, e, ti);
3455                 result = e.expressionSemantic(sc);
3456                 return;
3457             }
3458             if (ti.needsTypeInference(sc))
3459             {
3460                 if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
3461                 {
3462                     Dsymbol p = td.toParentLocal();
3463                     FuncDeclaration fdthis = hasThis(sc);
3464                     AggregateDeclaration ad = p ? p.isAggregateDeclaration() : null;
3465                     if (fdthis && ad && fdthis.isMemberLocal() == ad && (td._scope.stc & STC.static_) == 0)
3466                     {
3467                         Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3468                         result = e.expressionSemantic(sc);
3469                         return;
3470                     }
3471                 }
3472                 else if (OverloadSet os = ti.tempdecl.isOverloadSet())
3473                 {
3474                     FuncDeclaration fdthis = hasThis(sc);
3475                     AggregateDeclaration ad = os.parent.isAggregateDeclaration();
3476                     if (fdthis && ad && fdthis.isMemberLocal() == ad)
3477                     {
3478                         Expression e = new DotTemplateInstanceExp(exp.loc, new ThisExp(exp.loc), ti);
3479                         result = e.expressionSemantic(sc);
3480                         return;
3481                     }
3482                 }
3483                 // ti is an instance which requires IFTI.
3484                 exp.sds = ti;
3485                 exp.type = Type.tvoid;
3486                 result = exp;
3487                 return;
3488             }
3489             ti.dsymbolSemantic(sc);
3490             if (!ti.inst || ti.errors)
3491                 return setError();
3492 
3493             Dsymbol s = ti.toAlias();
3494             if (s == ti)
3495             {
3496                 exp.sds = ti;
3497                 exp.type = Type.tvoid;
3498                 result = exp;
3499                 return;
3500             }
3501             sds2 = s.isScopeDsymbol();
3502             if (sds2)
3503             {
3504                 ti = sds2.isTemplateInstance();
3505                 //printf("+ sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3506                 continue;
3507             }
3508 
3509             if (auto v = s.isVarDeclaration())
3510             {
3511                 if (!v.type)
3512                 {
3513                     exp.error("forward reference of %s `%s`", v.kind(), v.toChars());
3514                     return setError();
3515                 }
3516                 if ((v.storage_class & STC.manifest) && v._init)
3517                 {
3518                     /* When an instance that will be converted to a constant exists,
3519                      * the instance representation "foo!tiargs" is treated like a
3520                      * variable name, and its recursive appearance check (note that
3521                      * it's equivalent with a recursive instantiation of foo) is done
3522                      * separately from the circular initialization check for the
3523                      * eponymous enum variable declaration.
3524                      *
3525                      *  template foo(T) {
3526                      *    enum bool foo = foo;    // recursive definition check (v.inuse)
3527                      *  }
3528                      *  template bar(T) {
3529                      *    enum bool bar = bar!T;  // recursive instantiation check (ti.inuse)
3530                      *  }
3531                      */
3532                     if (ti.inuse)
3533                     {
3534                         exp.error("recursive expansion of %s `%s`", ti.kind(), ti.toPrettyChars());
3535                         return setError();
3536                     }
3537                     v.checkDeprecated(exp.loc, sc);
3538                     auto e = v.expandInitializer(exp.loc);
3539                     ti.inuse++;
3540                     e = e.expressionSemantic(sc);
3541                     ti.inuse--;
3542                     result = e;
3543                     return;
3544                 }
3545             }
3546 
3547             //printf("s = %s, '%s'\n", s.kind(), s.toChars());
3548             auto e = symbolToExp(s, exp.loc, sc, true);
3549             //printf("-1ScopeExp::semantic()\n");
3550             result = e;
3551             return;
3552         }
3553 
3554         //printf("sds2 = %s, '%s'\n", sds2.kind(), sds2.toChars());
3555         //printf("\tparent = '%s'\n", sds2.parent.toChars());
3556         sds2.dsymbolSemantic(sc);
3557 
3558         // (Aggregate|Enum)Declaration
3559         if (auto t = sds2.getType())
3560         {
3561             result = (new TypeExp(exp.loc, t)).expressionSemantic(sc);
3562             return;
3563         }
3564 
3565         if (auto td = sds2.isTemplateDeclaration())
3566         {
3567             result = (new TemplateExp(exp.loc, td)).expressionSemantic(sc);
3568             return;
3569         }
3570 
3571         exp.sds = sds2;
3572         exp.type = Type.tvoid;
3573         //printf("-2ScopeExp::semantic() %s\n", toChars());
3574         result = exp;
3575     }
3576 
3577     override void visit(NewExp exp)
3578     {
3579         static if (LOGSEMANTIC)
3580         {
3581             printf("NewExp::semantic() %s\n", exp.toChars());
3582             if (exp.thisexp)
3583                 printf("\tthisexp = %s\n", exp.thisexp.toChars());
3584             printf("\tnewtype: %s\n", exp.newtype.toChars());
3585         }
3586         if (exp.type) // if semantic() already run
3587         {
3588             result = exp;
3589             return;
3590         }
3591 
3592         //for error messages if the argument in [] is not convertible to size_t
3593         const originalNewtype = exp.newtype;
3594 
3595         // https://issues.dlang.org/show_bug.cgi?id=11581
3596         // With the syntax `new T[edim]` or `thisexp.new T[edim]`,
3597         // T should be analyzed first and edim should go into arguments iff it's
3598         // not a tuple.
3599         Expression edim = null;
3600         if (!exp.arguments && exp.newtype.isTypeSArray())
3601         {
3602             auto ts = exp.newtype.isTypeSArray();
3603             // check `new Value[Key]`
3604             ts.dim = ts.dim.expressionSemantic(sc);
3605             if (ts.dim.op == EXP.type)
3606             {
3607                 exp.newtype = new TypeAArray(ts.next, ts.dim.isTypeExp().type);
3608             }
3609             else
3610             {
3611                 edim = ts.dim;
3612                 exp.newtype = ts.next;
3613             }
3614         }
3615 
3616         ClassDeclaration cdthis = null;
3617         if (exp.thisexp)
3618         {
3619             exp.thisexp = exp.thisexp.expressionSemantic(sc);
3620             if (exp.thisexp.op == EXP.error)
3621                 return setError();
3622 
3623             cdthis = exp.thisexp.type.isClassHandle();
3624             if (!cdthis)
3625             {
3626                 exp.error("`this` for nested class must be a class type, not `%s`", exp.thisexp.type.toChars());
3627                 return setError();
3628             }
3629 
3630             sc = sc.push(cdthis);
3631             exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3632             sc = sc.pop();
3633         }
3634         else
3635         {
3636             exp.type = exp.newtype.typeSemantic(exp.loc, sc);
3637         }
3638         if (exp.type.ty == Terror)
3639             return setError();
3640 
3641         if (edim)
3642         {
3643             if (exp.type.toBasetype().ty == Ttuple)
3644             {
3645                 // --> new T[edim]
3646                 exp.type = new TypeSArray(exp.type, edim);
3647                 exp.type = exp.type.typeSemantic(exp.loc, sc);
3648                 if (exp.type.ty == Terror)
3649                     return setError();
3650             }
3651             else
3652             {
3653                 // --> new T[](edim)
3654                 exp.arguments = new Expressions();
3655                 exp.arguments.push(edim);
3656                 exp.type = exp.type.arrayOf();
3657             }
3658         }
3659 
3660         exp.newtype = exp.type; // in case type gets cast to something else
3661         Type tb = exp.type.toBasetype();
3662         //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
3663         if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc))
3664         {
3665             return setError();
3666         }
3667         if (preFunctionParameters(sc, exp.argumentList))
3668         {
3669             return setError();
3670         }
3671 
3672         if (exp.thisexp && tb.ty != Tclass)
3673         {
3674             exp.error("`.new` is only for allocating nested classes, not `%s`", tb.toChars());
3675             return setError();
3676         }
3677 
3678         const size_t nargs = exp.arguments ? exp.arguments.length : 0;
3679         Expression newprefix = null;
3680 
3681         if (auto tc = tb.isTypeClass())
3682         {
3683             auto cd = tc.sym;
3684             if (cd.errors)
3685                 return setError();
3686             cd.size(exp.loc);
3687             if (cd.sizeok != Sizeok.done)
3688                 return setError();
3689             if (!cd.ctor)
3690                 cd.ctor = cd.searchCtor();
3691             if (cd.noDefaultCtor && !nargs && !cd.defaultCtor)
3692             {
3693                 exp.error("default construction is disabled for type `%s`", cd.type.toChars());
3694                 return setError();
3695             }
3696 
3697             if (cd.isInterfaceDeclaration())
3698             {
3699                 exp.error("cannot create instance of interface `%s`", cd.toChars());
3700                 return setError();
3701             }
3702 
3703             if (cd.isAbstract())
3704             {
3705                 exp.error("cannot create instance of abstract class `%s`", cd.toChars());
3706                 for (size_t i = 0; i < cd.vtbl.length; i++)
3707                 {
3708                     FuncDeclaration fd = cd.vtbl[i].isFuncDeclaration();
3709                     if (fd && fd.isAbstract())
3710                     {
3711                         errorSupplemental(exp.loc, "function `%s` is not implemented",
3712                             fd.toFullSignature());
3713                     }
3714                 }
3715                 return setError();
3716             }
3717             // checkDeprecated() is already done in newtype.typeSemantic().
3718 
3719             if (cd.isNested())
3720             {
3721                 /* We need a 'this' pointer for the nested class.
3722                  * Ensure we have the right one.
3723                  */
3724                 Dsymbol s = cd.toParentLocal();
3725 
3726                 //printf("cd isNested, parent = %s '%s'\n", s.kind(), s.toPrettyChars());
3727                 if (auto cdn = s.isClassDeclaration())
3728                 {
3729                     if (!cdthis)
3730                     {
3731                         void noReferenceToOuterClass()
3732                         {
3733                             if (cd.isAnonymous)
3734                                 exp.error("cannot construct anonymous nested class because no implicit `this` reference to outer class is available");
3735                             else
3736                                 exp.error("cannot construct nested class `%s` because no implicit `this` reference to outer class `%s` is available",
3737                                     cd.toChars(), cdn.toChars());
3738                             return setError();
3739                         }
3740 
3741                         if (!sc.hasThis)
3742                             return noReferenceToOuterClass();
3743 
3744                         // Supply an implicit 'this' and try again
3745                         exp.thisexp = new ThisExp(exp.loc);
3746                         for (Dsymbol sp = sc.parent; 1; sp = sp.toParentLocal())
3747                         {
3748                             if (!sp)
3749                                 return noReferenceToOuterClass();
3750                             ClassDeclaration cdp = sp.isClassDeclaration();
3751                             if (!cdp)
3752                                 continue;
3753                             if (cdp == cdn || cdn.isBaseOf(cdp, null))
3754                                 break;
3755                             // Add a '.outer' and try again
3756                             exp.thisexp = new DotIdExp(exp.loc, exp.thisexp, Id.outer);
3757                         }
3758 
3759                         exp.thisexp = exp.thisexp.expressionSemantic(sc);
3760                         if (exp.thisexp.op == EXP.error)
3761                             return setError();
3762                         cdthis = exp.thisexp.type.isClassHandle();
3763                     }
3764                     if (cdthis != cdn && !cdn.isBaseOf(cdthis, null))
3765                     {
3766                         //printf("cdthis = %s\n", cdthis.toChars());
3767                         exp.error("`this` for nested class must be of type `%s`, not `%s`",
3768                             cdn.toChars(), exp.thisexp.type.toChars());
3769                         return setError();
3770                     }
3771                     if (!MODimplicitConv(exp.thisexp.type.mod, exp.newtype.mod))
3772                     {
3773                         exp.error("nested type `%s` should have the same or weaker constancy as enclosing type `%s`",
3774                             exp.newtype.toChars(), exp.thisexp.type.toChars());
3775                         return setError();
3776                     }
3777                 }
3778                 else if (exp.thisexp)
3779                 {
3780                     exp.error("`.new` is only for allocating nested classes");
3781                     return setError();
3782                 }
3783                 else if (auto fdn = s.isFuncDeclaration())
3784                 {
3785                     // make sure the parent context fdn of cd is reachable from sc
3786                     if (!ensureStaticLinkTo(sc.parent, fdn))
3787                     {
3788                         exp.error("outer function context of `%s` is needed to `new` nested class `%s`",
3789                             fdn.toPrettyChars(), cd.toPrettyChars());
3790                         return setError();
3791                     }
3792                 }
3793                 else
3794                     assert(0);
3795             }
3796             else if (exp.thisexp)
3797             {
3798                 exp.error("`.new` is only for allocating nested classes");
3799                 return setError();
3800             }
3801 
3802             if (cd.vthis2)
3803             {
3804                 if (AggregateDeclaration ad2 = cd.isMember2())
3805                 {
3806                     Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
3807                     if (te.op != EXP.error)
3808                         te = getRightThis(exp.loc, sc, ad2, te, cd);
3809                     if (te.op == EXP.error)
3810                     {
3811                         exp.error("need `this` of type `%s` needed to `new` nested class `%s`", ad2.toChars(), cd.toChars());
3812                         return setError();
3813                     }
3814                 }
3815             }
3816 
3817             if (cd.disableNew && !exp.onstack)
3818             {
3819                 exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
3820                           originalNewtype.toChars());
3821                 return setError();
3822             }
3823 
3824             if (cd.ctor)
3825             {
3826                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
3827                 if (!f || f.errors)
3828                     return setError();
3829 
3830                 checkFunctionAttributes(exp, sc, f);
3831                 checkAccess(cd, exp.loc, sc, f);
3832 
3833                 TypeFunction tf = f.type.isTypeFunction();
3834                 if (!exp.arguments)
3835                     exp.arguments = new Expressions();
3836                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
3837                     return setError();
3838 
3839                 exp.member = f.isCtorDeclaration();
3840                 assert(exp.member);
3841             }
3842             else
3843             {
3844                 if (nargs)
3845                 {
3846                     exp.error("no constructor for `%s`", cd.toChars());
3847                     return setError();
3848                 }
3849 
3850                 // https://issues.dlang.org/show_bug.cgi?id=19941
3851                 // Run semantic on all field initializers to resolve any forward
3852                 // references. This is the same as done for structs in sd.fill().
3853                 for (ClassDeclaration c = cd; c; c = c.baseClass)
3854                 {
3855                     foreach (v; c.fields)
3856                     {
3857                         if (v.inuse || v._scope is null || v._init is null ||
3858                             v._init.isVoidInitializer())
3859                             continue;
3860                         v.inuse++;
3861                         v._init = v._init.initializerSemantic(v._scope, v.type, INITinterpret);
3862                         v.inuse--;
3863                     }
3864                 }
3865             }
3866 
3867             // When using `@nogc` exception handling, lower `throw new E(args)` to
3868             // `throw (__tmp = _d_newThrowable!E(), __tmp.__ctor(args), __tmp)`.
3869             if (global.params.ehnogc && exp.thrownew &&
3870                 !cd.isCOMclass() && !cd.isCPPclass())
3871             {
3872                 assert(cd.ctor);
3873 
3874                 Expression id = new IdentifierExp(exp.loc, Id.empty);
3875                 id = new DotIdExp(exp.loc, id, Id.object);
3876 
3877                 auto tiargs = new Objects();
3878                 tiargs.push(exp.newtype);
3879                 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
3880                 id = new CallExp(exp.loc, id).expressionSemantic(sc);
3881 
3882                 Expression idVal;
3883                 Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
3884                 // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
3885 
3886                 auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
3887                 auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
3888 
3889                 id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
3890                 id = Expression.combine(id, ctorCall).expressionSemantic(sc);
3891                 // id = Expression.combine(id, castTmp).expressionSemantic(sc);
3892 
3893                 result = id.expressionSemantic(sc);
3894                 return;
3895             }
3896             else if (sc.needsCodegen() && // interpreter doesn't need this lowered
3897                      !exp.onstack && !exp.type.isscope()) // these won't use the GC
3898             {
3899                 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
3900                  * or `_d_newclassTTrace`
3901                  */
3902                 auto hook = global.params.tracegc ? Id._d_newclassTTrace : Id._d_newclassT;
3903                 if (!verifyHookExist(exp.loc, *sc, hook, "new class"))
3904                     return setError();
3905 
3906                 Expression id = new IdentifierExp(exp.loc, Id.empty);
3907                 id = new DotIdExp(exp.loc, id, Id.object);
3908 
3909                 auto tiargs = new Objects();
3910                 auto t = exp.newtype.unqualify(MODFlags.wild);  // remove `inout`
3911                 tiargs.push(t);
3912                 id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
3913                 auto arguments = new Expressions();
3914                 if (global.params.tracegc)
3915                 {
3916                     auto funcname = (sc.callsc && sc.callsc.func) ?
3917                         sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
3918                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
3919                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
3920                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
3921                 }
3922                 id = new CallExp(exp.loc, id, arguments);
3923 
3924                 exp.lowering = id.expressionSemantic(sc);
3925             }
3926         }
3927         else if (auto ts = tb.isTypeStruct())
3928         {
3929             auto sd = ts.sym;
3930             sd.size(exp.loc);
3931             if (sd.sizeok != Sizeok.done)
3932                 return setError();
3933             if (!sd.ctor)
3934                 sd.ctor = sd.searchCtor();
3935             if (sd.noDefaultCtor && !nargs)
3936             {
3937                 exp.error("default construction is disabled for type `%s`", sd.type.toChars());
3938                 return setError();
3939             }
3940             // checkDeprecated() is already done in newtype.typeSemantic().
3941 
3942             if (sd.disableNew)
3943             {
3944                 exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
3945                           originalNewtype.toChars());
3946                 return setError();
3947             }
3948 
3949             // https://issues.dlang.org/show_bug.cgi?id=22639
3950             // If the new expression has arguments, we either should call a
3951             // regular constructor of a copy constructor if the first argument
3952             // is the same type as the struct
3953             if (nargs && (sd.hasRegularCtor() || (sd.ctor && (*exp.arguments)[0].type.mutableOf() == sd.type.mutableOf())))
3954             {
3955                 FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.ctor, null, tb, exp.argumentList, FuncResolveFlag.standard);
3956                 if (!f || f.errors)
3957                     return setError();
3958 
3959                 checkFunctionAttributes(exp, sc, f);
3960                 checkAccess(sd, exp.loc, sc, f);
3961 
3962                 TypeFunction tf = f.type.isTypeFunction();
3963                 if (!exp.arguments)
3964                     exp.arguments = new Expressions();
3965                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.argumentList, f, &exp.type, &exp.argprefix))
3966                     return setError();
3967 
3968                 exp.member = f.isCtorDeclaration();
3969                 assert(exp.member);
3970 
3971                 if (checkFrameAccess(exp.loc, sc, sd, sd.fields.length))
3972                     return setError();
3973             }
3974             else
3975             {
3976                 if (exp.names)
3977                 {
3978                     exp.arguments = resolveStructLiteralNamedArgs(sd, exp.type, sc, exp.loc,
3979                         exp.names ? (*exp.names)[] : null,
3980                         (size_t i, Type t) => (*exp.arguments)[i],
3981                         i => (*exp.arguments)[i].loc
3982                     );
3983                     if (!exp.arguments)
3984                         return setError();
3985                 }
3986                 else if (!exp.arguments)
3987                 {
3988                     exp.arguments = new Expressions();
3989                 }
3990 
3991                 if (!sd.fit(exp.loc, sc, exp.arguments, tb))
3992                     return setError();
3993 
3994                 if (!sd.fill(exp.loc, *exp.arguments, false))
3995                     return setError();
3996 
3997                 if (checkFrameAccess(exp.loc, sc, sd, exp.arguments ? exp.arguments.length : 0))
3998                     return setError();
3999 
4000                 /* Since a `new` allocation may escape, check each of the arguments for escaping
4001                  */
4002                 foreach (arg; *exp.arguments)
4003                 {
4004                     if (arg && checkNewEscape(sc, arg, false))
4005                         return setError();
4006                 }
4007             }
4008 
4009             exp.type = exp.type.pointerTo();
4010         }
4011         else if (tb.ty == Tarray)
4012         {
4013             if (!nargs)
4014             {
4015                 // https://issues.dlang.org/show_bug.cgi?id=20422
4016                 // Without this check the compiler would give a misleading error
4017                 exp.error("missing length argument for array");
4018                 return setError();
4019             }
4020 
4021             Type tn = tb.nextOf().baseElemOf();
4022             Dsymbol s = tn.toDsymbol(sc);
4023             AggregateDeclaration ad = s ? s.isAggregateDeclaration() : null;
4024             if (ad && ad.noDefaultCtor)
4025             {
4026                 exp.error("default construction is disabled for type `%s`", tb.nextOf().toChars());
4027                 return setError();
4028             }
4029             for (size_t i = 0; i < nargs; i++)
4030             {
4031                 if (tb.ty != Tarray)
4032                 {
4033                     exp.error("too many arguments for array");
4034                     return setError();
4035                 }
4036 
4037                 Expression arg = (*exp.arguments)[i];
4038                 if (exp.names && (*exp.names)[i])
4039                 {
4040                     exp.error("no named argument `%s` allowed for array dimension", (*exp.names)[i].toChars());
4041                     return setError();
4042                 }
4043 
4044                 arg = resolveProperties(sc, arg);
4045                 arg = arg.implicitCastTo(sc, Type.tsize_t);
4046                 if (arg.op == EXP.error)
4047                     return setError();
4048                 arg = arg.optimize(WANTvalue);
4049                 if (arg.op == EXP.int64 && cast(sinteger_t)arg.toInteger() < 0)
4050                 {
4051                     exp.error("negative array index `%s`", arg.toChars());
4052                     return setError();
4053                 }
4054                 (*exp.arguments)[i] = arg;
4055                 tb = tb.isTypeDArray().next.toBasetype();
4056             }
4057         }
4058         else if (tb.isscalar())
4059         {
4060             if (!nargs)
4061             {
4062             }
4063             else if (nargs == 1)
4064             {
4065                 if (exp.names && (*exp.names)[0])
4066                 {
4067                     exp.error("no named argument `%s` allowed for scalar", (*exp.names)[0].toChars());
4068                     return setError();
4069                 }
4070                 Expression e = (*exp.arguments)[0];
4071                 e = e.implicitCastTo(sc, tb);
4072                 (*exp.arguments)[0] = e;
4073             }
4074             else
4075             {
4076                 exp.error("more than one argument for construction of `%s`", exp.type.toChars());
4077                 return setError();
4078             }
4079 
4080             exp.type = exp.type.pointerTo();
4081         }
4082         else if (tb.ty == Taarray)
4083         {
4084             // e.g. `new Alias(args)`
4085             if (nargs)
4086             {
4087                 exp.error("`new` cannot take arguments for an associative array");
4088                 return setError();
4089             }
4090         }
4091         else
4092         {
4093             exp.error("cannot create a `%s` with `new`", exp.type.toChars());
4094             return setError();
4095         }
4096 
4097         //printf("NewExp: '%s'\n", toChars());
4098         //printf("NewExp:type '%s'\n", type.toChars());
4099         semanticTypeInfo(sc, exp.type);
4100 
4101         if (newprefix)
4102         {
4103             result = Expression.combine(newprefix, exp);
4104             return;
4105         }
4106         result = exp;
4107     }
4108 
4109     override void visit(NewAnonClassExp e)
4110     {
4111         static if (LOGSEMANTIC)
4112         {
4113             printf("NewAnonClassExp::semantic() %s\n", e.toChars());
4114             //printf("thisexp = %p\n", thisexp);
4115             //printf("type: %s\n", type.toChars());
4116         }
4117 
4118         Expression d = new DeclarationExp(e.loc, e.cd);
4119         sc = sc.push(); // just create new scope
4120         sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4121         d = d.expressionSemantic(sc);
4122         sc = sc.pop();
4123 
4124         if (!e.cd.errors && sc.intypeof && !sc.parent.inNonRoot())
4125         {
4126             ScopeDsymbol sds = sc.tinst ? cast(ScopeDsymbol)sc.tinst : sc._module;
4127             if (!sds.members)
4128                 sds.members = new Dsymbols();
4129             sds.members.push(e.cd);
4130         }
4131 
4132         Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
4133 
4134         Expression c = new CommaExp(e.loc, d, n);
4135         result = c.expressionSemantic(sc);
4136     }
4137 
4138     override void visit(SymOffExp e)
4139     {
4140         static if (LOGSEMANTIC)
4141         {
4142             printf("SymOffExp::semantic('%s')\n", e.toChars());
4143         }
4144         //var.dsymbolSemantic(sc);
4145         if (!e.type)
4146             e.type = e.var.type.pointerTo();
4147 
4148         if (auto v = e.var.isVarDeclaration())
4149         {
4150             if (v.checkNestedReference(sc, e.loc))
4151                 return setError();
4152         }
4153         else if (auto f = e.var.isFuncDeclaration())
4154         {
4155             if (f.checkNestedReference(sc, e.loc))
4156                 return setError();
4157         }
4158 
4159         result = e;
4160     }
4161 
4162     override void visit(VarExp e)
4163     {
4164         static if (LOGSEMANTIC)
4165         {
4166             printf("VarExp::semantic(%s)\n", e.toChars());
4167         }
4168 
4169         auto vd = e.var.isVarDeclaration();
4170         auto fd = e.var.isFuncDeclaration();
4171 
4172         if (fd)
4173         {
4174             //printf("L%d fd = %s\n", __LINE__, f.toChars());
4175             if (!fd.functionSemantic())
4176                 return setError();
4177         }
4178 
4179         if (!e.type)
4180             e.type = e.var.type;
4181         if (e.type && !e.type.deco)
4182         {
4183             auto decl = e.var.isDeclaration();
4184             if (decl)
4185                 decl.inuse++;
4186             e.type = e.type.typeSemantic(e.loc, sc);
4187             if (decl)
4188                 decl.inuse--;
4189         }
4190 
4191         /* Fix for 1161 doesn't work because it causes visibility
4192          * problems when instantiating imported templates passing private
4193          * variables as alias template parameters.
4194          */
4195         //checkAccess(loc, sc, NULL, var);
4196 
4197         if (vd)
4198         {
4199             if (vd.checkNestedReference(sc, e.loc))
4200                 return setError();
4201 
4202             // https://issues.dlang.org/show_bug.cgi?id=12025
4203             // If the variable is not actually used in runtime code,
4204             // the purity violation error is redundant.
4205             //checkPurity(sc, vd);
4206         }
4207         else if (fd)
4208         {
4209             // TODO: If fd isn't yet resolved its overload, the checkNestedReference
4210             // call would cause incorrect validation.
4211             // Maybe here should be moved in CallExp, or AddrExp for functions.
4212             if (fd.checkNestedReference(sc, e.loc))
4213                 return setError();
4214         }
4215         else if (auto od = e.var.isOverDeclaration())
4216         {
4217             e.type = Type.tvoid; // ambiguous type?
4218         }
4219 
4220         result = e;
4221     }
4222 
4223     override void visit(FuncExp exp)
4224     {
4225         static if (LOGSEMANTIC)
4226         {
4227             printf("FuncExp::semantic(%s)\n", exp.toChars());
4228             if (exp.fd.treq)
4229                 printf("  treq = %s\n", exp.fd.treq.toChars());
4230         }
4231 
4232         if (exp.type)
4233         {
4234             result = exp;
4235             return;
4236         }
4237 
4238         Expression e = exp;
4239         uint olderrors;
4240 
4241         sc = sc.push(); // just create new scope
4242         sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
4243         sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
4244 
4245         /* fd.treq might be incomplete type,
4246             * so should not semantic it.
4247             * void foo(T)(T delegate(int) dg){}
4248             * foo(a=>a); // in IFTI, treq == T delegate(int)
4249             */
4250         //if (fd.treq)
4251         //    fd.treq = fd.treq.dsymbolSemantic(loc, sc);
4252 
4253         exp.genIdent(sc);
4254 
4255         // Set target of return type inference
4256         if (exp.fd.treq && !exp.fd.type.nextOf())
4257         {
4258             TypeFunction tfv = null;
4259             if (exp.fd.treq.ty == Tdelegate || exp.fd.treq.isPtrToFunction())
4260                 tfv = cast(TypeFunction)exp.fd.treq.nextOf();
4261             if (tfv)
4262             {
4263                 TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4264                 tfl.next = tfv.nextOf();
4265             }
4266         }
4267 
4268         //printf("td = %p, treq = %p\n", td, fd.treq);
4269         if (exp.td)
4270         {
4271             assert(exp.td.parameters && exp.td.parameters.length);
4272             exp.td.dsymbolSemantic(sc);
4273             exp.type = Type.tvoid; // temporary type
4274 
4275             if (exp.fd.treq) // defer type determination
4276             {
4277                 FuncExp fe;
4278                 if (exp.matchType(exp.fd.treq, sc, &fe) > MATCH.nomatch)
4279                     e = fe;
4280                 else
4281                     e = ErrorExp.get();
4282             }
4283             goto Ldone;
4284         }
4285 
4286         olderrors = global.errors;
4287         exp.fd.dsymbolSemantic(sc);
4288         if (olderrors == global.errors)
4289         {
4290             exp.fd.semantic2(sc);
4291             if (olderrors == global.errors)
4292                 exp.fd.semantic3(sc);
4293         }
4294         if (olderrors != global.errors)
4295         {
4296             if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
4297                 (cast(TypeFunction)exp.fd.type).next = Type.terror;
4298             e = ErrorExp.get();
4299             goto Ldone;
4300         }
4301 
4302         // Type is a "delegate to" or "pointer to" the function literal
4303         if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
4304         {
4305             // https://issues.dlang.org/show_bug.cgi?id=22686
4306             // if the delegate return type is an error
4307             // abort semantic of the FuncExp and propagate
4308             // the error
4309             if (exp.fd.type.isTypeError())
4310             {
4311                 e = ErrorExp.get();
4312                 goto Ldone;
4313             }
4314             exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
4315             exp.type = exp.type.typeSemantic(exp.loc, sc);
4316 
4317             exp.fd.tok = TOK.delegate_;
4318         }
4319         else
4320         {
4321             exp.type = new TypePointer(exp.fd.type);
4322             exp.type = exp.type.typeSemantic(exp.loc, sc);
4323             //type = fd.type.pointerTo();
4324 
4325             /* A lambda expression deduced to function pointer might become
4326                 * to a delegate literal implicitly.
4327                 *
4328                 *   auto foo(void function() fp) { return 1; }
4329                 *   assert(foo({}) == 1);
4330                 *
4331                 * So, should keep fd.tok == TOK.reserve if fd.treq == NULL.
4332                 */
4333             if (exp.fd.treq && exp.fd.treq.ty == Tpointer)
4334             {
4335                 // change to non-nested
4336                 exp.fd.tok = TOK.function_;
4337                 exp.fd.vthis = null;
4338             }
4339         }
4340         exp.fd.tookAddressOf++;
4341 
4342     Ldone:
4343         sc = sc.pop();
4344         result = e;
4345     }
4346 
4347     /**
4348      * Perform semantic analysis on function literals
4349      *
4350      * Test the following construct:
4351      * ---
4352      * (x, y, z) { return x + y + z; }(42, 84, 1992);
4353      * ---
4354      */
4355     Expression callExpSemantic(FuncExp exp, Scope* sc, Expressions* arguments)
4356     {
4357         if ((!exp.type || exp.type == Type.tvoid) && exp.td && arguments && arguments.length)
4358         {
4359             for (size_t k = 0; k < arguments.length; k++)
4360             {
4361                 Expression checkarg = (*arguments)[k];
4362                 if (checkarg.op == EXP.error)
4363                     return checkarg;
4364             }
4365 
4366             exp.genIdent(sc);
4367 
4368             assert(exp.td.parameters && exp.td.parameters.length);
4369             exp.td.dsymbolSemantic(sc);
4370 
4371             TypeFunction tfl = cast(TypeFunction)exp.fd.type;
4372             size_t dim = tfl.parameterList.length;
4373             if (arguments.length < dim)
4374             {
4375                 // Default arguments are always typed, so they don't need inference.
4376                 Parameter p = tfl.parameterList[arguments.length];
4377                 if (p.defaultArg)
4378                     dim = arguments.length;
4379             }
4380 
4381             if ((tfl.parameterList.varargs == VarArg.none && arguments.length > dim) ||
4382                 arguments.length < dim)
4383             {
4384                 OutBuffer buf;
4385                 foreach (idx, ref arg; *arguments)
4386                     buf.printf("%s%s", (idx ? ", ".ptr : "".ptr), arg.type.toChars());
4387                 exp.error("function literal `%s%s` is not callable using argument types `(%s)`",
4388                           exp.fd.toChars(), parametersTypeToChars(tfl.parameterList),
4389                           buf.peekChars());
4390                 exp.errorSupplemental("too %s arguments, expected %d, got %d",
4391                                       arguments.length < dim ? "few".ptr : "many".ptr,
4392                                       cast(int)dim, cast(int)arguments.length);
4393                 return ErrorExp.get();
4394             }
4395 
4396             auto tiargs = new Objects();
4397             tiargs.reserve(exp.td.parameters.length);
4398 
4399             for (size_t i = 0; i < exp.td.parameters.length; i++)
4400             {
4401                 TemplateParameter tp = (*exp.td.parameters)[i];
4402                 assert(dim <= tfl.parameterList.length);
4403                 foreach (u, p; tfl.parameterList)
4404                 {
4405                     if (u == dim)
4406                         break;
4407 
4408                     if (p.type.ty == Tident && (cast(TypeIdentifier)p.type).ident == tp.ident)
4409                     {
4410                         Expression e = (*arguments)[u];
4411                         tiargs.push(e.type);
4412                         break;
4413                     }
4414                 }
4415             }
4416 
4417             auto ti = new TemplateInstance(exp.loc, exp.td, tiargs);
4418             return (new ScopeExp(exp.loc, ti)).expressionSemantic(sc);
4419         }
4420         return exp.expressionSemantic(sc);
4421     }
4422 
4423     override void visit(CallExp exp)
4424     {
4425         static if (LOGSEMANTIC)
4426         {
4427             printf("CallExp::semantic() %s\n", exp.toChars());
4428         }
4429         if (exp.type)
4430         {
4431             result = exp;
4432             return; // semantic() already run
4433         }
4434 
4435         Objects* tiargs = null; // initial list of template arguments
4436         Expression ethis = null;
4437         Type tthis = null;
4438         Expression e1org = exp.e1;
4439 
4440         if (auto ce = exp.e1.isCommaExp())
4441         {
4442             /* Rewrite (a,b)(args) as (a,(b(args)))
4443              */
4444             exp.e1 = ce.e2;
4445             ce.e2 = exp;
4446             result = ce.expressionSemantic(sc);
4447             return;
4448         }
4449         if (DelegateExp de = exp.e1.isDelegateExp())
4450         {
4451             exp.e1 = new DotVarExp(de.loc, de.e1, de.func, de.hasOverloads);
4452             visit(exp);
4453             return;
4454         }
4455         if (FuncExp fe = exp.e1.isFuncExp())
4456         {
4457             if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4458                 preFunctionParameters(sc, exp.argumentList))
4459                 return setError();
4460 
4461             // Run e1 semantic even if arguments have any errors
4462             exp.e1 = callExpSemantic(fe, sc, exp.arguments);
4463             if (exp.e1.op == EXP.error)
4464             {
4465                 result = exp.e1;
4466                 return;
4467             }
4468         }
4469         if (sc.flags & SCOPE.Cfile)
4470         {
4471             /* See if need to rewrite the AST because of cast/call ambiguity
4472              */
4473             if (auto e = castCallAmbiguity(exp, sc))
4474             {
4475                 result = expressionSemantic(e, sc);
4476                 return;
4477             }
4478         }
4479 
4480         if (Expression ex = resolveUFCS(sc, exp))
4481         {
4482             result = ex;
4483             return;
4484         }
4485 
4486         /* This recognizes:
4487          *  foo!(tiargs)(funcargs)
4488          */
4489         if (ScopeExp se = exp.e1.isScopeExp())
4490         {
4491             TemplateInstance ti = se.sds.isTemplateInstance();
4492             if (ti)
4493             {
4494                 /* Attempt to instantiate ti. If that works, go with it.
4495                  * If not, go with partial explicit specialization.
4496                  */
4497                 WithScopeSymbol withsym;
4498                 if (!ti.findTempDecl(sc, &withsym) || !ti.semanticTiargs(sc))
4499                     return setError();
4500                 if (withsym && withsym.withstate.wthis)
4501                 {
4502                     exp.e1 = new VarExp(exp.e1.loc, withsym.withstate.wthis);
4503                     exp.e1 = new DotTemplateInstanceExp(exp.e1.loc, exp.e1, ti);
4504                     goto Ldotti;
4505                 }
4506                 if (ti.needsTypeInference(sc, 1))
4507                 {
4508                     /* Go with partial explicit specialization
4509                      */
4510                     tiargs = ti.tiargs;
4511                     assert(ti.tempdecl);
4512                     if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4513                         exp.e1 = new TemplateExp(exp.loc, td);
4514                     else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4515                         exp.e1 = new VarExp(exp.loc, od);
4516                     else
4517                         exp.e1 = new OverExp(exp.loc, ti.tempdecl.isOverloadSet());
4518                 }
4519                 else
4520                 {
4521                     Expression e1x = exp.e1.expressionSemantic(sc);
4522                     if (e1x.op == EXP.error)
4523                     {
4524                         result = e1x;
4525                         return;
4526                     }
4527                     exp.e1 = e1x;
4528                 }
4529             }
4530         }
4531 
4532         /* This recognizes:
4533          *  expr.foo!(tiargs)(funcargs)
4534          */
4535     Ldotti:
4536         if (DotTemplateInstanceExp se = exp.e1.isDotTemplateInstanceExp())
4537         {
4538             TemplateInstance ti = se.ti;
4539             {
4540                 /* Attempt to instantiate ti. If that works, go with it.
4541                  * If not, go with partial explicit specialization.
4542                  */
4543                 if (!se.findTempDecl(sc) || !ti.semanticTiargs(sc))
4544                     return setError();
4545                 if (ti.needsTypeInference(sc, 1))
4546                 {
4547                     /* Go with partial explicit specialization
4548                      */
4549                     tiargs = ti.tiargs;
4550                     assert(ti.tempdecl);
4551                     if (TemplateDeclaration td = ti.tempdecl.isTemplateDeclaration())
4552                         exp.e1 = new DotTemplateExp(exp.loc, se.e1, td);
4553                     else if (OverDeclaration od = ti.tempdecl.isOverDeclaration())
4554                     {
4555                         exp.e1 = new DotVarExp(exp.loc, se.e1, od, true);
4556                     }
4557                     else
4558                         exp.e1 = new DotExp(exp.loc, se.e1, new OverExp(exp.loc, ti.tempdecl.isOverloadSet()));
4559                 }
4560                 else
4561                 {
4562                     Expression e1x = exp.e1.expressionSemantic(sc);
4563                     if (e1x.op == EXP.error)
4564                     {
4565                         result = e1x;
4566                         return;
4567                     }
4568                     exp.e1 = e1x;
4569                 }
4570             }
4571         }
4572 
4573         Type att = null;
4574     Lagain:
4575         //printf("Lagain: %s\n", toChars());
4576         exp.f = null;
4577         if (exp.e1.op == EXP.this_ || exp.e1.op == EXP.super_)
4578         {
4579             // semantic() run later for these
4580         }
4581         else
4582         {
4583             if (DotIdExp die = exp.e1.isDotIdExp())
4584             {
4585                 exp.e1 = die.expressionSemantic(sc);
4586                 /* Look for e1 having been rewritten to expr.opDispatch!(string)
4587                  * We handle such earlier, so go back.
4588                  * Note that in the rewrite, we carefully did not run semantic() on e1
4589                  */
4590                 if (exp.e1.op == EXP.dotTemplateInstance)
4591                 {
4592                     goto Ldotti;
4593                 }
4594             }
4595             else
4596             {
4597                 __gshared int nest;
4598                 if (++nest > global.recursionLimit)
4599                 {
4600                     exp.error("recursive evaluation of `%s`", exp.toChars());
4601                     --nest;
4602                     return setError();
4603                 }
4604                 Expression ex = unaSemantic(exp, sc);
4605                 --nest;
4606                 if (ex)
4607                 {
4608                     result = ex;
4609                     return;
4610                 }
4611             }
4612 
4613             /* Look for e1 being a lazy parameter
4614              */
4615             if (VarExp ve = exp.e1.isVarExp())
4616             {
4617                 if (ve.var.storage_class & STC.lazy_)
4618                 {
4619                     // lazy parameters can be called without violating purity and safety
4620                     Type tw = ve.var.type;
4621                     Type tc = ve.var.type.substWildTo(MODFlags.const_);
4622                     auto tf = new TypeFunction(ParameterList(), tc, LINK.d, STC.safe | STC.pure_);
4623                     (tf = cast(TypeFunction)tf.typeSemantic(exp.loc, sc)).next = tw; // hack for bug7757
4624                     auto t = new TypeDelegate(tf);
4625                     ve.type = t.typeSemantic(exp.loc, sc);
4626                 }
4627                 VarDeclaration v = ve.var.isVarDeclaration();
4628                 if (v && ve.checkPurity(sc, v))
4629                     return setError();
4630             }
4631 
4632             if (exp.e1.op == EXP.symbolOffset && (cast(SymOffExp)exp.e1).hasOverloads)
4633             {
4634                 SymOffExp se = cast(SymOffExp)exp.e1;
4635                 exp.e1 = new VarExp(se.loc, se.var, true);
4636                 exp.e1 = exp.e1.expressionSemantic(sc);
4637             }
4638             else if (DotExp de = exp.e1.isDotExp())
4639             {
4640                 if (de.e2.op == EXP.overloadSet)
4641                 {
4642                     ethis = de.e1;
4643                     tthis = de.e1.type;
4644                     exp.e1 = de.e2;
4645                 }
4646             }
4647             else if (exp.e1.op == EXP.star && exp.e1.type.ty == Tfunction)
4648             {
4649                 // Rewrite (*fp)(arguments) to fp(arguments)
4650                 exp.e1 = (cast(PtrExp)exp.e1).e1;
4651             }
4652             else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
4653             {
4654                 const numArgs = exp.arguments ? exp.arguments.length : 0;
4655 
4656                 /* Ambiguous cases arise from CParser where there is not enough
4657                  * information to determine if we have a function call or declaration.
4658                  *   type-name ( identifier ) ;
4659                  *   identifier ( identifier ) ;
4660                  * If exp.e1 is a type-name, then this is a declaration. C11 does not
4661                  * have type construction syntax, so don't convert this to a cast().
4662                  */
4663                 if (numArgs == 1)
4664                 {
4665                     Expression arg = (*exp.arguments)[0];
4666                     if (auto ie = (*exp.arguments)[0].isIdentifierExp())
4667                     {
4668                         TypeExp te = cast(TypeExp)exp.e1;
4669                         auto initializer = new VoidInitializer(ie.loc);
4670                         Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
4671                         auto decls = new Dsymbols(1);
4672                         (*decls)[0] = s;
4673                         s = new LinkDeclaration(s.loc, LINK.c, decls);
4674                         result = new DeclarationExp(exp.loc, s);
4675                         result = result.expressionSemantic(sc);
4676                     }
4677                     else
4678                     {
4679                         arg.error("identifier or `(` expected");
4680                         result = ErrorExp.get();
4681                     }
4682                     return;
4683                 }
4684                 exp.error("identifier or `(` expected before `)`");
4685                 result = ErrorExp.get();
4686                 return;
4687             }
4688         }
4689 
4690         Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
4691 
4692         if (exp.e1.op == EXP.error)
4693         {
4694             result = exp.e1;
4695             return;
4696         }
4697         if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
4698             preFunctionParameters(sc, exp.argumentList))
4699             return setError();
4700 
4701         // Check for call operator overload
4702         if (t1)
4703         {
4704             if (t1.ty == Tstruct)
4705             {
4706                 auto sd = (cast(TypeStruct)t1).sym;
4707                 sd.size(exp.loc); // Resolve forward references to construct object
4708                 if (sd.sizeok != Sizeok.done)
4709                     return setError();
4710                 if (!sd.ctor)
4711                     sd.ctor = sd.searchCtor();
4712                 /* If `sd.ctor` is a generated copy constructor, this means that it
4713                    is the single constructor that this struct has. In order to not
4714                    disable default construction, the ctor is nullified. The side effect
4715                    of this is that the generated copy constructor cannot be called
4716                    explicitly, but that is ok, because when calling a constructor the
4717                    default constructor should have priority over the generated copy
4718                    constructor.
4719                 */
4720                 if (sd.ctor)
4721                 {
4722                     auto ctor = sd.ctor.isCtorDeclaration();
4723                     if (ctor && ctor.isCpCtor && ctor.isGenerated())
4724                         sd.ctor = null;
4725                 }
4726 
4727                 // First look for constructor
4728                 if (exp.e1.op == EXP.type && sd.ctor)
4729                 {
4730                     if (!sd.noDefaultCtor && !(exp.arguments && exp.arguments.length))
4731                         goto Lx;
4732 
4733                     /* https://issues.dlang.org/show_bug.cgi?id=20695
4734                        If all constructors are copy constructors, then
4735                        try default construction.
4736                      */
4737                     if (!sd.hasRegularCtor &&
4738                         // https://issues.dlang.org/show_bug.cgi?id=22639
4739                         // we might still have a copy constructor that could be called
4740                         (*exp.arguments)[0].type.mutableOf != sd.type.mutableOf())
4741                         goto Lx;
4742 
4743                     auto sle = new StructLiteralExp(exp.loc, sd, null, exp.e1.type);
4744                     if (!sd.fill(exp.loc, *sle.elements, true))
4745                         return setError();
4746                     if (checkFrameAccess(exp.loc, sc, sd, sle.elements.length))
4747                         return setError();
4748 
4749                     // https://issues.dlang.org/show_bug.cgi?id=14556
4750                     // Set concrete type to avoid further redundant semantic().
4751                     sle.type = exp.e1.type;
4752 
4753                     /* Constructor takes a mutable object, so don't use
4754                      * the immutable initializer symbol.
4755                      */
4756                     sle.useStaticInit = false;
4757 
4758                     Expression e = sle;
4759                     if (auto cf = sd.ctor.isCtorDeclaration())
4760                     {
4761                         e = new DotVarExp(exp.loc, e, cf, true);
4762                     }
4763                     else if (auto td = sd.ctor.isTemplateDeclaration())
4764                     {
4765                         e = new DotIdExp(exp.loc, e, td.ident);
4766                     }
4767                     else if (auto os = sd.ctor.isOverloadSet())
4768                     {
4769                         e = new DotExp(exp.loc, e, new OverExp(exp.loc, os));
4770                     }
4771                     else
4772                         assert(0);
4773                     e = new CallExp(exp.loc, e, exp.arguments);
4774                     e = e.expressionSemantic(sc);
4775                     result = e;
4776                     return;
4777                 }
4778                 // No constructor, look for overload of opCall
4779                 if (search_function(sd, Id.call))
4780                     goto L1;
4781                 // overload of opCall, therefore it's a call
4782                 if (exp.e1.op != EXP.type)
4783                 {
4784                     if (sd.aliasthis && !isRecursiveAliasThis(att, exp.e1.type))
4785                     {
4786                         exp.e1 = resolveAliasThis(sc, exp.e1);
4787                         goto Lagain;
4788                     }
4789                     exp.error("%s `%s` does not overload ()", sd.kind(), sd.toChars());
4790                     return setError();
4791                 }
4792 
4793                 /* It's a struct literal
4794                  */
4795             Lx:
4796                 Expressions* resolvedArgs = exp.arguments;
4797                 if (exp.names)
4798                 {
4799                     resolvedArgs = resolveStructLiteralNamedArgs(sd, exp.e1.type, sc, exp.loc,
4800                         (*exp.names)[],
4801                         (size_t i, Type t) => (*exp.arguments)[i],
4802                         i => (*exp.arguments)[i].loc
4803                     );
4804                     if (!resolvedArgs)
4805                     {
4806                         result = ErrorExp.get();
4807                         return;
4808                     }
4809                 }
4810 
4811                 Expression e = new StructLiteralExp(exp.loc, sd, resolvedArgs, exp.e1.type);
4812                 e = e.expressionSemantic(sc);
4813                 result = e;
4814                 return;
4815             }
4816             else if (t1.ty == Tclass)
4817             {
4818             L1:
4819                 // Rewrite as e1.call(arguments)
4820                 Expression e = new DotIdExp(exp.loc, exp.e1, Id.call);
4821                 e = new CallExp(exp.loc, e, exp.arguments, exp.names);
4822                 e = e.expressionSemantic(sc);
4823                 result = e;
4824                 return;
4825             }
4826             else if (exp.e1.op == EXP.type && t1.isscalar())
4827             {
4828                 Expression e;
4829 
4830                 // Make sure to use the enum type itself rather than its
4831                 // base type
4832                 // https://issues.dlang.org/show_bug.cgi?id=16346
4833                 if (exp.e1.type.ty == Tenum)
4834                 {
4835                     t1 = exp.e1.type;
4836                 }
4837 
4838                 if (!exp.arguments || exp.arguments.length == 0)
4839                 {
4840                     e = t1.defaultInitLiteral(exp.loc);
4841                 }
4842                 else if (exp.arguments.length == 1)
4843                 {
4844                     e = (*exp.arguments)[0];
4845                     e = e.implicitCastTo(sc, t1);
4846                     e = new CastExp(exp.loc, e, t1);
4847                 }
4848                 else
4849                 {
4850                     exp.error("more than one argument for construction of `%s`", t1.toChars());
4851                     return setError();
4852                 }
4853                 e = e.expressionSemantic(sc);
4854                 result = e;
4855                 return;
4856             }
4857         }
4858 
4859         FuncDeclaration resolveOverloadSet(Loc loc, Scope* sc,
4860             OverloadSet os, Objects* tiargs, Type tthis, ArgumentList argumentList)
4861         {
4862             FuncDeclaration f = null;
4863             foreach (s; os.a)
4864             {
4865                 if (tiargs && s.isFuncDeclaration())
4866                     continue;
4867                 if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
4868                 {
4869                     if (f2.errors)
4870                         return null;
4871                     if (f)
4872                     {
4873                         /* Match in more than one overload set,
4874                          * even if one is a 'better' match than the other.
4875                          */
4876                         if (f.isCsymbol() && f2.isCsymbol())
4877                         {
4878                             /* C has global name space, so just pick one, such as f.
4879                              * If f and f2 are not compatible, that's how C rolls.
4880                              */
4881                         }
4882                         else
4883                             ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
4884                     }
4885                     else
4886                         f = f2;
4887                 }
4888             }
4889             if (!f)
4890             {
4891                 .error(loc, "no overload matches for `%s`", exp.toChars());
4892                 errorSupplemental(loc, "Candidates are:");
4893                 foreach (s; os.a)
4894                 {
4895                     overloadApply(s, (ds){
4896                         if (auto fd = ds.isFuncDeclaration())
4897                             .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
4898                                 fd.type.toTypeFunction().parameterList.parametersTypeToChars());
4899                         else
4900                             .errorSupplemental(ds.loc, "%s", ds.toChars());
4901                         return 0;
4902                     });
4903                 }
4904             }
4905             else if (f.errors)
4906                 f = null;
4907             return f;
4908         }
4909 
4910         bool isSuper = false;
4911         if (exp.e1.op == EXP.dotVariable && t1.ty == Tfunction || exp.e1.op == EXP.dotTemplateDeclaration)
4912         {
4913             UnaExp ue = cast(UnaExp)exp.e1;
4914 
4915             Expression ue1old = ue.e1; // need for 'right this' check
4916             DotVarExp dve;
4917             DotTemplateExp dte;
4918             Dsymbol s;
4919             if (exp.e1.op == EXP.dotVariable)
4920             {
4921                 dve = cast(DotVarExp)exp.e1;
4922                 dte = null;
4923                 s = dve.var;
4924                 tiargs = null;
4925             }
4926             else
4927             {
4928                 dve = null;
4929                 dte = cast(DotTemplateExp)exp.e1;
4930                 s = dte.td;
4931             }
4932 
4933             // Do overload resolution
4934             exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, ue.e1.type, exp.argumentList, FuncResolveFlag.standard);
4935             if (!exp.f || exp.f.errors || exp.f.type.ty == Terror)
4936                 return setError();
4937 
4938             if (exp.f.interfaceVirtual)
4939             {
4940                 /* Cast 'this' to the type of the interface, and replace f with the interface's equivalent
4941                  */
4942                 auto b = exp.f.interfaceVirtual;
4943                 auto ad2 = b.sym;
4944                 ue.e1 = ue.e1.castTo(sc, ad2.type.addMod(ue.e1.type.mod));
4945                 ue.e1 = ue.e1.expressionSemantic(sc);
4946                 auto vi = exp.f.findVtblIndex(&ad2.vtbl, cast(int)ad2.vtbl.length);
4947                 assert(vi >= 0);
4948                 exp.f = ad2.vtbl[vi].isFuncDeclaration();
4949                 assert(exp.f);
4950             }
4951             if (exp.f.needThis())
4952             {
4953                 AggregateDeclaration ad = exp.f.isMemberLocal();
4954                 ue.e1 = getRightThis(exp.loc, sc, ad, ue.e1, exp.f);
4955                 if (ue.e1.op == EXP.error)
4956                 {
4957                     result = ue.e1;
4958                     return;
4959                 }
4960                 ethis = ue.e1;
4961                 tthis = ue.e1.type;
4962                 if (!(exp.f.type.ty == Tfunction && (cast(TypeFunction)exp.f.type).isScopeQual))
4963                 {
4964                     if (checkParamArgumentEscape(sc, exp.f, Id.This, exp.f.vthis, STC.undefined_, ethis, false, false))
4965                         return setError();
4966                 }
4967             }
4968 
4969             /* Cannot call public functions from inside invariant
4970              * (because then the invariant would have infinite recursion)
4971              */
4972             if (sc.func && sc.func.isInvariantDeclaration() && ue.e1.op == EXP.this_ && exp.f.addPostInvariant())
4973             {
4974                 exp.error("cannot call `public`/`export` function `%s` from invariant", exp.f.toChars());
4975                 return setError();
4976             }
4977 
4978             if (!exp.ignoreAttributes)
4979                 checkFunctionAttributes(exp, sc, exp.f);
4980             checkAccess(exp.loc, sc, ue.e1, exp.f);
4981             if (!exp.f.needThis())
4982             {
4983                 exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false));
4984             }
4985             else
4986             {
4987                 if (ue1old.checkRightThis(sc))
4988                     return setError();
4989                 if (exp.e1.op == EXP.dotVariable)
4990                 {
4991                     dve.var = exp.f;
4992                     exp.e1.type = exp.f.type;
4993                 }
4994                 else
4995                 {
4996                     exp.e1 = new DotVarExp(exp.loc, dte.e1, exp.f, false);
4997                     exp.e1 = exp.e1.expressionSemantic(sc);
4998                     if (exp.e1.op == EXP.error)
4999                         return setError();
5000                     ue = cast(UnaExp)exp.e1;
5001                 }
5002                 version (none)
5003                 {
5004                     printf("ue.e1 = %s\n", ue.e1.toChars());
5005                     printf("f = %s\n", exp.f.toChars());
5006                     printf("t1 = %s\n", t1.toChars());
5007                     printf("e1 = %s\n", exp.e1.toChars());
5008                     printf("e1.type = %s\n", exp.e1.type.toChars());
5009                 }
5010 
5011                 // See if we need to adjust the 'this' pointer
5012                 AggregateDeclaration ad = exp.f.isThis();
5013                 ClassDeclaration cd = ue.e1.type.isClassHandle();
5014                 if (ad && cd && ad.isClassDeclaration())
5015                 {
5016                     if (ue.e1.op == EXP.dotType)
5017                     {
5018                         ue.e1 = (cast(DotTypeExp)ue.e1).e1;
5019                         exp.directcall = true;
5020                     }
5021                     else if (ue.e1.op == EXP.super_)
5022                         exp.directcall = true;
5023                     else if ((cd.storage_class & STC.final_) != 0) // https://issues.dlang.org/show_bug.cgi?id=14211
5024                         exp.directcall = true;
5025 
5026                     if (ad != cd)
5027                     {
5028                         ue.e1 = ue.e1.castTo(sc, ad.type.addMod(ue.e1.type.mod));
5029                         ue.e1 = ue.e1.expressionSemantic(sc);
5030                     }
5031                 }
5032             }
5033             // If we've got a pointer to a function then deference it
5034             // https://issues.dlang.org/show_bug.cgi?id=16483
5035             if (exp.e1.type.isPtrToFunction())
5036             {
5037                 Expression e = new PtrExp(exp.loc, exp.e1);
5038                 e.type = exp.e1.type.nextOf();
5039                 exp.e1 = e;
5040             }
5041             t1 = exp.e1.type;
5042         }
5043         else if (exp.e1.op == EXP.super_ || exp.e1.op == EXP.this_)
5044         {
5045             auto ad = sc.func ? sc.func.isThis() : null;
5046             auto cd = ad ? ad.isClassDeclaration() : null;
5047 
5048             isSuper = exp.e1.op == EXP.super_;
5049             if (isSuper)
5050             {
5051                 // Base class constructor call
5052                 if (!cd || !cd.baseClass || !sc.func.isCtorDeclaration())
5053                 {
5054                     exp.error("super class constructor call must be in a constructor");
5055                     return setError();
5056                 }
5057                 if (!cd.baseClass.ctor)
5058                 {
5059                     exp.error("no super class constructor for `%s`", cd.baseClass.toChars());
5060                     return setError();
5061                 }
5062             }
5063             else
5064             {
5065                 // `this` call expression must be inside a
5066                 // constructor
5067                 if (!ad || !sc.func.isCtorDeclaration())
5068                 {
5069                     exp.error("constructor call must be in a constructor");
5070                     return setError();
5071                 }
5072 
5073                 // https://issues.dlang.org/show_bug.cgi?id=18719
5074                 // If `exp` is a call expression to another constructor
5075                 // then it means that all struct/class fields will be
5076                 // initialized after this call.
5077                 foreach (ref field; sc.ctorflow.fieldinit)
5078                 {
5079                     field.csx |= CSX.this_ctor;
5080                 }
5081             }
5082 
5083             if (!sc.intypeof && !(sc.ctorflow.callSuper & CSX.halt))
5084             {
5085                 if (sc.inLoop || sc.ctorflow.callSuper & CSX.label)
5086                     exp.error("constructor calls not allowed in loops or after labels");
5087                 if (sc.ctorflow.callSuper & (CSX.super_ctor | CSX.this_ctor))
5088                     exp.error("multiple constructor calls");
5089                 if ((sc.ctorflow.callSuper & CSX.return_) && !(sc.ctorflow.callSuper & CSX.any_ctor))
5090                     exp.error("an earlier `return` statement skips constructor");
5091                 sc.ctorflow.callSuper |= CSX.any_ctor | (isSuper ? CSX.super_ctor : CSX.this_ctor);
5092             }
5093 
5094             tthis = ad.type.addMod(sc.func.type.mod);
5095             auto ctor = isSuper ? cd.baseClass.ctor : ad.ctor;
5096             if (auto os = ctor.isOverloadSet())
5097                 exp.f = resolveOverloadSet(exp.loc, sc, os, null, tthis, exp.argumentList);
5098             else
5099                 exp.f = resolveFuncCall(exp.loc, sc, ctor, null, tthis, exp.argumentList, FuncResolveFlag.standard);
5100 
5101             if (!exp.f || exp.f.errors)
5102                 return setError();
5103 
5104             checkFunctionAttributes(exp, sc, exp.f);
5105             checkAccess(exp.loc, sc, null, exp.f);
5106 
5107             exp.e1 = new DotVarExp(exp.e1.loc, exp.e1, exp.f, false);
5108             exp.e1 = exp.e1.expressionSemantic(sc);
5109             // https://issues.dlang.org/show_bug.cgi?id=21095
5110             if (exp.e1.op == EXP.error)
5111                 return setError();
5112             t1 = exp.e1.type;
5113 
5114             // BUG: this should really be done by checking the static
5115             // call graph
5116             if (exp.f == sc.func)
5117             {
5118                 exp.error("cyclic constructor call");
5119                 return setError();
5120             }
5121         }
5122         else if (auto oe = exp.e1.isOverExp())
5123         {
5124             exp.f = resolveOverloadSet(exp.loc, sc, oe.vars, tiargs, tthis, exp.argumentList);
5125             if (!exp.f)
5126                 return setError();
5127             if (ethis)
5128                 exp.e1 = new DotVarExp(exp.loc, ethis, exp.f, false);
5129             else
5130                 exp.e1 = new VarExp(exp.loc, exp.f, false);
5131             goto Lagain;
5132         }
5133         else if (!t1)
5134         {
5135             exp.error("function expected before `()`, not `%s`", exp.e1.toChars());
5136             return setError();
5137         }
5138         else if (t1.ty == Terror)
5139         {
5140             return setError();
5141         }
5142         else if (t1.ty != Tfunction)
5143         {
5144             TypeFunction tf;
5145             const(char)* p;
5146             Dsymbol s;
5147             exp.f = null;
5148             if (auto fe = exp.e1.isFuncExp())
5149             {
5150                 // function literal that direct called is always inferred.
5151                 assert(fe.fd);
5152                 exp.f = fe.fd;
5153                 tf = cast(TypeFunction)exp.f.type;
5154                 p = "function literal";
5155             }
5156             else if (t1.ty == Tdelegate)
5157             {
5158                 TypeDelegate td = cast(TypeDelegate)t1;
5159                 assert(td.next.ty == Tfunction);
5160                 tf = cast(TypeFunction)td.next;
5161                 p = "delegate";
5162             }
5163             else if (auto tfx = t1.isPtrToFunction())
5164             {
5165                 tf = tfx;
5166                 p = "function pointer";
5167             }
5168             else if (exp.e1.op == EXP.dotVariable && (cast(DotVarExp)exp.e1).var.isOverDeclaration())
5169             {
5170                 DotVarExp dve = cast(DotVarExp)exp.e1;
5171                 exp.f = resolveFuncCall(exp.loc, sc, dve.var, tiargs, dve.e1.type, exp.argumentList, FuncResolveFlag.overloadOnly);
5172                 if (!exp.f)
5173                     return setError();
5174                 if (exp.f.needThis())
5175                 {
5176                     dve.var = exp.f;
5177                     dve.type = exp.f.type;
5178                     dve.hasOverloads = false;
5179                     goto Lagain;
5180                 }
5181                 exp.e1 = new VarExp(dve.loc, exp.f, false);
5182                 Expression e = new CommaExp(exp.loc, dve.e1, exp);
5183                 result = e.expressionSemantic(sc);
5184                 return;
5185             }
5186             else if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.isOverDeclaration())
5187             {
5188                 s = (cast(VarExp)exp.e1).var;
5189                 goto L2;
5190             }
5191             else if (exp.e1.op == EXP.template_)
5192             {
5193                 s = (cast(TemplateExp)exp.e1).td;
5194             L2:
5195                 exp.f = resolveFuncCall(exp.loc, sc, s, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5196                 if (!exp.f || exp.f.errors)
5197                     return setError();
5198                 if (exp.f.needThis())
5199                 {
5200                     if (hasThis(sc))
5201                     {
5202                         // Supply an implicit 'this', as in
5203                         //    this.ident
5204                         exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), exp.f, false);
5205                         goto Lagain;
5206                     }
5207                     else if (isNeedThisScope(sc, exp.f))
5208                     {
5209                         exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5210                         return setError();
5211                     }
5212                 }
5213                 exp.e1 = new VarExp(exp.e1.loc, exp.f, false);
5214                 goto Lagain;
5215             }
5216             else
5217             {
5218                 exp.error("function expected before `()`, not `%s` of type `%s`", exp.e1.toChars(), exp.e1.type.toChars());
5219                 return setError();
5220             }
5221 
5222             const(char)* failMessage;
5223             if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5224             {
5225                 OutBuffer buf;
5226                 buf.writeByte('(');
5227                 argExpTypesToCBuffer(&buf, exp.arguments);
5228                 buf.writeByte(')');
5229                 if (tthis)
5230                     tthis.modToBuffer(&buf);
5231 
5232                 //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5233                 .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5234                     p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5235                 if (failMessage)
5236                     errorSupplemental(exp.loc, "%s", failMessage);
5237                 return setError();
5238             }
5239             // Purity and safety check should run after testing arguments matching
5240             if (exp.f)
5241             {
5242                 exp.checkPurity(sc, exp.f);
5243                 exp.checkSafety(sc, exp.f);
5244                 exp.checkNogc(sc, exp.f);
5245                 if (exp.f.checkNestedReference(sc, exp.loc))
5246                     return setError();
5247             }
5248             else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
5249             {
5250                 bool err = false;
5251                 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
5252                 {
5253                     exp.error("`pure` %s `%s` cannot call impure %s `%s`",
5254                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5255                     err = true;
5256                 }
5257                 if (!tf.isnogc && sc.func.setGC(exp.loc, "`@nogc` %s `%s` cannot call non-@nogc `%s`", exp.e1))
5258                 {
5259                     exp.error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
5260                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5261                     err = true;
5262                 }
5263                 if (tf.trust <= TRUST.system && sc.setUnsafe(true, exp.loc,
5264                     "`@safe` function `%s` cannot call `@system` `%s`", sc.func, exp.e1))
5265                 {
5266                     exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
5267                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
5268                     err = true;
5269                 }
5270                 if (err)
5271                     return setError();
5272             }
5273 
5274             if (t1.ty == Tpointer)
5275             {
5276                 Expression e = new PtrExp(exp.loc, exp.e1);
5277                 e.type = tf;
5278                 exp.e1 = e;
5279             }
5280             t1 = tf;
5281         }
5282         else if (VarExp ve = exp.e1.isVarExp())
5283         {
5284             // Do overload resolution
5285             exp.f = ve.var.isFuncDeclaration();
5286             assert(exp.f);
5287             tiargs = null;
5288 
5289             if (exp.f.overnext)
5290                 exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.overloadOnly);
5291             else
5292             {
5293                 exp.f = exp.f.toAliasFunc();
5294                 TypeFunction tf = cast(TypeFunction)exp.f.type;
5295                 const(char)* failMessage;
5296                 if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
5297                 {
5298                     OutBuffer buf;
5299                     buf.writeByte('(');
5300                     argExpTypesToCBuffer(&buf, exp.arguments);
5301                     buf.writeByte(')');
5302 
5303                     //printf("tf = %s, args = %s\n", tf.deco, (*arguments)[0].type.deco);
5304                     .error(exp.loc, "%s `%s%s` is not callable using argument types `%s`",
5305                         exp.f.kind(), exp.f.toPrettyChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
5306                     if (failMessage)
5307                         errorSupplemental(exp.loc, "%s", failMessage);
5308                     exp.f = null;
5309                 }
5310             }
5311             if (!exp.f || exp.f.errors)
5312                 return setError();
5313 
5314             if (exp.f.needThis())
5315             {
5316                 // Change the ancestor lambdas to delegate before hasThis(sc) call.
5317                 if (exp.f.checkNestedReference(sc, exp.loc))
5318                     return setError();
5319 
5320                 auto memberFunc = hasThis(sc);
5321                 if (memberFunc && haveSameThis(memberFunc, exp.f))
5322                 {
5323                     // Supply an implicit 'this', as in
5324                     //    this.ident
5325                     exp.e1 = new DotVarExp(exp.loc, (new ThisExp(exp.loc)).expressionSemantic(sc), ve.var);
5326                     // Note: we cannot use f directly, because further overload resolution
5327                     // through the supplied 'this' may cause different result.
5328                     goto Lagain;
5329                 }
5330                 else if (isNeedThisScope(sc, exp.f))
5331                 {
5332                     // At this point it is possible that `exp.f` had an ambiguity error that was
5333                     // silenced because the previous call to `resolveFuncCall` was done using
5334                     // `FuncResolveFlag.overloadOnly`. To make sure that a proper error message
5335                     // is printed, redo the call with `FuncResolveFlag.standard`.
5336                     //
5337                     // https://issues.dlang.org/show_bug.cgi?id=22157
5338                     if (exp.f.overnext)
5339                         exp.f = resolveFuncCall(exp.loc, sc, exp.f, tiargs, null, exp.argumentList, FuncResolveFlag.standard);
5340 
5341                     if (!exp.f || exp.f.errors)
5342                         return setError();
5343 
5344                     // If no error is printed, it means that `f` is the single matching overload
5345                     // and it needs `this`.
5346                     exp.error("need `this` for `%s` of type `%s`", exp.f.toChars(), exp.f.type.toChars());
5347                     return setError();
5348                 }
5349             }
5350 
5351             checkFunctionAttributes(exp, sc, exp.f);
5352             checkAccess(exp.loc, sc, null, exp.f);
5353             if (exp.f.checkNestedReference(sc, exp.loc))
5354                 return setError();
5355 
5356             ethis = null;
5357             tthis = null;
5358 
5359             if (ve.hasOverloads)
5360             {
5361                 exp.e1 = new VarExp(ve.loc, exp.f, false);
5362                 exp.e1.type = exp.f.type;
5363             }
5364             t1 = exp.f.type;
5365         }
5366         assert(t1.ty == Tfunction);
5367 
5368         Expression argprefix;
5369         if (!exp.arguments)
5370             exp.arguments = new Expressions();
5371         if (functionParameters(exp.loc, sc, cast(TypeFunction)t1, ethis, tthis, exp.argumentList, exp.f, &exp.type, &argprefix))
5372             return setError();
5373 
5374         if (!exp.type)
5375         {
5376             exp.e1 = e1org; // https://issues.dlang.org/show_bug.cgi?id=10922
5377                         // avoid recursive expression printing
5378             exp.error("forward reference to inferred return type of function call `%s`", exp.toChars());
5379             return setError();
5380         }
5381 
5382         if (exp.f && exp.f.tintro)
5383         {
5384             Type t = exp.type;
5385             int offset = 0;
5386             TypeFunction tf = cast(TypeFunction)exp.f.tintro;
5387             if (tf.next.isBaseOf(t, &offset) && offset)
5388             {
5389                 exp.type = tf.next;
5390                 result = Expression.combine(argprefix, exp.castTo(sc, t));
5391                 return;
5392             }
5393         }
5394 
5395         // Handle the case of a direct lambda call
5396         if (exp.f && exp.f.isFuncLiteralDeclaration() && sc.func && !sc.intypeof)
5397         {
5398             exp.f.tookAddressOf = 0;
5399         }
5400 
5401         result = Expression.combine(argprefix, exp);
5402 
5403         if (isSuper)
5404         {
5405             auto ad = sc.func ? sc.func.isThis() : null;
5406             auto cd = ad ? ad.isClassDeclaration() : null;
5407             if (cd && cd.classKind == ClassKind.cpp && exp.f && !exp.f.fbody)
5408             {
5409                 // if super is defined in C++, it sets the vtable pointer to the base class
5410                 // so we have to restore it, but still return 'this' from super() call:
5411                 // (auto __vptrTmp = this.__vptr, auto __superTmp = super()), (this.__vptr = __vptrTmp, __superTmp)
5412                 Loc loc = exp.loc;
5413 
5414                 auto vptr = new DotIdExp(loc, new ThisExp(loc), Id.__vptr);
5415                 auto vptrTmpDecl = copyToTemp(0, "__vptrTmp", vptr);
5416                 auto declareVptrTmp = new DeclarationExp(loc, vptrTmpDecl);
5417 
5418                 auto superTmpDecl = copyToTemp(0, "__superTmp", result);
5419                 auto declareSuperTmp = new DeclarationExp(loc, superTmpDecl);
5420 
5421                 auto declareTmps = new CommaExp(loc, declareVptrTmp, declareSuperTmp);
5422 
5423                 auto restoreVptr = new AssignExp(loc, vptr.syntaxCopy(), new VarExp(loc, vptrTmpDecl));
5424 
5425                 Expression e = new CommaExp(loc, declareTmps, new CommaExp(loc, restoreVptr, new VarExp(loc, superTmpDecl)));
5426                 result = e.expressionSemantic(sc);
5427             }
5428         }
5429 
5430         // declare dual-context container
5431         if (exp.f && exp.f.hasDualContext() && !sc.intypeof && sc.func)
5432         {
5433             // check access to second `this`
5434             if (AggregateDeclaration ad2 = exp.f.isMember2())
5435             {
5436                 Expression te = new ThisExp(exp.loc).expressionSemantic(sc);
5437                 if (te.op != EXP.error)
5438                     te = getRightThis(exp.loc, sc, ad2, te, exp.f);
5439                 if (te.op == EXP.error)
5440                 {
5441                     exp.error("need `this` of type `%s` to call function `%s`", ad2.toChars(), exp.f.toChars());
5442                     return setError();
5443                 }
5444             }
5445             exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f);
5446             Expression de = new DeclarationExp(exp.loc, exp.vthis2);
5447             result = Expression.combine(de, result);
5448             result = result.expressionSemantic(sc);
5449         }
5450     }
5451 
5452     override void visit(DeclarationExp e)
5453     {
5454         if (e.type)
5455         {
5456             result = e;
5457             return;
5458         }
5459         static if (LOGSEMANTIC)
5460         {
5461             printf("DeclarationExp::semantic() %s\n", e.toChars());
5462         }
5463 
5464         uint olderrors = global.errors;
5465 
5466         /* This is here to support extern(linkage) declaration,
5467          * where the extern(linkage) winds up being an AttribDeclaration
5468          * wrapper.
5469          */
5470         Dsymbol s = e.declaration;
5471 
5472         while (1)
5473         {
5474             AttribDeclaration ad = s.isAttribDeclaration();
5475             if (ad)
5476             {
5477                 if (ad.decl && ad.decl.length == 1)
5478                 {
5479                     s = (*ad.decl)[0];
5480                     continue;
5481                 }
5482             }
5483             break;
5484         }
5485 
5486         //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
5487         // Insert into both local scope and function scope.
5488         // Must be unique in both.
5489         if (s.ident)
5490         {
5491             VarDeclaration v = s.isVarDeclaration();
5492             if (v)
5493             {
5494                 if (sc.flags & SCOPE.Cfile)
5495                 {
5496                     /* Do semantic() on the type before inserting v into the symbol table
5497                      */
5498                     if (!v.originalType)
5499                         v.originalType = v.type.syntaxCopy();
5500                     Scope* sc2 = sc.push();
5501                     sc2.stc |= v.storage_class & STC.FUNCATTR;
5502                     sc2.linkage = LINK.c;       // account for the extern(C) in front of the declaration
5503                     v.inuse++;
5504                     v.type = v.type.typeSemantic(v.loc, sc2);
5505                     v.inuse--;
5506                     sc2.pop();
5507                 }
5508                 else
5509                 {
5510                     /* Do semantic() on initializer first so this will be illegal:
5511                      *      int a = a;
5512                      */
5513                     e.declaration.dsymbolSemantic(sc);
5514                     s.parent = sc.parent;
5515                 }
5516             }
5517 
5518             if (!sc.insert(s))
5519             {
5520                 auto conflict = sc.search(Loc.initial, s.ident, null);
5521                 e.error("declaration `%s` is already defined", s.toPrettyChars());
5522                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5523                                   conflict.kind(), conflict.toChars());
5524                 return setError();
5525             }
5526 
5527             if (v && (sc.flags & SCOPE.Cfile))
5528             {
5529                 /* Do semantic() on initializer last so this will be legal:
5530                  *      int a = a;
5531                  */
5532                 e.declaration.dsymbolSemantic(sc);
5533                 s.parent = sc.parent;
5534             }
5535 
5536             if (sc.func)
5537             {
5538                 // https://issues.dlang.org/show_bug.cgi?id=11720
5539                 if ((s.isFuncDeclaration() ||
5540                      s.isAggregateDeclaration() ||
5541                      s.isEnumDeclaration() ||
5542                      s.isTemplateDeclaration() ||
5543                      v
5544                     ) && !sc.func.localsymtab.insert(s))
5545                 {
5546                     // Get the previous symbol
5547                     Dsymbol originalSymbol = sc.func.localsymtab.lookup(s.ident);
5548 
5549                     // Perturb the name mangling so that the symbols can co-exist
5550                     // instead of colliding
5551                     s.localNum = cast(ushort)(originalSymbol.localNum + 1);
5552                     // 65535 should be enough for anyone
5553                     if (!s.localNum)
5554                     {
5555                         e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
5556                         return setError();
5557                     }
5558 
5559                     // Replace originalSymbol with s, which updates the localCount
5560                     sc.func.localsymtab.update(s);
5561 
5562                     // The mangling change only works for D mangling
5563                 }
5564 
5565                 if (!(sc.flags & SCOPE.Cfile))
5566                 {
5567                     /* https://issues.dlang.org/show_bug.cgi?id=21272
5568                      * If we are in a foreach body we need to extract the
5569                      * function containing the foreach
5570                      */
5571                     FuncDeclaration fes_enclosing_func;
5572                     if (sc.func && sc.func.fes)
5573                         fes_enclosing_func = sc.enclosing.enclosing.func;
5574 
5575                     // Disallow shadowing
5576                     for (Scope* scx = sc.enclosing; scx && (scx.func == sc.func || (fes_enclosing_func && scx.func == fes_enclosing_func)); scx = scx.enclosing)
5577                     {
5578                         Dsymbol s2;
5579                         if (scx.scopesym && scx.scopesym.symtab && (s2 = scx.scopesym.symtab.lookup(s.ident)) !is null && s != s2)
5580                         {
5581                             // allow STC.local symbols to be shadowed
5582                             // TODO: not really an optimal design
5583                             auto decl = s2.isDeclaration();
5584                             if (!decl || !(decl.storage_class & STC.local))
5585                             {
5586                                 if (sc.func.fes)
5587                                 {
5588                                     e.deprecation("%s `%s` is shadowing %s `%s`. Rename the `foreach` variable.", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5589                                 }
5590                                 else
5591                                 {
5592                                     e.error("%s `%s` is shadowing %s `%s`", s.kind(), s.ident.toChars(), s2.kind(), s2.toPrettyChars());
5593                                     return setError();
5594                                 }
5595                             }
5596                         }
5597                     }
5598                 }
5599             }
5600         }
5601         if (!s.isVarDeclaration())
5602         {
5603             Scope* sc2 = sc;
5604             if (sc2.stc & (STC.pure_ | STC.nothrow_ | STC.nogc))
5605                 sc2 = sc.push();
5606             sc2.stc &= ~(STC.pure_ | STC.nothrow_ | STC.nogc);
5607             e.declaration.dsymbolSemantic(sc2);
5608             if (sc2 != sc)
5609                 sc2.pop();
5610             s.parent = sc.parent;
5611         }
5612         if (global.errors == olderrors)
5613         {
5614             e.declaration.semantic2(sc);
5615             if (global.errors == olderrors)
5616             {
5617                 e.declaration.semantic3(sc);
5618             }
5619         }
5620         // todo: error in declaration should be propagated.
5621 
5622         e.type = Type.tvoid;
5623         result = e;
5624     }
5625 
5626     override void visit(TypeidExp exp)
5627     {
5628         static if (LOGSEMANTIC)
5629         {
5630             printf("TypeidExp::semantic() %s\n", exp.toChars());
5631         }
5632         Type ta = isType(exp.obj);
5633         Expression ea = isExpression(exp.obj);
5634         Dsymbol sa = isDsymbol(exp.obj);
5635         //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5636 
5637         if (ta)
5638         {
5639             dmd.typesem.resolve(ta, exp.loc, sc, ea, ta, sa, true);
5640         }
5641 
5642         if (ea)
5643         {
5644             if (auto sym = getDsymbol(ea))
5645                 ea = symbolToExp(sym, exp.loc, sc, false);
5646             else
5647                 ea = ea.expressionSemantic(sc);
5648             ea = resolveProperties(sc, ea);
5649             ta = ea.type;
5650             if (ea.op == EXP.type)
5651                 ea = null;
5652         }
5653 
5654         if (!ta)
5655         {
5656             //printf("ta %p ea %p sa %p\n", ta, ea, sa);
5657             exp.error("no type for `typeid(%s)`", ea ? ea.toChars() : (sa ? sa.toChars() : ""));
5658             return setError();
5659         }
5660 
5661         ta.checkComplexTransition(exp.loc, sc);
5662 
5663         Expression e;
5664         auto tb = ta.toBasetype();
5665         if (ea && tb.ty == Tclass)
5666         {
5667             if (tb.toDsymbol(sc).isClassDeclaration().classKind == ClassKind.cpp)
5668             {
5669                 error(exp.loc, "runtime type information is not supported for `extern(C++)` classes");
5670                 e = ErrorExp.get();
5671             }
5672             else if (!Type.typeinfoclass)
5673             {
5674                 error(exp.loc, "`object.TypeInfo_Class` could not be found, but is implicitly used");
5675                 e = ErrorExp.get();
5676             }
5677             else
5678             {
5679                 /* Get the dynamic type, which is .classinfo
5680                 */
5681                 ea = ea.expressionSemantic(sc);
5682                 e = new TypeidExp(ea.loc, ea);
5683                 e.type = Type.typeinfoclass.type;
5684             }
5685         }
5686         else if (ta.ty == Terror)
5687         {
5688             e = ErrorExp.get();
5689         }
5690         else
5691         {
5692             // Handle this in the glue layer
5693             e = new TypeidExp(exp.loc, ta);
5694 
5695             bool genObjCode = true;
5696 
5697             // https://issues.dlang.org/show_bug.cgi?id=23650
5698             // We generate object code for typeinfo, required
5699             // by typeid, only if in non-speculative context
5700             if (sc.flags & SCOPE.compile)
5701             {
5702                 genObjCode = false;
5703             }
5704 
5705             e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
5706             semanticTypeInfo(sc, ta);
5707 
5708             if (ea)
5709             {
5710                 e = new CommaExp(exp.loc, ea, e); // execute ea
5711                 e = e.expressionSemantic(sc);
5712             }
5713         }
5714         result = e;
5715     }
5716 
5717     override void visit(TraitsExp e)
5718     {
5719         result = semanticTraits(e, sc);
5720     }
5721 
5722     override void visit(HaltExp e)
5723     {
5724         static if (LOGSEMANTIC)
5725         {
5726             printf("HaltExp::semantic()\n");
5727         }
5728         e.type = Type.tnoreturn;
5729         result = e;
5730     }
5731 
5732     override void visit(IsExp e)
5733     {
5734         /* is(targ id tok tspec)
5735          * is(targ id :  tok2)
5736          * is(targ id == tok2)
5737          */
5738         Type tded = null;
5739 
5740         void yes()
5741         {
5742             //printf("yes\n");
5743             if (!e.id)
5744             {
5745                 result = IntegerExp.createBool(true);
5746                 return;
5747             }
5748 
5749             Dsymbol s;
5750             Tuple tup = isTuple(tded);
5751             if (tup)
5752                 s = new TupleDeclaration(e.loc, e.id, &tup.objects);
5753             else
5754                 s = new AliasDeclaration(e.loc, e.id, tded);
5755             s.dsymbolSemantic(sc);
5756 
5757             /* The reason for the !tup is unclear. It fails Phobos unittests if it is not there.
5758              * More investigation is needed.
5759              */
5760             if (!tup && !sc.insert(s))
5761             {
5762                 auto conflict = sc.search(Loc.initial, s.ident, null);
5763                 e.error("declaration `%s` is already defined", s.toPrettyChars());
5764                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
5765                                   conflict.kind(), conflict.toChars());
5766             }
5767 
5768             unSpeculative(sc, s);
5769 
5770             result = IntegerExp.createBool(true);
5771         }
5772         void no()
5773         {
5774             result = IntegerExp.createBool(false);
5775             //printf("no\n");
5776         }
5777 
5778         static if (LOGSEMANTIC)
5779         {
5780             printf("IsExp::semantic(%s)\n", e.toChars());
5781         }
5782         if (e.id && !(sc.flags & SCOPE.condition))
5783         {
5784             e.error("can only declare type aliases within `static if` conditionals or `static assert`s");
5785             return setError();
5786         }
5787 
5788         if (e.tok2 == TOK.package_ || e.tok2 == TOK.module_) // These is() expressions are special because they can work on modules, not just types.
5789         {
5790             const oldErrors = global.startGagging();
5791             Dsymbol sym = e.targ.toDsymbol(sc);
5792             global.endGagging(oldErrors);
5793 
5794             if (sym is null)
5795                 return no();
5796             Package p = resolveIsPackage(sym);
5797             if (p is null)
5798                 return no();
5799             if (e.tok2 == TOK.package_ && p.isModule()) // Note that isModule() will return null for package modules because they're not actually instances of Module.
5800                 return no();
5801             else if(e.tok2 == TOK.module_ && !(p.isModule() || p.isPackageMod()))
5802                 return no();
5803             tded = e.targ;
5804             return yes();
5805         }
5806 
5807         {
5808             Scope* sc2 = sc.copy(); // keep sc.flags
5809             sc2.tinst = null;
5810             sc2.minst = null;
5811             sc2.flags |= SCOPE.fullinst;
5812             Type t = e.targ.trySemantic(e.loc, sc2);
5813             sc2.pop();
5814             if (!t) // errors, so condition is false
5815                 return no();
5816             e.targ = t;
5817         }
5818 
5819         if (e.tok2 != TOK.reserved)
5820         {
5821             switch (e.tok2)
5822             {
5823             case TOK.struct_:
5824                 if (e.targ.ty != Tstruct)
5825                     return no();
5826                 if ((cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5827                     return no();
5828                 tded = e.targ;
5829                 break;
5830 
5831             case TOK.union_:
5832                 if (e.targ.ty != Tstruct)
5833                     return no();
5834                 if (!(cast(TypeStruct)e.targ).sym.isUnionDeclaration())
5835                     return no();
5836                 tded = e.targ;
5837                 break;
5838 
5839             case TOK.class_:
5840                 if (e.targ.ty != Tclass)
5841                     return no();
5842                 if ((cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5843                     return no();
5844                 tded = e.targ;
5845                 break;
5846 
5847             case TOK.interface_:
5848                 if (e.targ.ty != Tclass)
5849                     return no();
5850                 if (!(cast(TypeClass)e.targ).sym.isInterfaceDeclaration())
5851                     return no();
5852                 tded = e.targ;
5853                 break;
5854 
5855             case TOK.const_:
5856                 if (!e.targ.isConst())
5857                     return no();
5858                 tded = e.targ;
5859                 break;
5860 
5861             case TOK.immutable_:
5862                 if (!e.targ.isImmutable())
5863                     return no();
5864                 tded = e.targ;
5865                 break;
5866 
5867             case TOK.shared_:
5868                 if (!e.targ.isShared())
5869                     return no();
5870                 tded = e.targ;
5871                 break;
5872 
5873             case TOK.inout_:
5874                 if (!e.targ.isWild())
5875                     return no();
5876                 tded = e.targ;
5877                 break;
5878 
5879             case TOK.super_:
5880                 // If class or interface, get the base class and interfaces
5881                 if (e.targ.ty != Tclass)
5882                     return no();
5883                 else
5884                 {
5885                     ClassDeclaration cd = (cast(TypeClass)e.targ).sym;
5886                     auto args = new Parameters();
5887                     args.reserve(cd.baseclasses.length);
5888                     if (cd.semanticRun < PASS.semanticdone)
5889                         cd.dsymbolSemantic(null);
5890                     for (size_t i = 0; i < cd.baseclasses.length; i++)
5891                     {
5892                         BaseClass* b = (*cd.baseclasses)[i];
5893                         args.push(new Parameter(STC.in_, b.type, null, null, null));
5894                     }
5895                     tded = new TypeTuple(args);
5896                 }
5897                 break;
5898 
5899             case TOK.enum_:
5900                 if (e.targ.ty != Tenum)
5901                     return no();
5902                 if (e.id)
5903                     tded = (cast(TypeEnum)e.targ).sym.getMemtype(e.loc);
5904                 else
5905                     tded = e.targ;
5906 
5907                 if (tded.ty == Terror)
5908                     return setError();
5909                 break;
5910 
5911             case TOK.delegate_:
5912                 if (e.targ.ty != Tdelegate)
5913                     return no();
5914                 tded = (cast(TypeDelegate)e.targ).next; // the underlying function type
5915                 break;
5916 
5917             case TOK.function_:
5918             case TOK.parameters:
5919                 {
5920                     if (e.targ.ty != Tfunction)
5921                         return no();
5922                     tded = e.targ;
5923 
5924                     /* Generate tuple from function parameter types.
5925                      */
5926                     assert(tded.ty == Tfunction);
5927                     auto tdedf = tded.isTypeFunction();
5928                     auto args = new Parameters();
5929                     foreach (i, arg; tdedf.parameterList)
5930                     {
5931                         assert(arg && arg.type);
5932                         /* If one of the default arguments was an error,
5933                            don't return an invalid tuple
5934                          */
5935                         if (e.tok2 == TOK.parameters && arg.defaultArg && arg.defaultArg.op == EXP.error)
5936                             return setError();
5937                         args.push(new Parameter(arg.storageClass, arg.type, (e.tok2 == TOK.parameters) ? arg.ident : null, (e.tok2 == TOK.parameters) ? arg.defaultArg : null, arg.userAttribDecl));
5938                     }
5939                     tded = new TypeTuple(args);
5940                     break;
5941                 }
5942             case TOK.return_:
5943                 /* Get the 'return type' for the function,
5944                  * delegate, or pointer to function.
5945                  */
5946                 if (auto tf = e.targ.isFunction_Delegate_PtrToFunction())
5947                     tded = tf.next;
5948                 else
5949                     return no();
5950                 break;
5951 
5952             case TOK.argumentTypes:
5953                 /* Generate a type tuple of the equivalent types used to determine if a
5954                  * function argument of this type can be passed in registers.
5955                  * The results of this are highly platform dependent, and intended
5956                  * primarly for use in implementing va_arg().
5957                  */
5958                 tded = target.toArgTypes(e.targ);
5959                 if (!tded)
5960                     return no();
5961                 // not valid for a parameter
5962                 break;
5963 
5964             case TOK.vector:
5965                 if (e.targ.ty != Tvector)
5966                     return no();
5967                 tded = (cast(TypeVector)e.targ).basetype;
5968                 break;
5969 
5970             default:
5971                 assert(0);
5972             }
5973 
5974             // https://issues.dlang.org/show_bug.cgi?id=18753
5975             if (tded)
5976                 return yes();
5977             return no();
5978         }
5979         else if (e.tspec && !e.id && !(e.parameters && e.parameters.length))
5980         {
5981             /* Evaluate to true if targ matches tspec
5982              * is(targ == tspec)
5983              * is(targ : tspec)
5984              */
5985             e.tspec = e.tspec.typeSemantic(e.loc, sc);
5986             //printf("targ  = %s, %s\n", e.targ.toChars(), e.targ.deco);
5987             //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
5988 
5989             if (e.tok == TOK.colon)
5990             {
5991                 // current scope is itself deprecated, or deprecations are not errors
5992                 const bool deprecationAllowed = sc.isDeprecated
5993                     || global.params.useDeprecated != DiagnosticReporting.error;
5994                 const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
5995 
5996                 if (preventAliasThis && e.targ.ty == Tstruct)
5997                 {
5998                     if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
5999                         return yes();
6000                     else
6001                         return no();
6002                 }
6003                 else if (preventAliasThis && e.targ.ty == Tclass)
6004                 {
6005                     if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
6006                         return yes();
6007                     else
6008                         return no();
6009                 }
6010                 else if (e.targ.implicitConvTo(e.tspec))
6011                     return yes();
6012                 else
6013                     return no();
6014             }
6015             else /* == */
6016             {
6017                 if (e.targ.equals(e.tspec))
6018                     return yes();
6019                 else
6020                     return no();
6021             }
6022         }
6023         else if (e.tspec)
6024         {
6025             /* Evaluate to true if targ matches tspec.
6026              * If true, declare id as an alias for the specialized type.
6027              * is(targ == tspec, tpl)
6028              * is(targ : tspec, tpl)
6029              * is(targ id == tspec)
6030              * is(targ id : tspec)
6031              * is(targ id == tspec, tpl)
6032              * is(targ id : tspec, tpl)
6033              */
6034             Identifier tid = e.id ? e.id : Identifier.generateId("__isexp_id");
6035             e.parameters.insert(0, new TemplateTypeParameter(e.loc, tid, null, null));
6036 
6037             Objects dedtypes = Objects(e.parameters.length);
6038             dedtypes.zero();
6039 
6040             MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
6041 
6042             if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
6043             {
6044                 return no();
6045             }
6046             else
6047             {
6048                 tded = cast(Type)dedtypes[0];
6049                 if (!tded)
6050                     tded = e.targ;
6051                 Objects tiargs = Objects(1);
6052                 tiargs[0] = e.targ;
6053 
6054                 /* Declare trailing parameters
6055                  */
6056                 for (size_t i = 1; i < e.parameters.length; i++)
6057                 {
6058                     TemplateParameter tp = (*e.parameters)[i];
6059                     Declaration s = null;
6060 
6061                     m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
6062                     if (m == MATCH.nomatch)
6063                         return no();
6064                     s.dsymbolSemantic(sc);
6065                     if (!sc.insert(s))
6066                     {
6067                         auto conflict = sc.search(Loc.initial, s.ident, null);
6068                         e.error("declaration `%s` is already defined", s.toPrettyChars());
6069                         errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
6070                                           conflict.kind(), conflict.toChars());
6071                     }
6072 
6073                     unSpeculative(sc, s);
6074                 }
6075                 return yes();
6076             }
6077         }
6078         else if (e.id)
6079         {
6080             /* Declare id as an alias for type targ. Evaluate to true
6081              * is(targ id)
6082              */
6083             tded = e.targ;
6084         }
6085         return yes();
6086     }
6087 
6088     override void visit(BinAssignExp exp)
6089     {
6090         if (exp.type)
6091         {
6092             result = exp;
6093             return;
6094         }
6095 
6096         Expression e = exp.op_overload(sc);
6097         if (e)
6098         {
6099             result = e;
6100             return;
6101         }
6102 
6103         if (exp.e1.op == EXP.arrayLength)
6104         {
6105             // arr.length op= e2;
6106             e = rewriteOpAssign(exp);
6107             e = e.expressionSemantic(sc);
6108             result = e;
6109             return;
6110         }
6111         if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
6112         {
6113             if (checkNonAssignmentArrayOp(exp.e1))
6114                 return setError();
6115 
6116             if (exp.e1.op == EXP.slice)
6117                 (cast(SliceExp)exp.e1).arrayop = true;
6118 
6119             // T[] op= ...
6120             if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
6121             {
6122                 // T[] op= T
6123                 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
6124             }
6125             else if (Expression ex = typeCombine(exp, sc))
6126             {
6127                 result = ex;
6128                 return;
6129             }
6130             exp.type = exp.e1.type;
6131             result = arrayOp(exp, sc);
6132             return;
6133         }
6134 
6135         exp.e1 = exp.e1.expressionSemantic(sc);
6136         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
6137         exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
6138         exp.type = exp.e1.type;
6139 
6140         if (auto ad = isAggregate(exp.e1.type))
6141         {
6142             if (const s = search_function(ad, Id.opOpAssign))
6143             {
6144                 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());
6145                 return setError();
6146             }
6147         }
6148         if (exp.e1.checkScalar() ||
6149             exp.e1.checkReadModifyWrite(exp.op, exp.e2) ||
6150             exp.e1.checkSharedAccess(sc))
6151             return setError();
6152 
6153         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);
6154         int bitwise = (exp.op == EXP.andAssign || exp.op == EXP.orAssign || exp.op == EXP.xorAssign);
6155         int shift = (exp.op == EXP.leftShiftAssign || exp.op == EXP.rightShiftAssign || exp.op == EXP.unsignedRightShiftAssign);
6156 
6157         if (bitwise && exp.type.toBasetype().ty == Tbool)
6158             exp.e2 = exp.e2.implicitCastTo(sc, exp.type);
6159         else if (exp.checkNoBool())
6160             return setError();
6161 
6162         if ((exp.op == EXP.addAssign || exp.op == EXP.minAssign) && exp.e1.type.toBasetype().ty == Tpointer && exp.e2.type.toBasetype().isintegral())
6163         {
6164             result = scaleFactor(exp, sc);
6165             return;
6166         }
6167 
6168         if (Expression ex = typeCombine(exp, sc))
6169         {
6170             result = ex;
6171             return;
6172         }
6173 
6174         if (arith && (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc)))
6175             return setError();
6176         if ((bitwise || shift) && (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc)))
6177             return setError();
6178 
6179         if (shift)
6180         {
6181             if (exp.e2.type.toBasetype().ty != Tvector)
6182                 exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
6183         }
6184 
6185         if (!target.isVectorOpSupported(exp.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
6186         {
6187             result = exp.incompatibleTypes();
6188             return;
6189         }
6190 
6191         if (exp.e1.op == EXP.error || exp.e2.op == EXP.error)
6192             return setError();
6193 
6194         e = exp.checkOpAssignTypes(sc);
6195         if (e.op == EXP.error)
6196         {
6197             result = e;
6198             return;
6199         }
6200 
6201         assert(e.op == EXP.assign || e == exp);
6202         result = (cast(BinExp)e).reorderSettingAAElem(sc);
6203     }
6204 
6205     private Expression compileIt(MixinExp exp)
6206     {
6207         OutBuffer buf;
6208         if (expressionsToString(buf, sc, exp.exps))
6209             return null;
6210 
6211         uint errors = global.errors;
6212         const len = buf.length;
6213         const str = buf.extractChars()[0 .. len];
6214         const bool doUnittests = global.params.useUnitTests || global.params.ddoc.doOutput || global.params.dihdr.doOutput;
6215         auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
6216         scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
6217         p.transitionIn = global.params.vin;
6218         p.nextToken();
6219         //printf("p.loc.linnum = %d\n", p.loc.linnum);
6220 
6221         Expression e = p.parseExpression();
6222         if (global.errors != errors)
6223             return null;
6224 
6225         if (p.token.value != TOK.endOfFile)
6226         {
6227             exp.error("incomplete mixin expression `%s`", str.ptr);
6228             return null;
6229         }
6230         return e;
6231     }
6232 
6233     override void visit(MixinExp exp)
6234     {
6235         /* https://dlang.org/spec/expression.html#mixin_expressions
6236          */
6237 
6238         static if (LOGSEMANTIC)
6239         {
6240             printf("MixinExp::semantic('%s')\n", exp.toChars());
6241         }
6242 
6243         auto e = compileIt(exp);
6244         if (!e)
6245             return setError();
6246         result = e.expressionSemantic(sc);
6247     }
6248 
6249     override void visit(ImportExp e)
6250     {
6251         static if (LOGSEMANTIC)
6252         {
6253             printf("ImportExp::semantic('%s')\n", e.toChars());
6254         }
6255 
6256         auto se = semanticString(sc, e.e1, "file name argument");
6257         if (!se)
6258             return setError();
6259         se = se.toUTF8(sc);
6260 
6261         auto namez = se.toStringz();
6262         if (!global.filePath)
6263         {
6264             e.error("need `-J` switch to import text file `%s`", namez.ptr);
6265             return setError();
6266         }
6267 
6268         /* Be wary of CWE-22: Improper Limitation of a Pathname to a Restricted Directory
6269          * ('Path Traversal') attacks.
6270          * https://cwe.mitre.org/data/definitions/22.html
6271          */
6272 
6273         if (FileName.absolute(namez))
6274         {
6275             e.error("absolute path is not allowed in import expression: `%s`", se.toChars());
6276             return setError();
6277         }
6278 
6279         auto idxReserved = FileName.findReservedChar(namez);
6280         if (idxReserved != size_t.max)
6281         {
6282             e.error("`%s` is not a valid filename on this platform", se.toChars());
6283             e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
6284             return setError();
6285         }
6286 
6287         if (FileName.refersToParentDir(namez))
6288         {
6289             e.error("path refers to parent (`..`) directory: `%s`", se.toChars());
6290             return setError();
6291         }
6292 
6293         auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
6294         if (!resolvedNamez)
6295         {
6296             e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
6297             e.errorSupplemental("Path(s) searched (as provided by `-J`):");
6298             foreach (idx, path; *global.filePath)
6299             {
6300                 const attr = FileName.exists(path);
6301                 const(char)* err = attr == 2 ? "" :
6302                     (attr == 1 ? " (not a directory)" : " (path not found)");
6303                 e.errorSupplemental("[%llu]: `%s`%s", cast(ulong)idx, path, err);
6304             }
6305             return setError();
6306         }
6307 
6308         sc._module.contentImportedFiles.push(resolvedNamez.ptr);
6309         if (global.params.verbose)
6310         {
6311             const slice = se.peekString();
6312             message("file      %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
6313         }
6314         if (global.params.moduleDeps.buffer !is null)
6315         {
6316             OutBuffer* ob = global.params.moduleDeps.buffer;
6317             Module imod = sc._module;
6318 
6319             if (!global.params.moduleDeps.name)
6320                 ob.writestring("depsFile ");
6321             ob.writestring(imod.toPrettyChars());
6322             ob.writestring(" (");
6323             escapePath(ob, imod.srcfile.toChars());
6324             ob.writestring(") : ");
6325             if (global.params.moduleDeps.name)
6326                 ob.writestring("string : ");
6327             ob.write(se.peekString());
6328             ob.writestring(" (");
6329             escapePath(ob, resolvedNamez.ptr);
6330             ob.writestring(")");
6331             ob.writenl();
6332         }
6333         if (global.params.makeDeps.doOutput)
6334         {
6335             global.params.makeDeps.files.push(resolvedNamez.ptr);
6336         }
6337 
6338         {
6339             auto fileName = FileName(resolvedNamez);
6340             if (auto fmResult = global.fileManager.lookup(fileName))
6341             {
6342                 se = new StringExp(e.loc, fmResult);
6343             }
6344             else
6345             {
6346                 e.error("cannot read file `%s`", resolvedNamez.ptr);
6347                 return setError();
6348             }
6349         }
6350         result = se.expressionSemantic(sc);
6351     }
6352 
6353     override void visit(AssertExp exp)
6354     {
6355         // https://dlang.org/spec/expression.html#assert_expressions
6356         static if (LOGSEMANTIC)
6357         {
6358             printf("AssertExp::semantic('%s')\n", exp.toChars());
6359         }
6360 
6361         const generateMsg = !exp.msg &&
6362                             sc.needsCodegen() && // let ctfe interpreter handle the error message
6363                             global.params.checkAction == CHECKACTION.context &&
6364                             global.params.useAssert == CHECKENABLE.on;
6365         Expression temporariesPrefix;
6366 
6367         if (generateMsg)
6368         // no message - use assert expression as msg
6369         {
6370             if (!verifyHookExist(exp.loc, *sc, Id._d_assert_fail, "generating assert messages"))
6371                 return setError();
6372 
6373             /*
6374             {
6375               auto a = e1, b = e2;
6376               assert(a == b, _d_assert_fail!"=="(a, b));
6377             }()
6378             */
6379 
6380             /*
6381             Stores the result of an operand expression into a temporary
6382             if necessary, e.g. if it is an impure fuction call containing side
6383             effects as in https://issues.dlang.org/show_bug.cgi?id=20114
6384 
6385             Params:
6386                 op = an expression which may require a temporary (added to
6387                      `temporariesPrefix`: `auto tmp = op`) and will be replaced
6388                      by `tmp` if necessary
6389 
6390             Returns: (possibly replaced) `op`
6391             */
6392             Expression maybePromoteToTmp(ref Expression op)
6393             {
6394                 // https://issues.dlang.org/show_bug.cgi?id=20989
6395                 // Flag that _d_assert_fail will never dereference `array.ptr` to avoid safety
6396                 // errors for `assert(!array.ptr)` => `_d_assert_fail!"!"(array.ptr)`
6397                 {
6398                     auto die = op.isDotIdExp();
6399                     if (die && die.ident == Id.ptr)
6400                         die.noderef = true;
6401                 }
6402 
6403                 op = op.expressionSemantic(sc);
6404                 op = resolveProperties(sc, op);
6405 
6406                 // Detect assert's using static operator overloads (e.g. `"var" in environment`)
6407                 if (auto te = op.isTypeExp())
6408                 {
6409                     // Replace the TypeExp with it's textual representation
6410                     // Including "..." in the error message isn't quite right but
6411                     // proper solutions require more drastic changes, e.g. directly
6412                     // using miniFormat and combine instead of calling _d_assert_fail
6413                     auto name = new StringExp(te.loc, te.toString());
6414                     return name.expressionSemantic(sc);
6415                 }
6416 
6417                 // Create a temporary for expressions with side effects
6418                 // Defensively assume that function calls may have side effects even
6419                 // though it's not detected by hasSideEffect (e.g. `debug puts("Hello")` )
6420                 // Rewriting CallExp's also avoids some issues with the inliner/debug generation
6421                 if (op.hasSideEffect(true))
6422                 {
6423                     // Don't create an invalid temporary for void-expressions
6424                     // Further semantic will issue an appropriate error
6425                     if (op.type.ty == Tvoid)
6426                         return op;
6427 
6428                     // https://issues.dlang.org/show_bug.cgi?id=21590
6429                     // Don't create unnecessary temporaries and detect `assert(a = b)`
6430                     if (op.isAssignExp() || op.isBinAssignExp())
6431                     {
6432                         auto left = (cast(BinExp) op).e1;
6433 
6434                         // Find leftmost expression to handle other rewrites,
6435                         // e.g. --(++a) => a += 1 -= 1
6436                         while (left.isAssignExp() || left.isBinAssignExp())
6437                             left = (cast(BinExp) left).e1;
6438 
6439                         // Only use the assignee if it's a variable and skip
6440                         // other lvalues (e.g. ref's returned by functions)
6441                         if (left.isVarExp())
6442                             return left;
6443 
6444                         // Sanity check that `op` can be converted to boolean
6445                         // But don't raise errors for assignments enclosed in another expression
6446                         if (op is exp.e1)
6447                             op.toBoolean(sc);
6448                     }
6449 
6450                     // Tuples with side-effects already receive a temporary during semantic
6451                     if (op.type.isTypeTuple())
6452                     {
6453                         auto te = op.isTupleExp();
6454                         assert(te);
6455 
6456                         // Create a new tuple without the associated temporary
6457                         auto res = new TupleExp(op.loc, te.exps);
6458                         return res.expressionSemantic(sc);
6459                     }
6460 
6461                     const stc = op.isLvalue() ? STC.ref_ : 0;
6462                     auto tmp = copyToTemp(stc, "__assertOp", op);
6463                     tmp.dsymbolSemantic(sc);
6464 
6465                     auto decl = new DeclarationExp(op.loc, tmp);
6466                     temporariesPrefix = Expression.combine(temporariesPrefix, decl);
6467 
6468                     op = new VarExp(op.loc, tmp);
6469                     op = op.expressionSemantic(sc);
6470                 }
6471                 return op;
6472             }
6473 
6474             // if the assert condition is a mixin expression, try to compile it
6475             if (auto ce = exp.e1.isMixinExp())
6476             {
6477                 if (auto e1 = compileIt(ce))
6478                     exp.e1 = e1;
6479             }
6480 
6481             Expressions* es;
6482             Objects* tiargs;
6483             Loc loc = exp.e1.loc;
6484 
6485             const op = exp.e1.op;
6486             bool isEqualsCallExpression;
6487             if (const callExp = exp.e1.isCallExp())
6488             {
6489                 // https://issues.dlang.org/show_bug.cgi?id=20331
6490                 // callExp.f may be null if the assert contains a call to
6491                 // a function pointer or literal
6492                 if (const callExpFunc = callExp.f)
6493                 {
6494                     const callExpIdent = callExpFunc.ident;
6495                     isEqualsCallExpression = callExpIdent == Id.__equals ||
6496                                              callExpIdent == Id.eq;
6497                 }
6498             }
6499             if (op == EXP.equal || op == EXP.notEqual ||
6500                 op == EXP.lessThan || op == EXP.greaterThan ||
6501                 op == EXP.lessOrEqual || op == EXP.greaterOrEqual ||
6502                 op == EXP.identity || op == EXP.notIdentity ||
6503                 op == EXP.in_ ||
6504                 isEqualsCallExpression)
6505             {
6506                 es = new Expressions(3);
6507                 tiargs = new Objects(1);
6508 
6509                 if (isEqualsCallExpression)
6510                 {
6511                     auto callExp = cast(CallExp) exp.e1;
6512                     auto args = callExp.arguments;
6513 
6514                     // structs with opEquals get rewritten to a DotVarExp:
6515                     // a.opEquals(b)
6516                     // https://issues.dlang.org/show_bug.cgi?id=20100
6517                     if (args.length == 1)
6518                     {
6519                         auto dv = callExp.e1.isDotVarExp();
6520                         assert(dv);
6521 
6522                         // runtime args
6523                         (*es)[1] = maybePromoteToTmp(dv.e1);
6524                         (*es)[2] = maybePromoteToTmp((*args)[0]);
6525                     }
6526                     else
6527                     {
6528                         // runtime args
6529                         (*es)[1] = maybePromoteToTmp((*args)[0]);
6530                         (*es)[2] = maybePromoteToTmp((*args)[1]);
6531                     }
6532                 }
6533                 else
6534                 {
6535                     auto binExp = cast(EqualExp) exp.e1;
6536 
6537                     // runtime args
6538                     (*es)[1] = maybePromoteToTmp(binExp.e1);
6539                     (*es)[2] = maybePromoteToTmp(binExp.e2);
6540                 }
6541 
6542                 // template args
6543                 Expression comp = new StringExp(loc, isEqualsCallExpression ? "==" : EXPtoString(exp.e1.op));
6544                 comp = comp.expressionSemantic(sc);
6545                 (*es)[0] = comp;
6546                 (*tiargs)[0] = (*es)[1].type;
6547             }
6548 
6549             // Format exp.e1 before any additional boolean conversion
6550             // Ignore &&/|| because "assert(...) failed" is more informative than "false != true"
6551             else if (op != EXP.andAnd && op != EXP.orOr)
6552             {
6553                 es = new Expressions(2);
6554                 tiargs = new Objects(1);
6555 
6556                 if (auto ne = exp.e1.isNotExp())
6557                 {
6558                     // Fetch the (potential non-bool) expression and fold
6559                     // (n) negations into (n % 2) negations, e.g. !!a => a
6560                     for (bool neg = true; ; neg = !neg)
6561                     {
6562                         if (auto ne2 = ne.e1.isNotExp())
6563                             ne = ne2;
6564                         else
6565                         {
6566                             (*es)[0] = new StringExp(loc, neg ? "!" : "");
6567                             (*es)[1] = maybePromoteToTmp(ne.e1);
6568                             break;
6569                         }
6570                     }
6571                 }
6572                 else
6573                 {   // Simply format exp.e1
6574                     (*es)[0] = new StringExp(loc, "");
6575                     (*es)[1] = maybePromoteToTmp(exp.e1);
6576                 }
6577 
6578                 (*tiargs)[0] = (*es)[1].type;
6579 
6580                 // Passing __ctfe to auto ref infers ref and aborts compilation:
6581                 // "cannot modify compiler-generated variable __ctfe"
6582                 auto ve = (*es)[1].isVarExp();
6583                 if (ve && ve.var.ident == Id.ctfe)
6584                 {
6585                     exp.msg = new StringExp(loc, "assert(__ctfe) failed!");
6586                     goto LSkip;
6587                 }
6588             }
6589             else
6590             {
6591                 OutBuffer buf;
6592                 buf.printf("%s failed", exp.toChars());
6593                 exp.msg = new StringExp(Loc.initial, buf.extractSlice());
6594                 goto LSkip;
6595             }
6596 
6597             Expression __assertFail = new IdentifierExp(exp.loc, Id.empty);
6598             auto assertFail = new DotIdExp(loc, __assertFail, Id.object);
6599 
6600             auto dt = new DotTemplateInstanceExp(loc, assertFail, Id._d_assert_fail, tiargs);
6601             auto ec = CallExp.create(loc, dt, es);
6602             exp.msg = ec;
6603         }
6604 
6605         LSkip:
6606         if (Expression ex = unaSemantic(exp, sc))
6607         {
6608             result = ex;
6609             return;
6610         }
6611 
6612         exp.e1 = resolveProperties(sc, exp.e1);
6613         // BUG: see if we can do compile time elimination of the Assert
6614         exp.e1 = exp.e1.optimize(WANTvalue);
6615         exp.e1 = exp.e1.toBoolean(sc);
6616 
6617         if (exp.e1.op == EXP.error)
6618         {
6619             result = exp.e1;
6620             return;
6621         }
6622 
6623         if (exp.msg)
6624         {
6625             exp.msg = expressionSemantic(exp.msg, sc);
6626             exp.msg = resolveProperties(sc, exp.msg);
6627             exp.msg = exp.msg.implicitCastTo(sc, Type.tchar.constOf().arrayOf());
6628             exp.msg = exp.msg.optimize(WANTvalue);
6629             checkParamArgumentEscape(sc, null, null, null, STC.undefined_, exp.msg, true, false);
6630         }
6631 
6632         if (exp.msg && exp.msg.op == EXP.error)
6633         {
6634             result = exp.msg;
6635             return;
6636         }
6637 
6638         auto f1 = checkNonAssignmentArrayOp(exp.e1);
6639         auto f2 = exp.msg && checkNonAssignmentArrayOp(exp.msg);
6640         if (f1 || f2)
6641             return setError();
6642 
6643         if (exp.e1.toBool().hasValue(false))
6644         {
6645             /* This is an `assert(0)` which means halt program execution
6646              */
6647             FuncDeclaration fd = sc.parent.isFuncDeclaration();
6648             if (fd)
6649                 fd.hasReturnExp |= 4;
6650             sc.ctorflow.orCSX(CSX.halt);
6651 
6652             if (global.params.useAssert == CHECKENABLE.off)
6653             {
6654                 Expression e = new HaltExp(exp.loc);
6655                 e = e.expressionSemantic(sc);
6656                 result = e;
6657                 return;
6658             }
6659 
6660             // Only override the type when it isn't already some flavour of noreturn,
6661             // e.g. when this assert was generated by defaultInitLiteral
6662             if (!exp.type || !exp.type.isTypeNoreturn())
6663                 exp.type = Type.tnoreturn;
6664         }
6665         else
6666             exp.type = Type.tvoid;
6667 
6668         result = !temporariesPrefix
6669             ? exp
6670             : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc);
6671     }
6672 
6673     override void visit(ThrowExp te)
6674     {
6675         import dmd.statementsem;
6676 
6677         if (throwSemantic(te.loc, te.e1, sc))
6678             result = te;
6679         else
6680             setError();
6681     }
6682 
6683     override void visit(DotIdExp exp)
6684     {
6685         static if (LOGSEMANTIC)
6686         {
6687             printf("DotIdExp::semantic(this = %p, '%s')\n", exp, exp.toChars());
6688             //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
6689         }
6690 
6691         if (sc.flags & SCOPE.Cfile)
6692         {
6693             /* See if need to rewrite the AST because of cast/call ambiguity
6694              */
6695             if (auto e = castCallAmbiguity(exp, sc))
6696             {
6697                 result = expressionSemantic(e, sc);
6698                 return;
6699             }
6700 
6701             if (exp.arrow) // ImportC only
6702                 exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
6703 
6704             if (exp.ident == Id.__xalignof && exp.e1.isTypeExp())
6705             {
6706                 // C11 6.5.3 says _Alignof only applies to types
6707                 Expression e;
6708                 Type t;
6709                 Dsymbol s;
6710                 dmd.typesem.resolve(exp.e1.type, exp.e1.loc, sc, e, t, s, true);
6711                 if (e)
6712                 {
6713                     exp.e1.error("argument to `_Alignof` must be a type");
6714                     return setError();
6715                 }
6716                 else if (t)
6717                 {
6718                     // Note similarity to getProperty() implementation of __xalignof
6719                     const explicitAlignment = t.alignment();
6720                     const naturalAlignment = t.alignsize();
6721                     const actualAlignment = (explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get());
6722                     result = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
6723                 }
6724                 else if (s)
6725                 {
6726                     exp.e1.error("argument to `_Alignof` must be a type");
6727                     return setError();
6728                 }
6729                 else
6730                     assert(0);
6731                 return;
6732             }
6733 
6734             if (exp.ident != Id.__sizeof)
6735             {
6736                 result = fieldLookup(exp.e1, sc, exp.ident);
6737                 return;
6738             }
6739         }
6740 
6741         Expression e = exp.dotIdSemanticProp(sc, 1);
6742 
6743         if (e && isDotOpDispatch(e))
6744         {
6745             auto ode = e;
6746             uint errors = global.startGagging();
6747             e = resolvePropertiesX(sc, e);
6748             // Any error or if 'e' is not resolved, go to UFCS
6749             if (global.endGagging(errors) || e is ode)
6750                 e = null; /* fall down to UFCS */
6751             else
6752             {
6753                 result = e;
6754                 return;
6755             }
6756         }
6757         if (!e) // if failed to find the property
6758         {
6759             /* If ident is not a valid property, rewrite:
6760              *   e1.ident
6761              * as:
6762              *   .ident(e1)
6763              */
6764             e = resolveUFCSProperties(sc, exp);
6765         }
6766         result = e;
6767     }
6768 
6769     override void visit(DotTemplateExp e)
6770     {
6771         if (e.type)
6772         {
6773             result = e;
6774             return;
6775         }
6776         if (Expression ex = unaSemantic(e, sc))
6777         {
6778             result = ex;
6779             return;
6780         }
6781         // 'void' like TemplateExp
6782         e.type = Type.tvoid;
6783         result = e;
6784     }
6785 
6786     override void visit(DotVarExp exp)
6787     {
6788         static if (LOGSEMANTIC)
6789         {
6790             printf("DotVarExp::semantic('%s')\n", exp.toChars());
6791         }
6792         if (exp.type)
6793         {
6794             result = exp;
6795             return;
6796         }
6797 
6798         exp.var = exp.var.toAlias().isDeclaration();
6799 
6800         exp.e1 = exp.e1.expressionSemantic(sc);
6801 
6802         if (auto tup = exp.var.isTupleDeclaration())
6803         {
6804             /* Replace:
6805              *  e1.tuple(a, b, c)
6806              * with:
6807              *  tuple(e1.a, e1.b, e1.c)
6808              */
6809             Expression e0;
6810             Expression ev = sc.func ? extractSideEffect(sc, "__tup", e0, exp.e1) : exp.e1;
6811 
6812             auto exps = new Expressions();
6813             exps.reserve(tup.objects.length);
6814             for (size_t i = 0; i < tup.objects.length; i++)
6815             {
6816                 RootObject o = (*tup.objects)[i];
6817                 Expression e;
6818                 Declaration var;
6819                 switch (o.dyncast()) with (DYNCAST)
6820                 {
6821                 case expression:
6822                     e = cast(Expression)o;
6823                     if (auto se = e.isDsymbolExp())
6824                         var = se.s.isDeclaration();
6825                     else if (auto ve = e.isVarExp())
6826                         if (!ve.var.isFuncDeclaration())
6827                             // Exempt functions for backwards compatibility reasons.
6828                             // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6829                             var = ve.var;
6830                     break;
6831                 case dsymbol:
6832                     Dsymbol s = cast(Dsymbol) o;
6833                     Declaration d = s.isDeclaration();
6834                     if (!d || d.isFuncDeclaration())
6835                         // Exempt functions for backwards compatibility reasons.
6836                         // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
6837                         e = new DsymbolExp(exp.loc, s);
6838                     else
6839                         var = d;
6840                     break;
6841                 case type:
6842                     e = new TypeExp(exp.loc, cast(Type)o);
6843                     break;
6844                 default:
6845                     exp.error("`%s` is not an expression", o.toChars());
6846                     return setError();
6847                 }
6848                 if (var)
6849                     e = new DotVarExp(exp.loc, ev, var);
6850                 exps.push(e);
6851             }
6852 
6853             Expression e = new TupleExp(exp.loc, e0, exps);
6854             e = e.expressionSemantic(sc);
6855             result = e;
6856             return;
6857         }
6858         else if (auto ad = exp.var.isAliasDeclaration())
6859         {
6860             if (auto t = ad.getType())
6861             {
6862                 result = new TypeExp(exp.loc, t).expressionSemantic(sc);
6863                 return;
6864             }
6865         }
6866 
6867         exp.e1 = exp.e1.addDtorHook(sc);
6868 
6869         Type t1 = exp.e1.type;
6870 
6871         if (FuncDeclaration fd = exp.var.isFuncDeclaration())
6872         {
6873             // for functions, do checks after overload resolution
6874             if (!fd.functionSemantic())
6875                 return setError();
6876 
6877             /* https://issues.dlang.org/show_bug.cgi?id=13843
6878              * If fd obviously has no overloads, we should
6879              * normalize AST, and it will give a chance to wrap fd with FuncExp.
6880              */
6881             if ((fd.isNested() && !fd.isThis()) || fd.isFuncLiteralDeclaration())
6882             {
6883                 // (e1, fd)
6884                 auto e = symbolToExp(fd, exp.loc, sc, false);
6885                 result = Expression.combine(exp.e1, e);
6886                 return;
6887             }
6888 
6889             exp.type = fd.type;
6890             assert(exp.type);
6891         }
6892         else if (OverDeclaration od = exp.var.isOverDeclaration())
6893         {
6894             exp.type = Type.tvoid; // ambiguous type?
6895         }
6896         else
6897         {
6898             exp.type = exp.var.type;
6899             if (!exp.type && global.errors) // var is goofed up, just return error.
6900                 return setError();
6901             assert(exp.type);
6902 
6903             if (t1.ty == Tpointer)
6904                 t1 = t1.nextOf();
6905 
6906             exp.type = exp.type.addMod(t1.mod);
6907 
6908             // https://issues.dlang.org/show_bug.cgi?id=23109
6909             // Run semantic on the DotVarExp type
6910             if (auto handle = exp.type.isClassHandle())
6911             {
6912                 if (handle.semanticRun < PASS.semanticdone && !handle.isBaseInfoComplete())
6913                     handle.dsymbolSemantic(null);
6914             }
6915 
6916             Dsymbol vparent = exp.var.toParent();
6917             AggregateDeclaration ad = vparent ? vparent.isAggregateDeclaration() : null;
6918             if (Expression e1x = getRightThis(exp.loc, sc, ad, exp.e1, exp.var, 1))
6919                 exp.e1 = e1x;
6920             else
6921             {
6922                 /* Later checkRightThis will report correct error for invalid field variable access.
6923                  */
6924                 Expression e = new VarExp(exp.loc, exp.var);
6925                 e = e.expressionSemantic(sc);
6926                 result = e;
6927                 return;
6928             }
6929             checkAccess(exp.loc, sc, exp.e1, exp.var);
6930 
6931             VarDeclaration v = exp.var.isVarDeclaration();
6932             if (v && (v.isDataseg() || (v.storage_class & STC.manifest)))
6933             {
6934                 Expression e = expandVar(WANTvalue, v);
6935                 if (e)
6936                 {
6937                     result = e;
6938                     return;
6939                 }
6940             }
6941 
6942             if (v && (v.isDataseg() || // fix https://issues.dlang.org/show_bug.cgi?id=8238
6943                       (!v.needThis() && v.semanticRun > PASS.initial)))  // fix https://issues.dlang.org/show_bug.cgi?id=17258
6944             {
6945                 // (e1, v)
6946                 checkAccess(exp.loc, sc, exp.e1, v);
6947                 Expression e = new VarExp(exp.loc, v);
6948                 e = new CommaExp(exp.loc, exp.e1, e);
6949                 e = e.expressionSemantic(sc);
6950                 result = e;
6951                 return;
6952             }
6953         }
6954         //printf("-DotVarExp::semantic('%s')\n", toChars());
6955         result = exp;
6956     }
6957 
6958     override void visit(DotTemplateInstanceExp exp)
6959     {
6960         static if (LOGSEMANTIC)
6961         {
6962             printf("DotTemplateInstanceExp::semantic('%s')\n", exp.toChars());
6963         }
6964         if (exp.type)
6965         {
6966             result = exp;
6967             return;
6968         }
6969         // Indicate we need to resolve by UFCS.
6970         Expression e = exp.dotTemplateSemanticProp(sc, DotExpFlag.gag);
6971         if (!e)
6972             e = resolveUFCSProperties(sc, exp);
6973         if (e is exp)
6974             e.type = Type.tvoid; // Unresolved type, because it needs inference
6975         result = e;
6976     }
6977 
6978     override void visit(DelegateExp e)
6979     {
6980         static if (LOGSEMANTIC)
6981         {
6982             printf("DelegateExp::semantic('%s')\n", e.toChars());
6983         }
6984         if (e.type)
6985         {
6986             result = e;
6987             return;
6988         }
6989 
6990         e.e1 = e.e1.expressionSemantic(sc);
6991 
6992         e.type = new TypeDelegate(e.func.type.isTypeFunction());
6993         e.type = e.type.typeSemantic(e.loc, sc);
6994 
6995         FuncDeclaration f = e.func.toAliasFunc();
6996         AggregateDeclaration ad = f.isMemberLocal();
6997         if (f.needThis())
6998             e.e1 = getRightThis(e.loc, sc, ad, e.e1, f);
6999 
7000         if (f.type.ty == Tfunction)
7001         {
7002             TypeFunction tf = cast(TypeFunction)f.type;
7003             if (!MODmethodConv(e.e1.type.mod, f.type.mod))
7004             {
7005                 OutBuffer thisBuf, funcBuf;
7006                 MODMatchToBuffer(&thisBuf, e.e1.type.mod, tf.mod);
7007                 MODMatchToBuffer(&funcBuf, tf.mod, e.e1.type.mod);
7008                 e.error("%smethod `%s` is not callable using a %s`%s`",
7009                     funcBuf.peekChars(), f.toPrettyChars(), thisBuf.peekChars(), e.e1.toChars());
7010                 return setError();
7011             }
7012         }
7013         if (ad && ad.isClassDeclaration() && ad.type != e.e1.type)
7014         {
7015             // A downcast is required for interfaces
7016             // https://issues.dlang.org/show_bug.cgi?id=3706
7017             e.e1 = new CastExp(e.loc, e.e1, ad.type);
7018             e.e1 = e.e1.expressionSemantic(sc);
7019         }
7020         result = e;
7021         // declare dual-context container
7022         if (f.hasDualContext() && !sc.intypeof && sc.func)
7023         {
7024             // check access to second `this`
7025             if (AggregateDeclaration ad2 = f.isMember2())
7026             {
7027                 Expression te = new ThisExp(e.loc).expressionSemantic(sc);
7028                 if (te.op != EXP.error)
7029                     te = getRightThis(e.loc, sc, ad2, te, f);
7030                 if (te.op == EXP.error)
7031                 {
7032                     e.error("need `this` of type `%s` to make delegate from function `%s`", ad2.toChars(), f.toChars());
7033                     return setError();
7034                 }
7035             }
7036             VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f);
7037             e.vthis2 = vthis2;
7038             Expression de = new DeclarationExp(e.loc, vthis2);
7039             result = Expression.combine(de, result);
7040             result = result.expressionSemantic(sc);
7041         }
7042     }
7043 
7044     override void visit(DotTypeExp exp)
7045     {
7046         static if (LOGSEMANTIC)
7047         {
7048             printf("DotTypeExp::semantic('%s')\n", exp.toChars());
7049         }
7050         if (exp.type)
7051         {
7052             result = exp;
7053             return;
7054         }
7055 
7056         if (auto e = unaSemantic(exp, sc))
7057         {
7058             result = e;
7059             return;
7060         }
7061 
7062         exp.type = exp.sym.getType().addMod(exp.e1.type.mod);
7063         result = exp;
7064     }
7065 
7066     override void visit(AddrExp exp)
7067     {
7068         static if (LOGSEMANTIC)
7069         {
7070             printf("AddrExp::semantic('%s')\n", exp.toChars());
7071         }
7072         if (exp.type)
7073         {
7074             result = exp;
7075             return;
7076         }
7077 
7078         if (Expression ex = unaSemantic(exp, sc))
7079         {
7080             result = ex;
7081             return;
7082         }
7083 
7084         if (sc.flags & SCOPE.Cfile)
7085         {
7086             /* Special handling for &"string"/&(T[]){0, 1}
7087              * since C regards string/array literals as lvalues
7088              */
7089             auto e = exp.e1;
7090             if(e.isStringExp() || e.isArrayLiteralExp())
7091             {
7092                 e.type = typeSemantic(e.type, Loc.initial, sc);
7093                 // if type is already a pointer exp is an illegal expression of the form `&(&"")`
7094                 if (!e.type.isTypePointer())
7095                 {
7096                     e.type = e.type.pointerTo();
7097                     result = e;
7098                     return;
7099                 }
7100                 else
7101                 {
7102                     // `toLvalue` call further below is upon exp.e1, omitting & from the error message
7103                     exp.toLvalue(sc, null);
7104                     return setError();
7105                 }
7106             }
7107         }
7108 
7109         int wasCond = exp.e1.op == EXP.question;
7110 
7111         if (exp.e1.op == EXP.dotTemplateInstance)
7112         {
7113             DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)exp.e1;
7114             TemplateInstance ti = dti.ti;
7115             {
7116                 //assert(ti.needsTypeInference(sc));
7117                 ti.dsymbolSemantic(sc);
7118                 if (!ti.inst || ti.errors) // if template failed to expand
7119                     return setError();
7120 
7121                 Dsymbol s = ti.toAlias();
7122                 FuncDeclaration f = s.isFuncDeclaration();
7123                 if (f)
7124                 {
7125                     exp.e1 = new DotVarExp(exp.e1.loc, dti.e1, f);
7126                     exp.e1 = exp.e1.expressionSemantic(sc);
7127                 }
7128             }
7129         }
7130         else if (exp.e1.op == EXP.scope_)
7131         {
7132             TemplateInstance ti = (cast(ScopeExp)exp.e1).sds.isTemplateInstance();
7133             if (ti)
7134             {
7135                 //assert(ti.needsTypeInference(sc));
7136                 ti.dsymbolSemantic(sc);
7137                 if (!ti.inst || ti.errors) // if template failed to expand
7138                     return setError();
7139 
7140                 Dsymbol s = ti.toAlias();
7141                 FuncDeclaration f = s.isFuncDeclaration();
7142                 if (f)
7143                 {
7144                     exp.e1 = new VarExp(exp.e1.loc, f);
7145                     exp.e1 = exp.e1.expressionSemantic(sc);
7146                 }
7147             }
7148         }
7149         /* https://issues.dlang.org/show_bug.cgi?id=809
7150          *
7151          * If the address of a lazy variable is taken,
7152          * the expression is rewritten so that the type
7153          * of it is the delegate type. This means that
7154          * the symbol is not going to represent a call
7155          * to the delegate anymore, but rather, the
7156          * actual symbol.
7157          */
7158         if (auto ve = exp.e1.isVarExp())
7159         {
7160             if (ve.var.storage_class & STC.lazy_)
7161             {
7162                 exp.e1 = exp.e1.expressionSemantic(sc);
7163                 exp.e1 = resolveProperties(sc, exp.e1);
7164                 if (auto callExp = exp.e1.isCallExp())
7165                 {
7166                     if (callExp.e1.type.toBasetype().ty == Tdelegate)
7167                     {
7168                         /* https://issues.dlang.org/show_bug.cgi?id=20551
7169                          *
7170                          * Cannot take address of lazy parameter in @safe code
7171                          * because it might end up being a pointer to undefined
7172                          * memory.
7173                          */
7174                         if (1)
7175                         {
7176                             if (sc.setUnsafe(false, exp.loc,
7177                                 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
7178                             {
7179                                 setError();
7180                                 return;
7181                             }
7182                         }
7183                         VarExp ve2 = callExp.e1.isVarExp();
7184                         ve2.delegateWasExtracted = true;
7185                         ve2.var.storage_class |= STC.scope_;
7186                         result = ve2;
7187                         return;
7188                     }
7189                 }
7190             }
7191         }
7192 
7193         exp.e1 = exp.e1.toLvalue(sc, null);
7194         if (exp.e1.op == EXP.error)
7195         {
7196             result = exp.e1;
7197             return;
7198         }
7199         if (checkNonAssignmentArrayOp(exp.e1))
7200             return setError();
7201 
7202         if (!exp.e1.type)
7203         {
7204             exp.error("cannot take address of `%s`", exp.e1.toChars());
7205             return setError();
7206         }
7207         if (!checkAddressable(exp, sc))
7208             return setError();
7209 
7210         bool hasOverloads;
7211         if (auto f = isFuncAddress(exp, &hasOverloads))
7212         {
7213             if (!hasOverloads && f.checkForwardRef(exp.loc))
7214                 return setError();
7215         }
7216         else if (!exp.e1.type.deco)
7217         {
7218             // try to resolve the type
7219             exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
7220             if (!exp.e1.type.deco)  // still couldn't resolve it
7221             {
7222                 if (auto ve = exp.e1.isVarExp())
7223                 {
7224                     Declaration d = ve.var;
7225                     exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
7226                 }
7227                 else
7228                     exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
7229                 return setError();
7230             }
7231         }
7232 
7233         exp.type = exp.e1.type.pointerTo();
7234 
7235         // See if this should really be a delegate
7236         if (exp.e1.op == EXP.dotVariable)
7237         {
7238             DotVarExp dve = cast(DotVarExp)exp.e1;
7239             FuncDeclaration f = dve.var.isFuncDeclaration();
7240             if (f)
7241             {
7242                 f = f.toAliasFunc(); // FIXME, should see overloads
7243                                      // https://issues.dlang.org/show_bug.cgi?id=1983
7244                 if (!dve.hasOverloads)
7245                     f.tookAddressOf++;
7246 
7247                 Expression e;
7248                 if (f.needThis())
7249                     e = new DelegateExp(exp.loc, dve.e1, f, dve.hasOverloads);
7250                 else // It is a function pointer. Convert &v.f() --> (v, &V.f())
7251                     e = new CommaExp(exp.loc, dve.e1, new AddrExp(exp.loc, new VarExp(exp.loc, f, dve.hasOverloads)));
7252                 e = e.expressionSemantic(sc);
7253                 result = e;
7254                 return;
7255             }
7256 
7257             // Look for misaligned pointer in @safe mode
7258             if (checkUnsafeAccess(sc, dve, !exp.type.isMutable(), true))
7259                 return setError();
7260         }
7261         else if (exp.e1.op == EXP.variable)
7262         {
7263             VarExp ve = cast(VarExp)exp.e1;
7264             VarDeclaration v = ve.var.isVarDeclaration();
7265             if (v)
7266             {
7267                 if (!checkAddressVar(sc, exp.e1, v))
7268                     return setError();
7269 
7270                 ve.checkPurity(sc, v);
7271             }
7272             FuncDeclaration f = ve.var.isFuncDeclaration();
7273             if (f)
7274             {
7275                 /* Because nested functions cannot be overloaded,
7276                  * mark here that we took its address because castTo()
7277                  * may not be called with an exact match.
7278                  *
7279                  * https://issues.dlang.org/show_bug.cgi?id=19285 :
7280                  * We also need to make sure we aren't inside a typeof. Ideally the compiler
7281                  * would do typeof(...) semantic analysis speculatively then collect information
7282                  * about what it used rather than relying on what are effectively semantically-global
7283                  * variables but it doesn't.
7284                  */
7285                 if (!sc.isFromSpeculativeSemanticContext() && (!ve.hasOverloads || (f.isNested() && !f.needThis())))
7286                 {
7287                     // TODO: Refactor to use a proper interface that can keep track of causes.
7288                     f.tookAddressOf++;
7289                 }
7290 
7291                 if (f.isNested() && !f.needThis())
7292                 {
7293                     if (f.isFuncLiteralDeclaration())
7294                     {
7295                         if (!f.FuncDeclaration.isNested())
7296                         {
7297                             /* Supply a 'null' for a this pointer if no this is available
7298                              */
7299                             Expression e = new DelegateExp(exp.loc, new NullExp(exp.loc, Type.tnull), f, ve.hasOverloads);
7300                             e = e.expressionSemantic(sc);
7301                             result = e;
7302                             return;
7303                         }
7304                     }
7305                     Expression e = new DelegateExp(exp.loc, exp.e1, f, ve.hasOverloads);
7306                     e = e.expressionSemantic(sc);
7307                     result = e;
7308                     return;
7309                 }
7310                 if (f.needThis())
7311                 {
7312                     auto memberFunc = hasThis(sc);
7313                     if (memberFunc && haveSameThis(memberFunc, f))
7314                     {
7315                         /* Should probably supply 'this' after overload resolution,
7316                          * not before.
7317                          */
7318                         Expression ethis = new ThisExp(exp.loc);
7319                         Expression e = new DelegateExp(exp.loc, ethis, f, ve.hasOverloads);
7320                         e = e.expressionSemantic(sc);
7321                         result = e;
7322                         return;
7323                     }
7324                     if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
7325                     {
7326                         sc.setUnsafe(false, exp.loc,
7327                             "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
7328                             f, sc.func);
7329                     }
7330                 }
7331             }
7332         }
7333         else if (exp.e1.op == EXP.index)
7334         {
7335             /* For:
7336              *   int[3] a;
7337              *   &a[i]
7338              * check 'a' the same as for a regular variable
7339              */
7340             if (VarDeclaration v = expToVariable(exp.e1))
7341             {
7342                 exp.e1.checkPurity(sc, v);
7343             }
7344         }
7345         else if (wasCond)
7346         {
7347             /* a ? b : c was transformed to *(a ? &b : &c), but we still
7348              * need to do safety checks
7349              */
7350             assert(exp.e1.op == EXP.star);
7351             PtrExp pe = cast(PtrExp)exp.e1;
7352             assert(pe.e1.op == EXP.question);
7353             CondExp ce = cast(CondExp)pe.e1;
7354             assert(ce.e1.op == EXP.address);
7355             assert(ce.e2.op == EXP.address);
7356 
7357             // Re-run semantic on the address expressions only
7358             ce.e1.type = null;
7359             ce.e1 = ce.e1.expressionSemantic(sc);
7360             ce.e2.type = null;
7361             ce.e2 = ce.e2.expressionSemantic(sc);
7362         }
7363         result = exp.optimize(WANTvalue);
7364     }
7365 
7366     override void visit(PtrExp exp)
7367     {
7368         static if (LOGSEMANTIC)
7369         {
7370             printf("PtrExp::semantic('%s')\n", exp.toChars());
7371         }
7372         if (exp.type)
7373         {
7374             result = exp;
7375             return;
7376         }
7377 
7378         Expression e = exp.op_overload(sc);
7379         if (e)
7380         {
7381             result = e;
7382             return;
7383         }
7384 
7385         exp.e1 = exp.e1.arrayFuncConv(sc);
7386 
7387         Type tb = exp.e1.type.toBasetype();
7388         switch (tb.ty)
7389         {
7390         case Tpointer:
7391             exp.type = (cast(TypePointer)tb).next;
7392             break;
7393 
7394         case Tsarray:
7395         case Tarray:
7396             if (isNonAssignmentArrayOp(exp.e1))
7397                 goto default;
7398             exp.error("using `*` on an array is no longer supported; use `*(%s).ptr` instead", exp.e1.toChars());
7399             exp.type = (cast(TypeArray)tb).next;
7400             exp.e1 = exp.e1.castTo(sc, exp.type.pointerTo());
7401             break;
7402 
7403         case Terror:
7404             return setError();
7405 
7406         case Tnull:
7407             exp.type = Type.tnoreturn;  // typeof(*null) is bottom type
7408             break;
7409 
7410         default:
7411             exp.error("can only `*` a pointer, not a `%s`", exp.e1.type.toChars());
7412             goto case Terror;
7413         }
7414 
7415         if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
7416         {
7417             // https://issues.dlang.org/show_bug.cgi?id=23752
7418             // `&*((void*)(0))` is allowed in C
7419             result = exp;
7420             return;
7421         }
7422 
7423         if (exp.checkValue())
7424             return setError();
7425 
7426         result = exp;
7427     }
7428 
7429     override void visit(NegExp exp)
7430     {
7431         static if (LOGSEMANTIC)
7432         {
7433             printf("NegExp::semantic('%s')\n", exp.toChars());
7434         }
7435         if (exp.type)
7436         {
7437             result = exp;
7438             return;
7439         }
7440 
7441         Expression e = exp.op_overload(sc);
7442         if (e)
7443         {
7444             result = e;
7445             return;
7446         }
7447 
7448         fix16997(sc, exp);
7449         exp.type = exp.e1.type;
7450         Type tb = exp.type.toBasetype();
7451         if (tb.ty == Tarray || tb.ty == Tsarray)
7452         {
7453             if (!isArrayOpValid(exp.e1))
7454             {
7455                 result = arrayOpInvalidError(exp);
7456                 return;
7457             }
7458             result = exp;
7459             return;
7460         }
7461         if (!target.isVectorOpSupported(tb, exp.op))
7462         {
7463             result = exp.incompatibleTypes();
7464             return;
7465         }
7466         if (exp.e1.checkNoBool())
7467             return setError();
7468         if (exp.e1.checkArithmetic() ||
7469             exp.e1.checkSharedAccess(sc))
7470             return setError();
7471 
7472         result = exp;
7473     }
7474 
7475     override void visit(UAddExp exp)
7476     {
7477         static if (LOGSEMANTIC)
7478         {
7479             printf("UAddExp::semantic('%s')\n", exp.toChars());
7480         }
7481         assert(!exp.type);
7482 
7483         Expression e = exp.op_overload(sc);
7484         if (e)
7485         {
7486             result = e;
7487             return;
7488         }
7489 
7490         fix16997(sc, exp);
7491         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op))
7492         {
7493             result = exp.incompatibleTypes();
7494             return;
7495         }
7496         if (exp.e1.checkNoBool())
7497             return setError();
7498         if (exp.e1.checkArithmetic())
7499             return setError();
7500         if (exp.e1.checkSharedAccess(sc))
7501             return setError();
7502 
7503         result = exp.e1;
7504     }
7505 
7506     override void visit(ComExp exp)
7507     {
7508         if (exp.type)
7509         {
7510             result = exp;
7511             return;
7512         }
7513 
7514         Expression e = exp.op_overload(sc);
7515         if (e)
7516         {
7517             result = e;
7518             return;
7519         }
7520 
7521         fix16997(sc, exp);
7522         exp.type = exp.e1.type;
7523         Type tb = exp.type.toBasetype();
7524         if (tb.ty == Tarray || tb.ty == Tsarray)
7525         {
7526             if (!isArrayOpValid(exp.e1))
7527             {
7528                 result = arrayOpInvalidError(exp);
7529                 return;
7530             }
7531             result = exp;
7532             return;
7533         }
7534         if (!target.isVectorOpSupported(tb, exp.op))
7535         {
7536             result = exp.incompatibleTypes();
7537             return;
7538         }
7539         if (exp.e1.checkNoBool())
7540             return setError();
7541         if (exp.e1.checkIntegral() ||
7542             exp.e1.checkSharedAccess(sc))
7543             return setError();
7544 
7545         result = exp;
7546     }
7547 
7548     override void visit(NotExp e)
7549     {
7550         if (e.type)
7551         {
7552             result = e;
7553             return;
7554         }
7555 
7556         e.setNoderefOperand();
7557 
7558         // Note there is no operator overload
7559         if (Expression ex = unaSemantic(e, sc))
7560         {
7561             result = ex;
7562             return;
7563         }
7564 
7565         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7566         if (e.e1.op == EXP.type)
7567             e.e1 = resolveAliasThis(sc, e.e1);
7568 
7569         e.e1 = resolveProperties(sc, e.e1);
7570         e.e1 = e.e1.toBoolean(sc);
7571         if (e.e1.type == Type.terror)
7572         {
7573             result = e.e1;
7574             return;
7575         }
7576 
7577         if (!target.isVectorOpSupported(e.e1.type.toBasetype(), e.op))
7578         {
7579             result = e.incompatibleTypes();
7580         }
7581         // https://issues.dlang.org/show_bug.cgi?id=13910
7582         // Today NotExp can take an array as its operand.
7583         if (checkNonAssignmentArrayOp(e.e1))
7584             return setError();
7585 
7586         e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
7587         result = e;
7588     }
7589 
7590     override void visit(DeleteExp exp)
7591     {
7592         // @@@DEPRECATED_2.109@@@
7593         // 1. Deprecated since 2.079
7594         // 2. Error since 2.099
7595         // 3. Removal of keyword, "delete" can be used for other identities
7596         if (!exp.isRAII)
7597         {
7598             error(exp.loc, "the `delete` keyword is obsolete");
7599             errorSupplemental(exp.loc, "use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead");
7600             return setError();
7601         }
7602 
7603         Expression e = exp;
7604 
7605         if (Expression ex = unaSemantic(exp, sc))
7606         {
7607             result = ex;
7608             return;
7609         }
7610         exp.e1 = resolveProperties(sc, exp.e1);
7611         exp.e1 = exp.e1.modifiableLvalue(sc, null);
7612         if (exp.e1.op == EXP.error)
7613         {
7614             result = exp.e1;
7615             return;
7616         }
7617         exp.type = Type.tvoid;
7618 
7619         Type tb = exp.e1.type.toBasetype();
7620 
7621         /* Now that `delete` in user code is an error, we only get here when
7622          * `isRAII` has been set to true for the deletion of a `scope class`.  */
7623         if (tb.ty != Tclass)
7624         {
7625             exp.error("cannot delete type `%s`", exp.e1.type.toChars());
7626             return setError();
7627         }
7628 
7629         ClassDeclaration cd = (cast(TypeClass)tb).sym;
7630         if (cd.isCOMinterface())
7631         {
7632             /* Because COM classes are deleted by IUnknown.Release()
7633              */
7634             exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
7635             return setError();
7636         }
7637 
7638         bool err = false;
7639         if (cd.dtor)
7640         {
7641             err |= !cd.dtor.functionSemantic();
7642             err |= exp.checkPurity(sc, cd.dtor);
7643             err |= exp.checkSafety(sc, cd.dtor);
7644             err |= exp.checkNogc(sc, cd.dtor);
7645         }
7646         if (err)
7647             return setError();
7648 
7649         result = e;
7650     }
7651 
7652     override void visit(CastExp exp)
7653     {
7654         static if (LOGSEMANTIC)
7655         {
7656             printf("CastExp::semantic('%s')\n", exp.toChars());
7657         }
7658         //static int x; assert(++x < 10);
7659         if (exp.type)
7660         {
7661             result = exp;
7662             return;
7663         }
7664 
7665         if ((sc && sc.flags & SCOPE.Cfile) &&
7666             exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
7667             (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
7668              exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
7669         {
7670             /* Ambiguous cases arise from CParser if type-name is just an identifier.
7671              *   ( identifier ) cast-expression
7672              *   ( identifier [expression]) cast-expression
7673              * If we determine that `identifier` is a variable, and cast-expression
7674              * is one of the unary operators (& * + -), then rewrite this cast
7675              * as a binary expression.
7676              */
7677             Loc loc = exp.loc;
7678             Type t;
7679             Expression e;
7680             Dsymbol s;
7681             exp.to.resolve(loc, sc, e, t, s);
7682             if (e !is null)
7683             {
7684                 if (auto ex = exp.e1.isAddrExp())       // (ident) &exp -> (ident & exp)
7685                     result = new AndExp(loc, e, ex.e1);
7686                 else if (auto ex = exp.e1.isPtrExp())   // (ident) *exp -> (ident * exp)
7687                     result = new MulExp(loc, e, ex.e1);
7688                 else if (auto ex = exp.e1.isUAddExp())  // (ident) +exp -> (ident + exp)
7689                     result = new AddExp(loc, e, ex.e1);
7690                 else if (auto ex = exp.e1.isNegExp())   // (ident) -exp -> (ident - exp)
7691                     result = new MinExp(loc, e, ex.e1);
7692 
7693                 assert(result);
7694                 result = result.expressionSemantic(sc);
7695                 return;
7696             }
7697         }
7698 
7699         if (exp.to)
7700         {
7701             exp.to = exp.to.typeSemantic(exp.loc, sc);
7702             if (exp.to == Type.terror)
7703                 return setError();
7704 
7705             if (!exp.to.hasPointers())
7706                 exp.setNoderefOperand();
7707 
7708             // When e1 is a template lambda, this cast may instantiate it with
7709             // the type 'to'.
7710             exp.e1 = inferType(exp.e1, exp.to);
7711         }
7712 
7713         if (auto e = unaSemantic(exp, sc))
7714         {
7715             result = e;
7716             return;
7717         }
7718 
7719         if (exp.to && !exp.to.isTypeSArray() && !exp.to.isTypeFunction())
7720             exp.e1 = exp.e1.arrayFuncConv(sc);
7721 
7722         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
7723         if (exp.e1.op == EXP.type)
7724             exp.e1 = resolveAliasThis(sc, exp.e1);
7725 
7726         auto e1x = resolveProperties(sc, exp.e1);
7727         if (e1x.op == EXP.error)
7728         {
7729             result = e1x;
7730             return;
7731         }
7732         if (e1x.checkType())
7733             return setError();
7734         exp.e1 = e1x;
7735 
7736         if (!exp.e1.type)
7737         {
7738             exp.error("cannot cast `%s`", exp.e1.toChars());
7739             return setError();
7740         }
7741 
7742         // https://issues.dlang.org/show_bug.cgi?id=19954
7743         if (exp.e1.type.ty == Ttuple)
7744         {
7745             if (exp.to)
7746             {
7747                 if (TypeTuple tt = exp.to.isTypeTuple())
7748                 {
7749                     if (exp.e1.type.implicitConvTo(tt))
7750                     {
7751                         result = exp.e1.castTo(sc, tt);
7752                         return;
7753                     }
7754                 }
7755             }
7756             TupleExp te = exp.e1.isTupleExp();
7757             if (te.exps.length == 1)
7758                 exp.e1 = (*te.exps)[0];
7759         }
7760 
7761         // only allow S(x) rewrite if cast specified S explicitly.
7762         // See https://issues.dlang.org/show_bug.cgi?id=18545
7763         const bool allowImplicitConstruction = exp.to !is null;
7764 
7765         if (!exp.to) // Handle cast(const) and cast(immutable), etc.
7766         {
7767             exp.to = exp.e1.type.castMod(exp.mod);
7768             exp.to = exp.to.typeSemantic(exp.loc, sc);
7769 
7770             if (exp.to == Type.terror)
7771                 return setError();
7772         }
7773 
7774         if (exp.to.ty == Ttuple)
7775         {
7776             exp.error("cannot cast `%s` of type `%s` to tuple type `%s`", exp.e1.toChars(), exp.e1.type.toChars(), exp.to.toChars());
7777             return setError();
7778         }
7779 
7780         // cast(void) is used to mark e1 as unused, so it is safe
7781         if (exp.to.ty == Tvoid)
7782         {
7783             exp.type = exp.to;
7784             result = exp;
7785             return;
7786         }
7787 
7788         if (!exp.to.equals(exp.e1.type) && exp.mod == cast(ubyte)~0)
7789         {
7790             if (Expression e = exp.op_overload(sc))
7791             {
7792                 result = e.implicitCastTo(sc, exp.to);
7793                 return;
7794             }
7795         }
7796 
7797         Type t1b = exp.e1.type.toBasetype();
7798         Type tob = exp.to.toBasetype();
7799 
7800         if (allowImplicitConstruction && tob.ty == Tstruct && !tob.equals(t1b))
7801         {
7802             /* Look to replace:
7803              *  cast(S)t
7804              * with:
7805              *  S(t)
7806              */
7807 
7808             // Rewrite as to.call(e1)
7809             Expression e = new TypeExp(exp.loc, exp.to);
7810             e = new CallExp(exp.loc, e, exp.e1);
7811             e = e.trySemantic(sc);
7812             if (e)
7813             {
7814                 result = e;
7815                 return;
7816             }
7817         }
7818 
7819         if (!t1b.equals(tob) && (t1b.ty == Tarray || t1b.ty == Tsarray))
7820         {
7821             if (checkNonAssignmentArrayOp(exp.e1))
7822                 return setError();
7823         }
7824 
7825         // Look for casting to a vector type
7826         if (tob.ty == Tvector && t1b.ty != Tvector)
7827         {
7828             result = new VectorExp(exp.loc, exp.e1, exp.to);
7829             result = result.expressionSemantic(sc);
7830             return;
7831         }
7832 
7833         Expression ex = exp.e1.castTo(sc, exp.to);
7834         if (ex.op == EXP.error)
7835         {
7836             result = ex;
7837             return;
7838         }
7839 
7840         // Check for unsafe casts
7841         if (!isSafeCast(ex, t1b, tob))
7842         {
7843             if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
7844             {
7845                 return setError();
7846             }
7847         }
7848 
7849         // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
7850         // to handle certain casts.  Those casts which `object.__ArrayCast` does not support are filtered out.
7851         // See `e2ir.toElemCast` for other types of casts.  If `object.__ArrayCast` is improved to support more
7852         // casts these conditions and potentially some logic in `e2ir.toElemCast` can be removed.
7853         if (tob.ty == Tarray)
7854         {
7855             // https://issues.dlang.org/show_bug.cgi?id=19840
7856             if (auto ad = isAggregate(t1b))
7857             {
7858                 if (ad.aliasthis)
7859                 {
7860                     Expression e = resolveAliasThis(sc, exp.e1);
7861                     e = new CastExp(exp.loc, e, exp.to);
7862                     result = e.expressionSemantic(sc);
7863                     return;
7864                 }
7865             }
7866 
7867             if(t1b.ty == Tarray && exp.e1.op != EXP.arrayLiteral && sc.needsCodegen())
7868             {
7869                 auto tFrom = t1b.nextOf();
7870                 auto tTo = tob.nextOf();
7871 
7872                 // https://issues.dlang.org/show_bug.cgi?id=20130
7873                 if (exp.e1.op != EXP.string_ || !ex.isStringExp)
7874                 {
7875                     const uint fromSize = cast(uint)tFrom.size();
7876                     const uint toSize = cast(uint)tTo.size();
7877                     if (fromSize == SIZE_INVALID || toSize == SIZE_INVALID)
7878                         return setError();
7879 
7880                     // If array element sizes do not match, we must adjust the dimensions
7881                     if (fromSize != toSize)
7882                     {
7883                         if (!verifyHookExist(exp.loc, *sc, Id.__ArrayCast, "casting array of structs"))
7884                             return setError();
7885 
7886                         // A runtime check is needed in case arrays don't line up.  That check should
7887                         // be done in the implementation of `object.__ArrayCast`
7888                         if (toSize == 0 || (fromSize % toSize) != 0)
7889                         {
7890                             // lower to `object.__ArrayCast!(TFrom, TTo)(from)`
7891 
7892                             // fully qualify as `object.__ArrayCast`
7893                             Expression id = new IdentifierExp(exp.loc, Id.empty);
7894                             auto dotid = new DotIdExp(exp.loc, id, Id.object);
7895 
7896                             auto tiargs = new Objects();
7897                             tiargs.push(tFrom);
7898                             tiargs.push(tTo);
7899                             auto dt = new DotTemplateInstanceExp(exp.loc, dotid, Id.__ArrayCast, tiargs);
7900 
7901                             auto arguments = new Expressions();
7902                             arguments.push(exp.e1);
7903                             Expression ce = new CallExp(exp.loc, dt, arguments);
7904 
7905                             result = expressionSemantic(ce, sc);
7906                             return;
7907                         }
7908                     }
7909                 }
7910             }
7911         }
7912 
7913         if (sc && sc.flags & SCOPE.Cfile)
7914         {
7915             /* C11 6.5.4-5: A cast does not yield an lvalue.
7916              * So ensure that castTo does not strip away the cast so that this
7917              * can be enforced in other semantic visitor methods.
7918              */
7919             if (!ex.isCastExp())
7920             {
7921                 ex = new CastExp(exp.loc, ex, exp.to);
7922                 ex.type = exp.to;
7923             }
7924         }
7925         result = ex;
7926     }
7927 
7928     override void visit(VectorExp exp)
7929     {
7930         static if (LOGSEMANTIC)
7931         {
7932             printf("VectorExp::semantic('%s')\n", exp.toChars());
7933         }
7934         if (exp.type)
7935         {
7936             result = exp;
7937             return;
7938         }
7939 
7940         exp.e1 = exp.e1.expressionSemantic(sc);
7941         exp.type = exp.to.typeSemantic(exp.loc, sc);
7942         if (exp.e1.op == EXP.error || exp.type.ty == Terror)
7943         {
7944             result = exp.e1;
7945             return;
7946         }
7947 
7948         Type tb = exp.type.toBasetype();
7949         assert(tb.ty == Tvector);
7950         TypeVector tv = cast(TypeVector)tb;
7951         Type te = tv.elementType();
7952         exp.dim = cast(int)(tv.size(exp.loc) / te.size(exp.loc));
7953 
7954         bool checkElem(Expression elem)
7955         {
7956             if (elem.isConst() == 1)
7957                 return false;
7958 
7959              exp.error("constant expression expected, not `%s`", elem.toChars());
7960              return true;
7961         }
7962 
7963         exp.e1 = exp.e1.optimize(WANTvalue);
7964         bool res;
7965         if (exp.e1.op == EXP.arrayLiteral)
7966         {
7967             foreach (i; 0 .. exp.dim)
7968             {
7969                 // Do not stop on first error - check all AST nodes even if error found
7970                 res |= checkElem(exp.e1.isArrayLiteralExp()[i]);
7971             }
7972         }
7973         else if (exp.e1.type.ty == Tvoid)
7974             checkElem(exp.e1);
7975 
7976         result = res ? ErrorExp.get() : exp;
7977     }
7978 
7979     override void visit(VectorArrayExp e)
7980     {
7981         static if (LOGSEMANTIC)
7982         {
7983             printf("VectorArrayExp::semantic('%s')\n", e.toChars());
7984         }
7985         if (!e.type)
7986         {
7987             unaSemantic(e, sc);
7988             e.e1 = resolveProperties(sc, e.e1);
7989 
7990             if (e.e1.op == EXP.error)
7991             {
7992                 result = e.e1;
7993                 return;
7994             }
7995             assert(e.e1.type.ty == Tvector);
7996             e.type = e.e1.type.isTypeVector().basetype;
7997         }
7998         result = e;
7999     }
8000 
8001     override void visit(SliceExp exp)
8002     {
8003         static if (LOGSEMANTIC)
8004         {
8005             printf("SliceExp::semantic('%s')\n", exp.toChars());
8006         }
8007         if (exp.type)
8008         {
8009             result = exp;
8010             return;
8011         }
8012 
8013         // operator overloading should be handled in ArrayExp already.
8014         if (Expression ex = unaSemantic(exp, sc))
8015         {
8016             result = ex;
8017             return;
8018         }
8019         exp.e1 = resolveProperties(sc, exp.e1);
8020         if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8021         {
8022             if (exp.lwr || exp.upr)
8023             {
8024                 exp.error("cannot slice type `%s`", exp.e1.toChars());
8025                 return setError();
8026             }
8027             Expression e = new TypeExp(exp.loc, exp.e1.type.arrayOf());
8028             result = e.expressionSemantic(sc);
8029             return;
8030         }
8031         if (!exp.lwr && !exp.upr)
8032         {
8033             if (exp.e1.op == EXP.arrayLiteral)
8034             {
8035                 // Convert [a,b,c][] to [a,b,c]
8036                 Type t1b = exp.e1.type.toBasetype();
8037                 Expression e = exp.e1;
8038                 if (t1b.ty == Tsarray)
8039                 {
8040                     e = e.copy();
8041                     e.type = t1b.nextOf().arrayOf();
8042                 }
8043                 result = e;
8044                 return;
8045             }
8046             if (exp.e1.op == EXP.slice)
8047             {
8048                 // Convert e[][] to e[]
8049                 SliceExp se = cast(SliceExp)exp.e1;
8050                 if (!se.lwr && !se.upr)
8051                 {
8052                     result = se;
8053                     return;
8054                 }
8055             }
8056             if (isArrayOpOperand(exp.e1))
8057             {
8058                 // Convert (a[]+b[])[] to a[]+b[]
8059                 result = exp.e1;
8060                 return;
8061             }
8062         }
8063         if (exp.e1.op == EXP.error)
8064         {
8065             result = exp.e1;
8066             return;
8067         }
8068         if (exp.e1.type.ty == Terror)
8069             return setError();
8070 
8071         Type t1b = exp.e1.type.toBasetype();
8072         if (auto tp = t1b.isTypePointer())
8073         {
8074             if (t1b.isPtrToFunction())
8075             {
8076                 exp.error("cannot slice function pointer `%s`", exp.e1.toChars());
8077                 return setError();
8078             }
8079             if (!exp.lwr || !exp.upr)
8080             {
8081                 exp.error("upper and lower bounds are needed to slice a pointer");
8082                 if (auto ad = isAggregate(tp.next.toBasetype()))
8083                 {
8084                     auto s = search_function(ad, Id.index);
8085                     if (!s) s = search_function(ad, Id.slice);
8086                     if (s)
8087                     {
8088                         auto fd = s.isFuncDeclaration();
8089                         if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
8090                         {
8091                             exp.errorSupplemental(
8092                                 "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
8093                                 exp.e1.toChars(),
8094                                 s.ident.toChars(),
8095                                 exp.e1.toChars()
8096                             );
8097                         }
8098 
8099                     }
8100                 }
8101 
8102                 return setError();
8103             }
8104             if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
8105                 return setError();
8106         }
8107         else if (t1b.ty == Tarray)
8108         {
8109         }
8110         else if (t1b.ty == Tsarray)
8111         {
8112         }
8113         else if (t1b.ty == Ttuple)
8114         {
8115             if (!exp.lwr && !exp.upr)
8116             {
8117                 result = exp.e1;
8118                 return;
8119             }
8120             if (!exp.lwr || !exp.upr)
8121             {
8122                 exp.error("need upper and lower bound to slice tuple");
8123                 return setError();
8124             }
8125         }
8126         else if (t1b.ty == Tvector && exp.e1.isLvalue())
8127         {
8128             // Convert e1 to corresponding static array
8129             TypeVector tv1 = cast(TypeVector)t1b;
8130             t1b = tv1.basetype;
8131             t1b = t1b.castMod(tv1.mod);
8132             exp.e1.type = t1b;
8133         }
8134         else
8135         {
8136             exp.error("`%s` cannot be sliced with `[]`", t1b.ty == Tvoid ? exp.e1.toChars() : t1b.toChars());
8137             return setError();
8138         }
8139 
8140         /* Run semantic on lwr and upr.
8141          */
8142         Scope* scx = sc;
8143         if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8144         {
8145             // Create scope for 'length' variable
8146             ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8147             sym.parent = sc.scopesym;
8148             sc = sc.push(sym);
8149         }
8150         if (exp.lwr)
8151         {
8152             if (t1b.ty == Ttuple)
8153                 sc = sc.startCTFE();
8154             exp.lwr = exp.lwr.expressionSemantic(sc);
8155             exp.lwr = resolveProperties(sc, exp.lwr);
8156             if (t1b.ty == Ttuple)
8157                 sc = sc.endCTFE();
8158             exp.lwr = exp.lwr.implicitCastTo(sc, Type.tsize_t);
8159         }
8160         if (exp.upr)
8161         {
8162             if (t1b.ty == Ttuple)
8163                 sc = sc.startCTFE();
8164             exp.upr = exp.upr.expressionSemantic(sc);
8165             exp.upr = resolveProperties(sc, exp.upr);
8166             if (t1b.ty == Ttuple)
8167                 sc = sc.endCTFE();
8168             exp.upr = exp.upr.implicitCastTo(sc, Type.tsize_t);
8169         }
8170         if (sc != scx)
8171             sc = sc.pop();
8172         if (exp.lwr && exp.lwr.type == Type.terror || exp.upr && exp.upr.type == Type.terror)
8173             return setError();
8174 
8175         if (t1b.ty == Ttuple)
8176         {
8177             exp.lwr = exp.lwr.ctfeInterpret();
8178             exp.upr = exp.upr.ctfeInterpret();
8179             uinteger_t i1 = exp.lwr.toUInteger();
8180             uinteger_t i2 = exp.upr.toUInteger();
8181 
8182             TupleExp te;
8183             TypeTuple tup;
8184             size_t length;
8185             if (exp.e1.op == EXP.tuple) // slicing an expression tuple
8186             {
8187                 te = cast(TupleExp)exp.e1;
8188                 tup = null;
8189                 length = te.exps.length;
8190             }
8191             else if (exp.e1.op == EXP.type) // slicing a type tuple
8192             {
8193                 te = null;
8194                 tup = cast(TypeTuple)t1b;
8195                 length = Parameter.dim(tup.arguments);
8196             }
8197             else
8198                 assert(0);
8199 
8200             if (i2 < i1 || length < i2)
8201             {
8202                 exp.error("string slice `[%llu .. %llu]` is out of bounds", i1, i2);
8203                 return setError();
8204             }
8205 
8206             size_t j1 = cast(size_t)i1;
8207             size_t j2 = cast(size_t)i2;
8208             Expression e;
8209             if (exp.e1.op == EXP.tuple)
8210             {
8211                 auto exps = new Expressions(j2 - j1);
8212                 for (size_t i = 0; i < j2 - j1; i++)
8213                 {
8214                     (*exps)[i] = (*te.exps)[j1 + i];
8215                 }
8216                 e = new TupleExp(exp.loc, te.e0, exps);
8217             }
8218             else
8219             {
8220                 auto args = new Parameters();
8221                 args.reserve(j2 - j1);
8222                 for (size_t i = j1; i < j2; i++)
8223                 {
8224                     Parameter arg = Parameter.getNth(tup.arguments, i);
8225                     args.push(arg);
8226                 }
8227                 e = new TypeExp(exp.e1.loc, new TypeTuple(args));
8228             }
8229             e = e.expressionSemantic(sc);
8230             result = e;
8231             return;
8232         }
8233 
8234         exp.type = t1b.nextOf().arrayOf();
8235         // Allow typedef[] -> typedef[]
8236         if (exp.type.equals(t1b))
8237             exp.type = exp.e1.type;
8238 
8239         // We might know $ now
8240         setLengthVarIfKnown(exp.lengthVar, t1b);
8241 
8242         if (exp.lwr && exp.upr)
8243         {
8244             exp.lwr = exp.lwr.optimize(WANTvalue);
8245             exp.upr = exp.upr.optimize(WANTvalue);
8246 
8247             IntRange lwrRange = getIntRange(exp.lwr);
8248             IntRange uprRange = getIntRange(exp.upr);
8249 
8250             if (t1b.ty == Tsarray || t1b.ty == Tarray)
8251             {
8252                 Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8253                 el = el.expressionSemantic(sc);
8254                 el = el.optimize(WANTvalue);
8255                 if (el.op == EXP.int64)
8256                 {
8257                     // Array length is known at compile-time. Upper is in bounds if it fits length.
8258                     dinteger_t length = el.toInteger();
8259                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length));
8260                     exp.upperIsInBounds = bounds.contains(uprRange);
8261                 }
8262                 else if (exp.upr.op == EXP.int64 && exp.upr.toInteger() == 0)
8263                 {
8264                     // Upper slice expression is '0'. Value is always in bounds.
8265                     exp.upperIsInBounds = true;
8266                 }
8267                 else if (exp.upr.op == EXP.variable && (cast(VarExp)exp.upr).var.ident == Id.dollar)
8268                 {
8269                     // Upper slice expression is '$'. Value is always in bounds.
8270                     exp.upperIsInBounds = true;
8271                 }
8272             }
8273             else if (t1b.ty == Tpointer)
8274             {
8275                 exp.upperIsInBounds = true;
8276             }
8277             else
8278                 assert(0);
8279 
8280             exp.lowerIsLessThanUpper = (lwrRange.imax <= uprRange.imin);
8281 
8282             //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", exp.upperIsInBounds, exp.lowerIsLessThanUpper);
8283         }
8284 
8285         result = exp;
8286     }
8287 
8288     override void visit(ArrayLengthExp e)
8289     {
8290         static if (LOGSEMANTIC)
8291         {
8292             printf("ArrayLengthExp::semantic('%s')\n", e.toChars());
8293         }
8294         if (e.type)
8295         {
8296             result = e;
8297             return;
8298         }
8299 
8300         if (Expression ex = unaSemantic(e, sc))
8301         {
8302             result = ex;
8303             return;
8304         }
8305         e.e1 = resolveProperties(sc, e.e1);
8306 
8307         e.type = Type.tsize_t;
8308         result = e;
8309     }
8310 
8311     override void visit(ArrayExp exp)
8312     {
8313         static if (LOGSEMANTIC)
8314         {
8315             printf("ArrayExp::semantic('%s')\n", exp.toChars());
8316         }
8317         assert(!exp.type);
8318 
8319         if (sc.flags & SCOPE.Cfile)
8320         {
8321             /* See if need to rewrite the AST because of cast/call ambiguity
8322              */
8323             if (auto e = castCallAmbiguity(exp, sc))
8324             {
8325                 result = expressionSemantic(e, sc);
8326                 return;
8327             }
8328         }
8329 
8330         result = exp.carraySemantic(sc);  // C semantics
8331         if (result)
8332             return;
8333 
8334         Expression e = exp.op_overload(sc);
8335         if (e)
8336         {
8337             result = e;
8338             return;
8339         }
8340 
8341         if (isAggregate(exp.e1.type))
8342             exp.error("no `[]` operator overload for type `%s`", exp.e1.type.toChars());
8343         else if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8344             exp.error("static array of `%s` with multiple lengths not allowed", exp.e1.type.toChars());
8345         else if (isIndexableNonAggregate(exp.e1.type))
8346             exp.error("only one index allowed to index `%s`", exp.e1.type.toChars());
8347         else
8348             exp.error("cannot use `[]` operator on expression of type `%s`", exp.e1.type.toChars());
8349 
8350         result = ErrorExp.get();
8351     }
8352 
8353     override void visit(DotExp exp)
8354     {
8355         static if (LOGSEMANTIC)
8356         {
8357             printf("DotExp::semantic('%s')\n", exp.toChars());
8358             if (exp.type)
8359                 printf("\ttype = %s\n", exp.type.toChars());
8360         }
8361         exp.e1 = exp.e1.expressionSemantic(sc);
8362         exp.e2 = exp.e2.expressionSemantic(sc);
8363 
8364         if (exp.e1.op == EXP.type)
8365         {
8366             result = exp.e2;
8367             return;
8368         }
8369         if (exp.e2.op == EXP.type)
8370         {
8371             result = exp.e2;
8372             return;
8373         }
8374         if (auto te = exp.e2.isTemplateExp())
8375         {
8376             Expression e = new DotTemplateExp(exp.loc, exp.e1, te.td);
8377             result = e.expressionSemantic(sc);
8378             return;
8379         }
8380         if (!exp.type)
8381             exp.type = exp.e2.type;
8382         result = exp;
8383     }
8384 
8385     override void visit(CommaExp e)
8386     {
8387         //printf("Semantic.CommaExp() %s\n", e.toChars());
8388         if (e.type)
8389         {
8390             result = e;
8391             return;
8392         }
8393 
8394         // Allow `((a,b),(x,y))`
8395         if (e.allowCommaExp)
8396         {
8397             CommaExp.allow(e.e1);
8398             CommaExp.allow(e.e2);
8399         }
8400 
8401         if (Expression ex = binSemanticProp(e, sc))
8402         {
8403             result = ex;
8404             return;
8405         }
8406         e.e1 = e.e1.addDtorHook(sc);
8407 
8408         if (checkNonAssignmentArrayOp(e.e1))
8409             return setError();
8410 
8411         // Comma expressions trigger this conversion
8412         e.e2 = e.e2.arrayFuncConv(sc);
8413 
8414         e.type = e.e2.type;
8415         result = e;
8416 
8417         if (sc.flags & SCOPE.Cfile)
8418             return;
8419 
8420         if (e.type is Type.tvoid)
8421         {
8422             checkMustUse(e.e1, sc);
8423             discardValue(e.e1);
8424         }
8425         else if (!e.allowCommaExp && !e.isGenerated)
8426             e.error("using the result of a comma expression is not allowed");
8427     }
8428 
8429     override void visit(IntervalExp e)
8430     {
8431         static if (LOGSEMANTIC)
8432         {
8433             printf("IntervalExp::semantic('%s')\n", e.toChars());
8434         }
8435         if (e.type)
8436         {
8437             result = e;
8438             return;
8439         }
8440 
8441         Expression le = e.lwr;
8442         le = le.expressionSemantic(sc);
8443         le = resolveProperties(sc, le);
8444 
8445         Expression ue = e.upr;
8446         ue = ue.expressionSemantic(sc);
8447         ue = resolveProperties(sc, ue);
8448 
8449         if (le.op == EXP.error)
8450         {
8451             result = le;
8452             return;
8453         }
8454         if (ue.op == EXP.error)
8455         {
8456             result = ue;
8457             return;
8458         }
8459 
8460         e.lwr = le;
8461         e.upr = ue;
8462 
8463         e.type = Type.tvoid;
8464         result = e;
8465     }
8466 
8467     override void visit(DelegatePtrExp e)
8468     {
8469         static if (LOGSEMANTIC)
8470         {
8471             printf("DelegatePtrExp::semantic('%s')\n", e.toChars());
8472         }
8473         if (!e.type)
8474         {
8475             unaSemantic(e, sc);
8476             e.e1 = resolveProperties(sc, e.e1);
8477 
8478             if (e.e1.op == EXP.error)
8479             {
8480                 result = e.e1;
8481                 return;
8482             }
8483             e.type = Type.tvoidptr;
8484         }
8485         result = e;
8486     }
8487 
8488     override void visit(DelegateFuncptrExp e)
8489     {
8490         static if (LOGSEMANTIC)
8491         {
8492             printf("DelegateFuncptrExp::semantic('%s')\n", e.toChars());
8493         }
8494         if (!e.type)
8495         {
8496             unaSemantic(e, sc);
8497             e.e1 = resolveProperties(sc, e.e1);
8498             if (e.e1.op == EXP.error)
8499             {
8500                 result = e.e1;
8501                 return;
8502             }
8503             e.type = e.e1.type.nextOf().pointerTo();
8504         }
8505         result = e;
8506     }
8507 
8508     override void visit(IndexExp exp)
8509     {
8510         static if (LOGSEMANTIC)
8511         {
8512             printf("IndexExp::semantic('%s')\n", exp.toChars());
8513         }
8514         if (exp.type)
8515         {
8516             result = exp;
8517             return;
8518         }
8519 
8520         // operator overloading should be handled in ArrayExp already.
8521         if (!exp.e1.type)
8522             exp.e1 = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
8523         assert(exp.e1.type); // semantic() should already be run on it
8524         if (exp.e1.op == EXP.type && exp.e1.type.ty != Ttuple)
8525         {
8526             exp.e2 = exp.e2.expressionSemantic(sc);
8527             exp.e2 = resolveProperties(sc, exp.e2);
8528             Type nt;
8529             if (exp.e2.op == EXP.type)
8530                 nt = new TypeAArray(exp.e1.type, exp.e2.type);
8531             else
8532                 nt = new TypeSArray(exp.e1.type, exp.e2);
8533             Expression e = new TypeExp(exp.loc, nt);
8534             result = e.expressionSemantic(sc);
8535             return;
8536         }
8537         if (exp.e1.op == EXP.error)
8538         {
8539             result = exp.e1;
8540             return;
8541         }
8542         if (exp.e1.type.ty == Terror)
8543             return setError();
8544 
8545         // Note that unlike C we do not implement the int[ptr]
8546 
8547         Type t1b = exp.e1.type.toBasetype();
8548 
8549         if (TypeVector tv1 = t1b.isTypeVector())
8550         {
8551             // Convert e1 to corresponding static array
8552             t1b = tv1.basetype;
8553             t1b = t1b.castMod(tv1.mod);
8554             exp.e1 = exp.e1.castTo(sc, t1b);
8555         }
8556         if (t1b.ty == Tsarray || t1b.ty == Tarray)
8557         {
8558             if (!checkAddressable(exp, sc))
8559                 return setError();
8560         }
8561 
8562         /* Run semantic on e2
8563          */
8564         Scope* scx = sc;
8565         if (t1b.ty == Tsarray || t1b.ty == Tarray || t1b.ty == Ttuple)
8566         {
8567             // Create scope for 'length' variable
8568             ScopeDsymbol sym = new ArrayScopeSymbol(sc, exp);
8569             sym.parent = sc.scopesym;
8570             sc = sc.push(sym);
8571         }
8572         if (t1b.ty == Ttuple)
8573             sc = sc.startCTFE();
8574         exp.e2 = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
8575         exp.e2 = resolveProperties(sc, exp.e2);
8576         if (t1b.ty == Ttuple)
8577             sc = sc.endCTFE();
8578         if (exp.e2.op == EXP.tuple)
8579         {
8580             TupleExp te = cast(TupleExp)exp.e2;
8581             if (te.exps && te.exps.length == 1)
8582                 exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix
8583         }
8584         if (sc != scx)
8585             sc = sc.pop();
8586         if (exp.e2.type == Type.terror)
8587             return setError();
8588 
8589         if (checkNonAssignmentArrayOp(exp.e1))
8590             return setError();
8591 
8592         switch (t1b.ty)
8593         {
8594         case Tpointer:
8595             if (t1b.isPtrToFunction())
8596             {
8597                 exp.error("cannot index function pointer `%s`", exp.e1.toChars());
8598                 return setError();
8599             }
8600             exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8601             if (exp.e2.type == Type.terror)
8602                 return setError();
8603             exp.e2 = exp.e2.optimize(WANTvalue);
8604             if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
8605             {
8606             }
8607             else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
8608             {
8609                 return setError();
8610             }
8611             exp.type = (cast(TypeNext)t1b).next;
8612             break;
8613 
8614         case Tarray:
8615             exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8616             if (exp.e2.type == Type.terror)
8617                 return setError();
8618             exp.type = (cast(TypeNext)t1b).next;
8619             break;
8620 
8621         case Tsarray:
8622             {
8623                 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8624                 if (exp.e2.type == Type.terror)
8625                     return setError();
8626                 exp.type = t1b.nextOf();
8627                 break;
8628             }
8629         case Taarray:
8630             {
8631                 TypeAArray taa = cast(TypeAArray)t1b;
8632                 /* We can skip the implicit conversion if they differ only by
8633                  * constness
8634                  * https://issues.dlang.org/show_bug.cgi?id=2684
8635                  * see also bug https://issues.dlang.org/show_bug.cgi?id=2954 b
8636                  */
8637                 if (!arrayTypeCompatibleWithoutCasting(exp.e2.type, taa.index))
8638                 {
8639                     exp.e2 = exp.e2.implicitCastTo(sc, taa.index); // type checking
8640                     if (exp.e2.type == Type.terror)
8641                         return setError();
8642                 }
8643 
8644                 semanticTypeInfo(sc, taa);
8645                 checkNewEscape(sc, exp.e2, false);
8646 
8647                 exp.type = taa.next;
8648                 break;
8649             }
8650         case Ttuple:
8651             {
8652                 exp.e2 = exp.e2.implicitCastTo(sc, Type.tsize_t);
8653                 if (exp.e2.type == Type.terror)
8654                     return setError();
8655 
8656                 exp.e2 = exp.e2.ctfeInterpret();
8657                 uinteger_t index = exp.e2.toUInteger();
8658 
8659                 TupleExp te;
8660                 TypeTuple tup;
8661                 size_t length;
8662                 if (exp.e1.op == EXP.tuple)
8663                 {
8664                     te = cast(TupleExp)exp.e1;
8665                     tup = null;
8666                     length = te.exps.length;
8667                 }
8668                 else if (exp.e1.op == EXP.type)
8669                 {
8670                     te = null;
8671                     tup = cast(TypeTuple)t1b;
8672                     length = Parameter.dim(tup.arguments);
8673                 }
8674                 else
8675                     assert(0);
8676 
8677                 if (length <= index)
8678                 {
8679                     exp.error("array index `[%llu]` is outside array bounds `[0 .. %llu]`", index, cast(ulong)length);
8680                     return setError();
8681                 }
8682                 Expression e;
8683                 if (exp.e1.op == EXP.tuple)
8684                 {
8685                     e = (*te.exps)[cast(size_t)index];
8686                     e = Expression.combine(te.e0, e);
8687                 }
8688                 else
8689                     e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type);
8690                 result = e;
8691                 return;
8692             }
8693         default:
8694             exp.error("`%s` must be an array or pointer type, not `%s`", exp.e1.toChars(), exp.e1.type.toChars());
8695             return setError();
8696         }
8697 
8698         // We might know $ now
8699         setLengthVarIfKnown(exp.lengthVar, t1b);
8700 
8701         if (t1b.ty == Tsarray || t1b.ty == Tarray)
8702         {
8703             Expression el = new ArrayLengthExp(exp.loc, exp.e1);
8704             el = el.expressionSemantic(sc);
8705             el = el.optimize(WANTvalue);
8706             if (el.op == EXP.int64)
8707             {
8708                 exp.e2 = exp.e2.optimize(WANTvalue);
8709                 dinteger_t length = el.toInteger();
8710                 if (length)
8711                 {
8712                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
8713                     // OR it in, because it might already be set for C array indexing
8714                     exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
8715                 }
8716                 else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
8717                 {
8718                     if (auto ve = exp.e1.isVarExp())
8719                     {
8720                         /* Rewrite 0-length C array ve[exp.e2] as *(ve + exp.e2)
8721                          */
8722                         auto vp = ve.castTo(sc, t1b.isTypeSArray().next.pointerTo());
8723                         auto e = new AddExp(exp.loc, vp, exp.e2);
8724                         auto pe = new PtrExp(exp.loc, e);
8725                         result = pe.expressionSemantic(sc).optimize(WANTvalue);
8726                         return;
8727                     }
8728                 }
8729             }
8730         }
8731 
8732         result = exp;
8733     }
8734 
8735     override void visit(PostExp exp)
8736     {
8737         static if (LOGSEMANTIC)
8738         {
8739             printf("PostExp::semantic('%s')\n", exp.toChars());
8740         }
8741         if (exp.type)
8742         {
8743             result = exp;
8744             return;
8745         }
8746 
8747         if (sc.flags & SCOPE.Cfile)
8748         {
8749             /* See if need to rewrite the AST because of cast/call ambiguity
8750              */
8751             if (auto e = castCallAmbiguity(exp, sc))
8752             {
8753                 result = expressionSemantic(e, sc);
8754                 return;
8755             }
8756         }
8757 
8758         if (Expression ex = binSemantic(exp, sc))
8759         {
8760             result = ex;
8761             return;
8762         }
8763         Expression e1x = resolveProperties(sc, exp.e1);
8764         if (e1x.op == EXP.error)
8765         {
8766             result = e1x;
8767             return;
8768         }
8769         exp.e1 = e1x;
8770 
8771         Expression e = exp.op_overload(sc);
8772         if (e)
8773         {
8774             result = e;
8775             return;
8776         }
8777 
8778         if (exp.e1.checkReadModifyWrite(exp.op))
8779             return setError();
8780 
8781         if (exp.e1.op == EXP.slice)
8782         {
8783             const(char)* s = exp.op == EXP.plusPlus ? "increment" : "decrement";
8784             exp.error("cannot post-%s array slice `%s`, use pre-%s instead", s, exp.e1.toChars(), s);
8785             return setError();
8786         }
8787 
8788         Type t1 = exp.e1.type.toBasetype();
8789         if (t1.ty == Tclass || t1.ty == Tstruct || exp.e1.op == EXP.arrayLength)
8790         {
8791             /* Check for operator overloading,
8792              * but rewrite in terms of ++e instead of e++
8793              */
8794 
8795             /* If e1 is not trivial, take a reference to it
8796              */
8797             Expression de = null;
8798             if (exp.e1.op != EXP.variable && exp.e1.op != EXP.arrayLength)
8799             {
8800                 // ref v = e1;
8801                 auto v = copyToTemp(STC.ref_, "__postref", exp.e1);
8802                 de = new DeclarationExp(exp.loc, v);
8803                 exp.e1 = new VarExp(exp.e1.loc, v);
8804             }
8805 
8806             /* Rewrite as:
8807              * auto tmp = e1; ++e1; tmp
8808              */
8809             auto tmp = copyToTemp(0, "__pitmp", exp.e1);
8810             Expression ea = new DeclarationExp(exp.loc, tmp);
8811 
8812             Expression eb = exp.e1.syntaxCopy();
8813             eb = new PreExp(exp.op == EXP.plusPlus ? EXP.prePlusPlus : EXP.preMinusMinus, exp.loc, eb);
8814 
8815             Expression ec = new VarExp(exp.loc, tmp);
8816 
8817             // Combine de,ea,eb,ec
8818             if (de)
8819                 ea = new CommaExp(exp.loc, de, ea);
8820             e = new CommaExp(exp.loc, ea, eb);
8821             e = new CommaExp(exp.loc, e, ec);
8822             e = e.expressionSemantic(sc);
8823             result = e;
8824             return;
8825         }
8826 
8827         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
8828         exp.e1 = exp.e1.optimize(WANTvalue, /*keepLvalue*/ true);
8829 
8830         e = exp;
8831         if (exp.e1.checkScalar() ||
8832             exp.e1.checkSharedAccess(sc))
8833             return setError();
8834         if (exp.e1.checkNoBool())
8835             return setError();
8836 
8837         if (exp.e1.type.ty == Tpointer)
8838             e = scaleFactor(exp, sc);
8839         else
8840             exp.e2 = exp.e2.castTo(sc, exp.e1.type);
8841         e.type = exp.e1.type;
8842         result = e;
8843     }
8844 
8845     override void visit(PreExp exp)
8846     {
8847         Expression e = exp.op_overload(sc);
8848         // printf("PreExp::semantic('%s')\n", toChars());
8849         if (e)
8850         {
8851             result = e;
8852             return;
8853         }
8854 
8855         // Rewrite as e1+=1 or e1-=1
8856         if (exp.op == EXP.prePlusPlus)
8857             e = new AddAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8858         else
8859             e = new MinAssignExp(exp.loc, exp.e1, IntegerExp.literal!1);
8860         result = e.expressionSemantic(sc);
8861     }
8862 
8863     /*
8864      * Get the expression initializer for a specific struct
8865      *
8866      * Params:
8867      *  sd = the struct for which the expression initializer is needed
8868      *  loc = the location of the initializer
8869      *  sc = the scope where the expression is located
8870      *  t = the type of the expression
8871      *
8872      * Returns:
8873      *  The expression initializer or error expression if any errors occured
8874      */
8875     private Expression getInitExp(StructDeclaration sd, Loc loc, Scope* sc, Type t)
8876     {
8877         if (sd.zeroInit && !sd.isNested())
8878         {
8879             // https://issues.dlang.org/show_bug.cgi?id=14606
8880             // Always use BlitExp for the special expression: (struct = 0)
8881             return IntegerExp.literal!0;
8882         }
8883 
8884         if (sd.isNested())
8885         {
8886             auto sle = new StructLiteralExp(loc, sd, null, t);
8887             if (!sd.fill(loc, *sle.elements, true))
8888                 return ErrorExp.get();
8889             if (checkFrameAccess(loc, sc, sd, sle.elements.length))
8890                 return ErrorExp.get();
8891 
8892             sle.type = t;
8893             return sle;
8894         }
8895 
8896         return t.defaultInit(loc);
8897     }
8898 
8899     override void visit(AssignExp exp)
8900     {
8901         static if (LOGSEMANTIC)
8902         {
8903             if (exp.op == EXP.blit)      printf("BlitExp.toElem('%s')\n", exp.toChars());
8904             if (exp.op == EXP.assign)    printf("AssignExp.toElem('%s')\n", exp.toChars());
8905             if (exp.op == EXP.construct) printf("ConstructExp.toElem('%s')\n", exp.toChars());
8906         }
8907 
8908         void setResult(Expression e, int line = __LINE__)
8909         {
8910             //printf("line %d\n", line);
8911             result = e;
8912         }
8913 
8914         if (exp.type)
8915         {
8916             return setResult(exp);
8917         }
8918 
8919         Expression e1old = exp.e1;
8920 
8921         if (auto e2comma = exp.e2.isCommaExp())
8922         {
8923             if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
8924                 exp.error("using the result of a comma expression is not allowed");
8925 
8926             /* Rewrite to get rid of the comma from rvalue
8927              *   e1=(e0,e2) => e0,(e1=e2)
8928              */
8929             Expression e0;
8930             exp.e2 = Expression.extractLast(e2comma, e0);
8931             Expression e = Expression.combine(e0, exp);
8932             return setResult(e.expressionSemantic(sc));
8933         }
8934 
8935         /* Look for operator overloading of a[arguments] = e2.
8936          * Do it before e1.expressionSemantic() otherwise the ArrayExp will have been
8937          * converted to unary operator overloading already.
8938          */
8939         if (auto ae = exp.e1.isArrayExp())
8940         {
8941             Expression res;
8942 
8943             ae.e1 = ae.e1.expressionSemantic(sc);
8944             ae.e1 = resolveProperties(sc, ae.e1);
8945             Expression ae1old = ae.e1;
8946 
8947             const(bool) maybeSlice =
8948                 (ae.arguments.length == 0 ||
8949                  ae.arguments.length == 1 && (*ae.arguments)[0].op == EXP.interval);
8950 
8951             IntervalExp ie = null;
8952             if (maybeSlice && ae.arguments.length)
8953             {
8954                 assert((*ae.arguments)[0].op == EXP.interval);
8955                 ie = cast(IntervalExp)(*ae.arguments)[0];
8956             }
8957             Type att = null; // first cyclic `alias this` type
8958             while (true)
8959             {
8960                 if (ae.e1.op == EXP.error)
8961                     return setResult(ae.e1);
8962 
8963                 Expression e0 = null;
8964                 Expression ae1save = ae.e1;
8965                 ae.lengthVar = null;
8966 
8967                 Type t1b = ae.e1.type.toBasetype();
8968                 AggregateDeclaration ad = isAggregate(t1b);
8969                 if (!ad)
8970                     break;
8971                 if (search_function(ad, Id.indexass))
8972                 {
8973                     // Deal with $
8974                     res = resolveOpDollar(sc, ae, &e0);
8975                     if (!res) // a[i..j] = e2 might be: a.opSliceAssign(e2, i, j)
8976                         goto Lfallback;
8977                     if (res.op == EXP.error)
8978                         return setResult(res);
8979 
8980                     res = exp.e2.expressionSemantic(sc);
8981                     if (res.op == EXP.error)
8982                         return setResult(res);
8983                     exp.e2 = res;
8984 
8985                     /* Rewrite (a[arguments] = e2) as:
8986                      *      a.opIndexAssign(e2, arguments)
8987                      */
8988                     Expressions* a = ae.arguments.copy();
8989                     a.insert(0, exp.e2);
8990                     res = new DotIdExp(exp.loc, ae.e1, Id.indexass);
8991                     res = new CallExp(exp.loc, res, a);
8992                     if (maybeSlice) // a[] = e2 might be: a.opSliceAssign(e2)
8993                         res = res.trySemantic(sc);
8994                     else
8995                         res = res.expressionSemantic(sc);
8996                     if (res)
8997                         return setResult(Expression.combine(e0, res));
8998                 }
8999 
9000             Lfallback:
9001                 if (maybeSlice && search_function(ad, Id.sliceass))
9002                 {
9003                     // Deal with $
9004                     res = resolveOpDollar(sc, ae, ie, &e0);
9005                     if (res.op == EXP.error)
9006                         return setResult(res);
9007 
9008                     res = exp.e2.expressionSemantic(sc);
9009                     if (res.op == EXP.error)
9010                         return setResult(res);
9011 
9012                     exp.e2 = res;
9013 
9014                     /* Rewrite (a[i..j] = e2) as:
9015                      *      a.opSliceAssign(e2, i, j)
9016                      */
9017                     auto a = new Expressions();
9018                     a.push(exp.e2);
9019                     if (ie)
9020                     {
9021                         a.push(ie.lwr);
9022                         a.push(ie.upr);
9023                     }
9024                     res = new DotIdExp(exp.loc, ae.e1, Id.sliceass);
9025                     res = new CallExp(exp.loc, res, a);
9026                     res = res.expressionSemantic(sc);
9027                     return setResult(Expression.combine(e0, res));
9028                 }
9029 
9030                 // No operator overloading member function found yet, but
9031                 // there might be an alias this to try.
9032                 if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type))
9033                 {
9034                     /* Rewrite (a[arguments] op e2) as:
9035                      *      a.aliasthis[arguments] op e2
9036                      */
9037                     ae.e1 = resolveAliasThis(sc, ae1save, true);
9038                     if (ae.e1)
9039                         continue;
9040                 }
9041                 break;
9042             }
9043             ae.e1 = ae1old; // recovery
9044             ae.lengthVar = null;
9045         }
9046 
9047         /* Run this.e1 semantic.
9048          */
9049         {
9050             Expression e1x = exp.e1;
9051 
9052             /* With UFCS, e.f = value
9053              * Could mean:
9054              *      .f(e, value)
9055              * or:
9056              *      .f(e) = value
9057              */
9058             if (auto dti = e1x.isDotTemplateInstanceExp())
9059             {
9060                 Expression e = dti.dotTemplateSemanticProp(sc, DotExpFlag.gag);
9061                 if (!e)
9062                 {
9063                     return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9064                 }
9065 
9066                 e1x = e;
9067             }
9068             else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
9069             {
9070                 auto die = e1x.isDotIdExp();
9071                 e1x = fieldLookup(die.e1, sc, die.ident);
9072             }
9073             else if (auto die = e1x.isDotIdExp())
9074             {
9075                 Expression e = die.dotIdSemanticProp(sc, 1);
9076                 if (e && isDotOpDispatch(e))
9077                 {
9078                     /* https://issues.dlang.org/show_bug.cgi?id=19687
9079                      *
9080                      * On this branch, e2 is semantically analyzed in resolvePropertiesX,
9081                      * but that call is done with gagged errors. That is the only time when
9082                      * semantic gets ran on e2, that is why the error never gets to be printed.
9083                      * In order to make sure that UFCS is tried with correct parameters, e2
9084                      * needs to have semantic ran on it.
9085                      */
9086                     auto ode = e;
9087                     exp.e2 = exp.e2.expressionSemantic(sc);
9088                     uint errors = global.startGagging();
9089                     e = resolvePropertiesX(sc, e, exp.e2);
9090                     // Any error or if 'e' is not resolved, go to UFCS
9091                     if (global.endGagging(errors) || e is ode)
9092                         e = null; /* fall down to UFCS */
9093                     else
9094                         return setResult(e);
9095                 }
9096                 if (!e)
9097                     return setResult(resolveUFCSProperties(sc, e1x, exp.e2));
9098                 e1x = e;
9099             }
9100             else
9101             {
9102                 if (auto se = e1x.isSliceExp())
9103                     se.arrayop = true;
9104 
9105                 e1x = e1x.expressionSemantic(sc);
9106             }
9107 
9108             /* We have f = value.
9109              * Could mean:
9110              *      f(value)
9111              * or:
9112              *      f() = value
9113              */
9114             if (Expression e = resolvePropertiesX(sc, e1x, exp.e2, exp))
9115                 return setResult(e);
9116 
9117             if (e1x.checkRightThis(sc))
9118             {
9119                 return setError();
9120             }
9121             exp.e1 = e1x;
9122             assert(exp.e1.type);
9123         }
9124         Type t1 = exp.e1.type.isTypeEnum() ? exp.e1.type : exp.e1.type.toBasetype();
9125 
9126         /* Run this.e2 semantic.
9127          * Different from other binary expressions, the analysis of e2
9128          * depends on the result of e1 in assignments.
9129          */
9130         {
9131             Expression e2x = inferType(exp.e2, t1.baseElemOf());
9132             e2x = e2x.expressionSemantic(sc);
9133             if (!t1.isTypeSArray())
9134                 e2x = e2x.arrayFuncConv(sc);
9135             e2x = resolveProperties(sc, e2x);
9136             if (e2x.op == EXP.type)
9137                 e2x = resolveAliasThis(sc, e2x); //https://issues.dlang.org/show_bug.cgi?id=17684
9138             if (e2x.op == EXP.error)
9139                 return setResult(e2x);
9140             // We delay checking the value for structs/classes as these might have
9141             // an opAssign defined.
9142             if ((t1.ty != Tstruct && t1.ty != Tclass && e2x.checkValue()) ||
9143                 e2x.checkSharedAccess(sc))
9144                 return setError();
9145 
9146             auto etmp = checkNoreturnVarAccess(e2x);
9147             if (etmp != e2x)
9148                 return setResult(etmp);
9149 
9150             exp.e2 = e2x;
9151         }
9152 
9153         /* Rewrite tuple assignment as a tuple of assignments.
9154          */
9155         {
9156             Expression e2x = exp.e2;
9157 
9158         Ltupleassign:
9159             if (exp.e1.op == EXP.tuple && e2x.op == EXP.tuple)
9160             {
9161                 TupleExp tup1 = cast(TupleExp)exp.e1;
9162                 TupleExp tup2 = cast(TupleExp)e2x;
9163                 size_t dim = tup1.exps.length;
9164                 Expression e = null;
9165                 if (dim != tup2.exps.length)
9166                 {
9167                     exp.error("mismatched tuple lengths, %d and %d", cast(int)dim, cast(int)tup2.exps.length);
9168                     return setError();
9169                 }
9170                 if (dim == 0)
9171                 {
9172                     e = IntegerExp.literal!0;
9173                     e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error
9174                     e = Expression.combine(tup1.e0, tup2.e0, e);
9175                 }
9176                 else
9177                 {
9178                     auto exps = new Expressions(dim);
9179                     for (size_t i = 0; i < dim; i++)
9180                     {
9181                         Expression ex1 = (*tup1.exps)[i];
9182                         Expression ex2 = (*tup2.exps)[i];
9183                         (*exps)[i] = new AssignExp(exp.loc, ex1, ex2);
9184                     }
9185                     e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps);
9186                 }
9187                 return setResult(e.expressionSemantic(sc));
9188             }
9189 
9190             /* Look for form: e1 = e2.aliasthis.
9191              */
9192             if (exp.e1.op == EXP.tuple)
9193             {
9194                 TupleDeclaration td = isAliasThisTuple(e2x);
9195                 if (!td)
9196                     goto Lnomatch;
9197 
9198                 assert(exp.e1.type.ty == Ttuple);
9199                 TypeTuple tt = cast(TypeTuple)exp.e1.type;
9200 
9201                 Expression e0;
9202                 Expression ev = extractSideEffect(sc, "__tup", e0, e2x);
9203 
9204                 auto iexps = new Expressions();
9205                 iexps.push(ev);
9206                 for (size_t u = 0; u < iexps.length; u++)
9207                 {
9208                 Lexpand:
9209                     Expression e = (*iexps)[u];
9210 
9211                     Parameter arg = Parameter.getNth(tt.arguments, u);
9212                     //printf("[%d] iexps.length = %d, ", u, iexps.length);
9213                     //printf("e = (%s %s, %s), ", Token.toChars[e.op], e.toChars(), e.type.toChars());
9214                     //printf("arg = (%s, %s)\n", arg.toChars(), arg.type.toChars());
9215 
9216                     if (!arg || !e.type.implicitConvTo(arg.type))
9217                     {
9218                         // expand initializer to tuple
9219                         if (expandAliasThisTuples(iexps, u) != -1)
9220                         {
9221                             if (iexps.length <= u)
9222                                 break;
9223                             goto Lexpand;
9224                         }
9225                         goto Lnomatch;
9226                     }
9227                 }
9228                 e2x = new TupleExp(e2x.loc, e0, iexps);
9229                 e2x = e2x.expressionSemantic(sc);
9230                 if (e2x.op == EXP.error)
9231                 {
9232                     result = e2x;
9233                     return;
9234                 }
9235                 // Do not need to overwrite this.e2
9236                 goto Ltupleassign;
9237             }
9238         Lnomatch:
9239         }
9240 
9241         /* Inside constructor, if this is the first assignment of object field,
9242          * rewrite this to initializing the field.
9243          */
9244         if (exp.op == EXP.assign
9245             && exp.e1.checkModifiable(sc) == Modifiable.initialization)
9246         {
9247             //printf("[%s] change to init - %s\n", exp.loc.toChars(), exp.toChars());
9248             auto t = exp.type;
9249             exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
9250             exp.type = t;
9251 
9252             // https://issues.dlang.org/show_bug.cgi?id=13515
9253             // set Index::modifiable flag for complex AA element initialization
9254             if (auto ie1 = exp.e1.isIndexExp())
9255             {
9256                 Expression e1x = ie1.markSettingAAElem();
9257                 if (e1x.op == EXP.error)
9258                 {
9259                     result = e1x;
9260                     return;
9261                 }
9262             }
9263         }
9264         else if (exp.op == EXP.construct && exp.e1.op == EXP.variable &&
9265                  (cast(VarExp)exp.e1).var.storage_class & (STC.out_ | STC.ref_))
9266         {
9267             exp.memset = MemorySet.referenceInit;
9268         }
9269 
9270         if (exp.op == EXP.assign)  // skip EXP.blit and EXP.construct, which are initializations
9271         {
9272             exp.e1.checkSharedAccess(sc);
9273             checkUnsafeAccess(sc, exp.e1, false, true);
9274         }
9275 
9276         checkUnsafeAccess(sc, exp.e2, true, true); // Initializer must always be checked
9277 
9278         /* If it is an assignment from a 'foreign' type,
9279          * check for operator overloading.
9280          */
9281         if (exp.memset == MemorySet.referenceInit)
9282         {
9283             // If this is an initialization of a reference,
9284             // do nothing
9285         }
9286         else if (t1.ty == Tstruct)
9287         {
9288             auto e1x = exp.e1;
9289             auto e2x = exp.e2;
9290             auto sd = (cast(TypeStruct)t1).sym;
9291 
9292             if (exp.op == EXP.construct)
9293             {
9294                 Type t2 = e2x.type.toBasetype();
9295                 if (t2.ty == Tstruct && sd == (cast(TypeStruct)t2).sym)
9296                 {
9297                     sd.size(exp.loc);
9298                     if (sd.sizeok != Sizeok.done)
9299                         return setError();
9300                     if (!sd.ctor)
9301                         sd.ctor = sd.searchCtor();
9302 
9303                     // https://issues.dlang.org/show_bug.cgi?id=15661
9304                     // Look for the form from last of comma chain.
9305                     auto e2y = lastComma(e2x);
9306 
9307                     CallExp ce = (e2y.op == EXP.call) ? cast(CallExp)e2y : null;
9308                     DotVarExp dve = (ce && ce.e1.op == EXP.dotVariable)
9309                         ? cast(DotVarExp)ce.e1 : null;
9310                     if (sd.ctor && ce && dve && dve.var.isCtorDeclaration() &&
9311                         // https://issues.dlang.org/show_bug.cgi?id=19389
9312                         dve.e1.op != EXP.dotVariable &&
9313                         e2y.type.implicitConvTo(t1))
9314                     {
9315                         /* Look for form of constructor call which is:
9316                          *    __ctmp.ctor(arguments...)
9317                          */
9318 
9319                         /* Before calling the constructor, initialize
9320                          * variable with a bit copy of the default
9321                          * initializer
9322                          */
9323                         Expression einit = getInitExp(sd, exp.loc, sc, t1);
9324                         if (einit.op == EXP.error)
9325                         {
9326                             result = einit;
9327                             return;
9328                         }
9329 
9330                         auto ae = new BlitExp(exp.loc, exp.e1, einit);
9331                         ae.type = e1x.type;
9332 
9333                         /* Replace __ctmp being constructed with e1.
9334                          * We need to copy constructor call expression,
9335                          * because it may be used in other place.
9336                          */
9337                         auto dvx = cast(DotVarExp)dve.copy();
9338                         dvx.e1 = e1x;
9339                         auto cx = cast(CallExp)ce.copy();
9340                         cx.e1 = dvx;
9341                         if (checkConstructorEscape(sc, cx, false))
9342                             return setError();
9343 
9344                         Expression e0;
9345                         Expression.extractLast(e2x, e0);
9346 
9347                         auto e = Expression.combine(e0, ae, cx);
9348                         e = e.expressionSemantic(sc);
9349                         result = e;
9350                         return;
9351                     }
9352                     // https://issues.dlang.org/show_bug.cgi?id=21586
9353                     // Rewrite CondExp or e1 will miss direct construction, e.g.
9354                     // e1 = a ? S(1) : ...; -> AST: e1 = a ? (S(0)).this(1) : ...;
9355                     // a temporary created and an extra destructor call.
9356                     // AST will be rewritten to:
9357                     // a ? e1 = 0, e1.this(1) : ...; -> blitting plus construction
9358                     if (e2x.op == EXP.question)
9359                     {
9360                         /* Rewrite as:
9361                          *  a ? e1 = b : e1 = c;
9362                          */
9363                         CondExp econd = cast(CondExp)e2x;
9364                         Expression ea1 = new ConstructExp(econd.e1.loc, e1x, econd.e1);
9365                         Expression ea2 = new ConstructExp(econd.e2.loc, e1x, econd.e2);
9366                         Expression e = new CondExp(exp.loc, econd.econd, ea1, ea2);
9367                         result = e.expressionSemantic(sc);
9368                         return;
9369                     }
9370                     if (sd.postblit || sd.hasCopyCtor)
9371                     {
9372                         /* We have a copy constructor for this
9373                          */
9374 
9375                         if (e2x.isLvalue())
9376                         {
9377                             if (sd.hasCopyCtor)
9378                             {
9379                                 /* Rewrite as:
9380                                  * e1 = init, e1.copyCtor(e2);
9381                                  */
9382                                 Expression einit = new BlitExp(exp.loc, exp.e1, getInitExp(sd, exp.loc, sc, t1));
9383                                 einit.type = e1x.type;
9384 
9385                                 Expression e;
9386                                 e = new DotIdExp(exp.loc, e1x, Id.ctor);
9387                                 e = new CallExp(exp.loc, e, e2x);
9388                                 e = new CommaExp(exp.loc, einit, e);
9389 
9390                                 //printf("e: %s\n", e.toChars());
9391 
9392                                 result = e.expressionSemantic(sc);
9393                                 return;
9394                             }
9395                             else
9396                             {
9397                                 if (!e2x.type.implicitConvTo(e1x.type))
9398                                 {
9399                                     exp.error("conversion error from `%s` to `%s`",
9400                                         e2x.type.toChars(), e1x.type.toChars());
9401                                     return setError();
9402                                 }
9403 
9404                                 /* Rewrite as:
9405                                  *  (e1 = e2).postblit();
9406                                  *
9407                                  * Blit assignment e1 = e2 returns a reference to the original e1,
9408                                  * then call the postblit on it.
9409                                  */
9410                                 Expression e = e1x.copy();
9411                                 e.type = e.type.mutableOf();
9412                                 if (e.type.isShared && !sd.type.isShared)
9413                                     e.type = e.type.unSharedOf();
9414                                 e = new BlitExp(exp.loc, e, e2x);
9415                                 e = new DotVarExp(exp.loc, e, sd.postblit, false);
9416                                 e = new CallExp(exp.loc, e);
9417                                 result = e.expressionSemantic(sc);
9418                                 return;
9419                             }
9420                         }
9421                         else
9422                         {
9423                             /* The struct value returned from the function is transferred
9424                              * so should not call the destructor on it.
9425                              */
9426                             e2x = valueNoDtor(e2x);
9427                         }
9428                     }
9429 
9430                     // https://issues.dlang.org/show_bug.cgi?id=19251
9431                     // if e2 cannot be converted to e1.type, maybe there is an alias this
9432                     if (!e2x.implicitConvTo(t1))
9433                     {
9434                         AggregateDeclaration ad2 = isAggregate(e2x.type);
9435                         if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9436                         {
9437                             /* Rewrite (e1 op e2) as:
9438                              *      (e1 op e2.aliasthis)
9439                              */
9440                             exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9441                             result = exp.expressionSemantic(sc);
9442                             return;
9443                         }
9444                     }
9445                 }
9446                 else if (!e2x.implicitConvTo(t1))
9447                 {
9448                     sd.size(exp.loc);
9449                     if (sd.sizeok != Sizeok.done)
9450                         return setError();
9451                     if (!sd.ctor)
9452                         sd.ctor = sd.searchCtor();
9453 
9454                     if (sd.ctor)
9455                     {
9456                         /* Look for implicit constructor call
9457                          * Rewrite as:
9458                          *  e1 = init, e1.ctor(e2)
9459                          */
9460 
9461                         /* Fix Issue 5153 : https://issues.dlang.org/show_bug.cgi?id=5153
9462                          * Using `new` to initialize a struct object is a common mistake, but
9463                          * the error message from the compiler is not very helpful in that
9464                          * case. If exp.e2 is a NewExp and the type of new is the same as
9465                          * the type as exp.e1 (struct in this case), then we know for sure
9466                          * that the user wants to instantiate a struct. This is done to avoid
9467                          * issuing an error when the user actually wants to call a constructor
9468                          * which receives a class object.
9469                          *
9470                          * Foo f = new Foo2(0); is a valid expression if Foo has a constructor
9471                          * which receives an instance of a Foo2 class
9472                          */
9473                         if (exp.e2.op == EXP.new_)
9474                         {
9475                             auto newExp = cast(NewExp)(exp.e2);
9476                             if (newExp.newtype && newExp.newtype == t1)
9477                             {
9478                                 error(exp.loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
9479                                       newExp.toChars(), newExp.type.toChars(), t1.toChars());
9480                                 errorSupplemental(exp.loc, "Perhaps remove the `new` keyword?");
9481                                 return setError();
9482                             }
9483                         }
9484 
9485                         Expression einit = new BlitExp(exp.loc, e1x, getInitExp(sd, exp.loc, sc, t1));
9486                         einit.type = e1x.type;
9487 
9488                         Expression e;
9489                         e = new DotIdExp(exp.loc, e1x, Id.ctor);
9490                         e = new CallExp(exp.loc, e, e2x);
9491                         e = new CommaExp(exp.loc, einit, e);
9492                         e = e.expressionSemantic(sc);
9493                         result = e;
9494                         return;
9495                     }
9496                     if (search_function(sd, Id.call))
9497                     {
9498                         /* Look for static opCall
9499                          * https://issues.dlang.org/show_bug.cgi?id=2702
9500                          * Rewrite as:
9501                          *  e1 = typeof(e1).opCall(arguments)
9502                          */
9503                         e2x = typeDotIdExp(e2x.loc, e1x.type, Id.call);
9504                         e2x = new CallExp(exp.loc, e2x, exp.e2);
9505 
9506                         e2x = e2x.expressionSemantic(sc);
9507                         e2x = resolveProperties(sc, e2x);
9508                         if (e2x.op == EXP.error)
9509                         {
9510                             result = e2x;
9511                             return;
9512                         }
9513                         if (e2x.checkValue() || e2x.checkSharedAccess(sc))
9514                             return setError();
9515                     }
9516                 }
9517                 else // https://issues.dlang.org/show_bug.cgi?id=11355
9518                 {
9519                     AggregateDeclaration ad2 = isAggregate(e2x.type);
9520                     if (ad2 && ad2.aliasthis && !isRecursiveAliasThis(exp.att2, exp.e2.type))
9521                     {
9522                         /* Rewrite (e1 op e2) as:
9523                          *      (e1 op e2.aliasthis)
9524                          */
9525                         exp.e2 = new DotIdExp(exp.e2.loc, exp.e2, ad2.aliasthis.ident);
9526                         result = exp.expressionSemantic(sc);
9527                         return;
9528                     }
9529                 }
9530             }
9531             else if (exp.op == EXP.assign)
9532             {
9533                 if (e1x.op == EXP.index && (cast(IndexExp)e1x).e1.type.toBasetype().ty == Taarray)
9534                 {
9535                     /*
9536                      * Rewrite:
9537                      *      aa[key] = e2;
9538                      * as:
9539                      *      ref __aatmp = aa;
9540                      *      ref __aakey = key;
9541                      *      ref __aaval = e2;
9542                      *      (__aakey in __aatmp
9543                      *          ? __aatmp[__aakey].opAssign(__aaval)
9544                      *          : ConstructExp(__aatmp[__aakey], __aaval));
9545                      */
9546                     // ensure we keep the expr modifiable
9547                     Expression esetting = (cast(IndexExp)e1x).markSettingAAElem();
9548                     if (esetting.op == EXP.error)
9549                     {
9550                         result = esetting;
9551                         return;
9552                     }
9553                     assert(esetting.op == EXP.index);
9554                     IndexExp ie = cast(IndexExp) esetting;
9555                     Type t2 = e2x.type.toBasetype();
9556 
9557                     Expression e0 = null;
9558                     Expression ea = extractSideEffect(sc, "__aatmp", e0, ie.e1);
9559                     Expression ek = extractSideEffect(sc, "__aakey", e0, ie.e2);
9560                     Expression ev = extractSideEffect(sc, "__aaval", e0, e2x);
9561 
9562                     AssignExp ae = cast(AssignExp)exp.copy();
9563                     ae.e1 = new IndexExp(exp.loc, ea, ek);
9564                     ae.e1 = ae.e1.expressionSemantic(sc);
9565                     ae.e1 = ae.e1.optimize(WANTvalue);
9566                     ae.e2 = ev;
9567                     Expression e = ae.op_overload(sc);
9568                     if (e)
9569                     {
9570                         Expression ey = null;
9571                         if (t2.ty == Tstruct && sd == t2.toDsymbol(sc))
9572                         {
9573                             ey = ev;
9574                         }
9575                         else if (!ev.implicitConvTo(ie.type) && sd.ctor)
9576                         {
9577                             // Look for implicit constructor call
9578                             // Rewrite as S().ctor(e2)
9579                             ey = new StructLiteralExp(exp.loc, sd, null);
9580                             ey = new DotIdExp(exp.loc, ey, Id.ctor);
9581                             ey = new CallExp(exp.loc, ey, ev);
9582                             ey = ey.trySemantic(sc);
9583                         }
9584                         if (ey)
9585                         {
9586                             Expression ex;
9587                             ex = new IndexExp(exp.loc, ea, ek);
9588                             ex = ex.expressionSemantic(sc);
9589                             ex = ex.modifiableLvalue(sc, ex); // allocate new slot
9590                             ex = ex.optimize(WANTvalue);
9591 
9592                             ey = new ConstructExp(exp.loc, ex, ey);
9593                             ey = ey.expressionSemantic(sc);
9594                             if (ey.op == EXP.error)
9595                             {
9596                                 result = ey;
9597                                 return;
9598                             }
9599                             ex = e;
9600 
9601                             // https://issues.dlang.org/show_bug.cgi?id=14144
9602                             // The whole expression should have the common type
9603                             // of opAssign() return and assigned AA entry.
9604                             // Even if there's no common type, expression should be typed as void.
9605                             if (!typeMerge(sc, EXP.question, ex, ey))
9606                             {
9607                                 ex = new CastExp(ex.loc, ex, Type.tvoid);
9608                                 ey = new CastExp(ey.loc, ey, Type.tvoid);
9609                             }
9610                             e = new CondExp(exp.loc, new InExp(exp.loc, ek, ea), ex, ey);
9611                         }
9612                         e = Expression.combine(e0, e);
9613                         e = e.expressionSemantic(sc);
9614                         result = e;
9615                         return;
9616                     }
9617                 }
9618                 else
9619                 {
9620                     Expression e = exp.op_overload(sc);
9621                     if (e)
9622                     {
9623                         result = e;
9624                         return;
9625                     }
9626                 }
9627             }
9628             else
9629                 assert(exp.op == EXP.blit);
9630 
9631             if (e2x.checkValue())
9632                 return setError();
9633 
9634             exp.e1 = e1x;
9635             exp.e2 = e2x;
9636         }
9637         else if (t1.ty == Tclass)
9638         {
9639             // Disallow assignment operator overloads for same type
9640             if (exp.op == EXP.assign && !exp.e2.implicitConvTo(exp.e1.type))
9641             {
9642                 Expression e = exp.op_overload(sc);
9643                 if (e)
9644                 {
9645                     result = e;
9646                     return;
9647                 }
9648             }
9649             if (exp.e2.checkValue())
9650                 return setError();
9651         }
9652         else if (t1.ty == Tsarray)
9653         {
9654             // SliceExp cannot have static array type without context inference.
9655             assert(exp.e1.op != EXP.slice);
9656             Expression e1x = exp.e1;
9657             Expression e2x = exp.e2;
9658 
9659             /* C strings come through as static arrays. May need to adjust the size of the
9660              * string to match the size of e1.
9661              */
9662             Type t2 = e2x.type.toBasetype();
9663             if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
9664             {
9665                 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
9666                 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
9667                 if (dim1 + 1 == dim2 || dim2 < dim1)
9668                 {
9669                     auto tsa2 = t2.isTypeSArray();
9670                     auto newt = tsa2.next.sarrayOf(dim1).immutableOf();
9671                     e2x = castTo(e2x, sc, newt);
9672                     exp.e2 = e2x;
9673                 }
9674             }
9675 
9676             if (e2x.implicitConvTo(e1x.type))
9677             {
9678                 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()))
9679                 {
9680                     if (e1x.checkPostblit(sc, t1))
9681                         return setError();
9682                 }
9683 
9684                 // e2 matches to t1 because of the implicit length match, so
9685                 if (isUnaArrayOp(e2x.op) || isBinArrayOp(e2x.op))
9686                 {
9687                     // convert e1 to e1[]
9688                     // e.g. e1[] = a[] + b[];
9689                     auto sle = new SliceExp(e1x.loc, e1x, null, null);
9690                     sle.arrayop = true;
9691                     e1x = sle.expressionSemantic(sc);
9692                 }
9693                 else
9694                 {
9695                     // convert e2 to t1 later
9696                     // e.g. e1 = [1, 2, 3];
9697                 }
9698             }
9699             else
9700             {
9701                 if (e2x.implicitConvTo(t1.nextOf().arrayOf()) > MATCH.nomatch)
9702                 {
9703                     uinteger_t dim1 = (cast(TypeSArray)t1).dim.toInteger();
9704                     uinteger_t dim2 = dim1;
9705                     if (auto ale = e2x.isArrayLiteralExp())
9706                     {
9707                         dim2 = ale.elements ? ale.elements.length : 0;
9708                     }
9709                     else if (auto se = e2x.isSliceExp())
9710                     {
9711                         Type tx = toStaticArrayType(se);
9712                         if (tx)
9713                             dim2 = (cast(TypeSArray)tx).dim.toInteger();
9714                     }
9715                     if (dim1 != dim2)
9716                     {
9717                         exp.error("mismatched array lengths, %d and %d", cast(int)dim1, cast(int)dim2);
9718                         return setError();
9719                     }
9720                 }
9721 
9722                 // May be block or element-wise assignment, so
9723                 // convert e1 to e1[]
9724                 if (exp.op != EXP.assign)
9725                 {
9726                     // If multidimensional static array, treat as one large array
9727                     //
9728                     // Find the appropriate array type depending on the assignment, e.g.
9729                     // int[3] = int => int[3]
9730                     // int[3][2] = int => int[6]
9731                     // int[3][2] = int[] => int[3][2]
9732                     // int[3][2][4] + int => int[24]
9733                     // int[3][2][4] + int[] => int[3][8]
9734                     ulong dim = t1.isTypeSArray().dim.toUInteger();
9735                     auto type = t1.nextOf();
9736 
9737                     for (TypeSArray tsa; (tsa = type.isTypeSArray()) !is null; )
9738                     {
9739                         import core.checkedint : mulu;
9740 
9741                         // Accumulate skipped dimensions
9742                         bool overflow = false;
9743                         dim = mulu(dim, tsa.dim.toUInteger(), overflow);
9744                         if (overflow || dim >= uint.max)
9745                         {
9746                             // dym exceeds maximum array size
9747                             exp.error("static array `%s` size overflowed to %llu",
9748                                         e1x.type.toChars(), cast(ulong) dim);
9749                             return setError();
9750                         }
9751 
9752                         // Move to the element type
9753                         type = tsa.nextOf().toBasetype();
9754 
9755                         // Rewrite ex1 as a static array if a matching type was found
9756                         if (e2x.implicitConvTo(type) > MATCH.nomatch)
9757                         {
9758                             e1x.type = type.sarrayOf(dim);
9759                             break;
9760                         }
9761                     }
9762                 }
9763                 auto sle = new SliceExp(e1x.loc, e1x, null, null);
9764                 sle.arrayop = true;
9765                 e1x = sle.expressionSemantic(sc);
9766             }
9767             if (e1x.op == EXP.error)
9768                 return setResult(e1x);
9769             if (e2x.op == EXP.error)
9770                 return setResult(e2x);
9771 
9772             exp.e1 = e1x;
9773             exp.e2 = e2x;
9774             t1 = e1x.type.toBasetype();
9775         }
9776         /* Check the mutability of e1.
9777          */
9778         if (auto ale = exp.e1.isArrayLengthExp())
9779         {
9780             // e1 is not an lvalue, but we let code generator handle it
9781 
9782             auto ale1x = ale.e1.modifiableLvalue(sc, exp.e1);
9783             if (ale1x.op == EXP.error)
9784                 return setResult(ale1x);
9785             ale.e1 = ale1x;
9786 
9787             Type tn = ale.e1.type.toBasetype().nextOf();
9788             checkDefCtor(ale.loc, tn);
9789 
9790             Identifier hook = global.params.tracegc ? Id._d_arraysetlengthTTrace : Id._d_arraysetlengthT;
9791             if (!verifyHookExist(exp.loc, *sc, Id._d_arraysetlengthTImpl, "resizing arrays"))
9792                 return setError();
9793 
9794             exp.e2 = exp.e2.expressionSemantic(sc);
9795             auto lc = lastComma(exp.e2);
9796             lc = lc.optimize(WANTvalue);
9797             // use slice expression when arr.length = 0 to avoid runtime call
9798             if(lc.op == EXP.int64 && lc.toInteger() == 0)
9799             {
9800                 Expression se = new SliceExp(ale.loc, ale.e1, lc, lc);
9801                 Expression as = new AssignExp(ale.loc, ale.e1, se);
9802                 as = as.expressionSemantic(sc);
9803                 auto res = Expression.combine(as, exp.e2);
9804                 res.type = ale.type;
9805                 return setResult(res);
9806             }
9807 
9808             if (!sc.needsCodegen())      // if compile time creature only
9809             {
9810                 exp.type = Type.tsize_t;
9811                 return setResult(exp);
9812             }
9813 
9814             // Lower to object._d_arraysetlengthTImpl!(typeof(e1))._d_arraysetlengthT{,Trace}(e1, e2)
9815             Expression id = new IdentifierExp(ale.loc, Id.empty);
9816             id = new DotIdExp(ale.loc, id, Id.object);
9817             auto tiargs = new Objects();
9818             tiargs.push(ale.e1.type);
9819             id = new DotTemplateInstanceExp(ale.loc, id, Id._d_arraysetlengthTImpl, tiargs);
9820             id = new DotIdExp(ale.loc, id, hook);
9821             id = id.expressionSemantic(sc);
9822 
9823             auto arguments = new Expressions();
9824             arguments.reserve(5);
9825             if (global.params.tracegc)
9826             {
9827                 auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
9828                 arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
9829                 arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
9830                 arguments.push(new StringExp(exp.loc, funcname.toDString()));
9831             }
9832             arguments.push(ale.e1);
9833             arguments.push(exp.e2);
9834 
9835             Expression ce = new CallExp(ale.loc, id, arguments).expressionSemantic(sc);
9836             auto res = new LoweredAssignExp(exp, ce);
9837             // if (global.params.verbose)
9838             //     message("lowered   %s =>\n          %s", exp.toChars(), res.toChars());
9839             res.type = Type.tsize_t;
9840             return setResult(res);
9841         }
9842         else if (auto se = exp.e1.isSliceExp())
9843         {
9844             Type tn = se.type.nextOf();
9845             const fun = sc.func;
9846             if (exp.op == EXP.assign && !tn.isMutable() &&
9847                 // allow modifiation in module ctor, see
9848                 // https://issues.dlang.org/show_bug.cgi?id=9884
9849                 (!fun || (fun && !fun.isStaticCtorDeclaration())))
9850             {
9851                 exp.error("slice `%s` is not mutable", se.toChars());
9852                 return setError();
9853             }
9854 
9855             if (exp.op == EXP.assign && !tn.baseElemOf().isAssignable())
9856             {
9857                 exp.error("slice `%s` is not mutable, struct `%s` has immutable members",
9858                     exp.e1.toChars(), tn.baseElemOf().toChars());
9859                 result = ErrorExp.get();
9860                 return;
9861             }
9862 
9863             // For conditional operator, both branches need conversion.
9864             while (se.e1.op == EXP.slice)
9865                 se = cast(SliceExp)se.e1;
9866             if (se.e1.op == EXP.question && se.e1.type.toBasetype().ty == Tsarray)
9867             {
9868                 se.e1 = se.e1.modifiableLvalue(sc, exp.e1);
9869                 if (se.e1.op == EXP.error)
9870                     return setResult(se.e1);
9871             }
9872         }
9873         else
9874         {
9875             if (t1.ty == Tsarray && exp.op == EXP.assign)
9876             {
9877                 Type tn = exp.e1.type.nextOf();
9878                 if (tn && !tn.baseElemOf().isAssignable())
9879                 {
9880                     exp.error("array `%s` is not mutable, struct `%s` has immutable members",
9881                         exp.e1.toChars(), tn.baseElemOf().toChars());
9882                     result = ErrorExp.get();
9883                     return;
9884                 }
9885             }
9886 
9887             Expression e1x = exp.e1;
9888 
9889             // Try to do a decent error message with the expression
9890             // before it gets constant folded
9891             if (exp.op == EXP.assign)
9892                 e1x = e1x.modifiableLvalue(sc, e1old);
9893 
9894             e1x = e1x.optimize(WANTvalue, /*keepLvalue*/ true);
9895 
9896             if (e1x.op == EXP.error)
9897             {
9898                 result = e1x;
9899                 return;
9900             }
9901             exp.e1 = e1x;
9902         }
9903 
9904         /* Tweak e2 based on the type of e1.
9905          */
9906         Expression e2x = exp.e2;
9907         Type t2 = e2x.type.toBasetype();
9908 
9909         // If it is a array, get the element type. Note that it may be
9910         // multi-dimensional.
9911         Type telem = t1;
9912         while (telem.ty == Tarray)
9913             telem = telem.nextOf();
9914 
9915         if (exp.e1.op == EXP.slice && t1.nextOf() &&
9916             (telem.ty != Tvoid || e2x.op == EXP.null_) &&
9917             e2x.implicitConvTo(t1.nextOf()))
9918         {
9919             // Check for block assignment. If it is of type void[], void[][], etc,
9920             // '= null' is the only allowable block assignment (Bug 7493)
9921             exp.memset = MemorySet.blockAssign;    // make it easy for back end to tell what this is
9922             e2x = e2x.implicitCastTo(sc, t1.nextOf());
9923             if (exp.op != EXP.blit && e2x.isLvalue() && exp.e1.checkPostblit(sc, t1.nextOf()))
9924                 return setError();
9925         }
9926         else if (exp.e1.op == EXP.slice &&
9927                  (t2.ty == Tarray || t2.ty == Tsarray) &&
9928                  t2.nextOf().implicitConvTo(t1.nextOf()))
9929         {
9930             // Check element-wise assignment.
9931 
9932             /* If assigned elements number is known at compile time,
9933              * check the mismatch.
9934              */
9935             SliceExp se1 = cast(SliceExp)exp.e1;
9936             TypeSArray tsa1 = cast(TypeSArray)toStaticArrayType(se1);
9937             TypeSArray tsa2 = null;
9938             if (auto ale = e2x.isArrayLiteralExp())
9939                 tsa2 = cast(TypeSArray)t2.nextOf().sarrayOf(ale.elements.length);
9940             else if (auto se = e2x.isSliceExp())
9941                 tsa2 = cast(TypeSArray)toStaticArrayType(se);
9942             else
9943                 tsa2 = t2.isTypeSArray();
9944 
9945             if (tsa1 && tsa2)
9946             {
9947                 uinteger_t dim1 = tsa1.dim.toInteger();
9948                 uinteger_t dim2 = tsa2.dim.toInteger();
9949                 if (dim1 != dim2)
9950                 {
9951                     exp.error("mismatched array lengths %d and %d for assignment `%s`", cast(int)dim1, cast(int)dim2, exp.toChars());
9952                     return setError();
9953                 }
9954             }
9955 
9956             if (exp.op != EXP.blit &&
9957                 (e2x.op == EXP.slice && (cast(UnaExp)e2x).e1.isLvalue() ||
9958                  e2x.op == EXP.cast_ && (cast(UnaExp)e2x).e1.isLvalue() ||
9959                  e2x.op != EXP.slice && e2x.isLvalue()))
9960             {
9961                 if (exp.e1.checkPostblit(sc, t1.nextOf()))
9962                     return setError();
9963             }
9964 
9965             if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
9966                 e2x.op != EXP.slice && e2x.op != EXP.assign &&
9967                 e2x.op != EXP.arrayLiteral && e2x.op != EXP.string_ &&
9968                 !(e2x.op == EXP.add || e2x.op == EXP.min ||
9969                   e2x.op == EXP.mul || e2x.op == EXP.div ||
9970                   e2x.op == EXP.mod || e2x.op == EXP.xor ||
9971                   e2x.op == EXP.and || e2x.op == EXP.or ||
9972                   e2x.op == EXP.pow ||
9973                   e2x.op == EXP.tilde || e2x.op == EXP.negate))
9974             {
9975                 const(char)* e1str = exp.e1.toChars();
9976                 const(char)* e2str = e2x.toChars();
9977                 exp.warning("explicit element-wise assignment `%s = (%s)[]` is better than `%s = %s`", e1str, e2str, e1str, e2str);
9978             }
9979 
9980             Type t2n = t2.nextOf();
9981             Type t1n = t1.nextOf();
9982             int offset;
9983             if (t2n.equivalent(t1n) ||
9984                 t1n.isBaseOf(t2n, &offset) && offset == 0)
9985             {
9986                 /* Allow copy of distinct qualifier elements.
9987                  * eg.
9988                  *  char[] dst;  const(char)[] src;
9989                  *  dst[] = src;
9990                  *
9991                  *  class C {}   class D : C {}
9992                  *  C[2] ca;  D[] da;
9993                  *  ca[] = da;
9994                  */
9995                 if (isArrayOpValid(e2x))
9996                 {
9997                     // Don't add CastExp to keep AST for array operations
9998                     e2x = e2x.copy();
9999                     e2x.type = exp.e1.type.constOf();
10000                 }
10001                 else
10002                     e2x = e2x.castTo(sc, exp.e1.type.constOf());
10003             }
10004             else
10005             {
10006                 /* https://issues.dlang.org/show_bug.cgi?id=15778
10007                  * A string literal has an array type of immutable
10008                  * elements by default, and normally it cannot be convertible to
10009                  * array type of mutable elements. But for element-wise assignment,
10010                  * elements need to be const at best. So we should give a chance
10011                  * to change code unit size for polysemous string literal.
10012                  */
10013                 if (e2x.op == EXP.string_)
10014                     e2x = e2x.implicitCastTo(sc, exp.e1.type.constOf());
10015                 else
10016                     e2x = e2x.implicitCastTo(sc, exp.e1.type);
10017             }
10018             if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
10019             {
10020                 if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
10021                     return setError();
10022             }
10023         }
10024         else
10025         {
10026             if (0 && global.params.warnings != DiagnosticReporting.off && !global.gag && exp.op == EXP.assign &&
10027                 t1.ty == Tarray && t2.ty == Tsarray &&
10028                 e2x.op != EXP.slice &&
10029                 t2.implicitConvTo(t1))
10030             {
10031                 // Disallow ar[] = sa (Converted to ar[] = sa[])
10032                 // Disallow da   = sa (Converted to da   = sa[])
10033                 const(char)* e1str = exp.e1.toChars();
10034                 const(char)* e2str = e2x.toChars();
10035                 const(char)* atypestr = exp.e1.op == EXP.slice ? "element-wise" : "slice";
10036                 exp.warning("explicit %s assignment `%s = (%s)[]` is better than `%s = %s`", atypestr, e1str, e2str, e1str, e2str);
10037             }
10038             if (exp.op == EXP.blit)
10039                 e2x = e2x.castTo(sc, exp.e1.type);
10040             else
10041             {
10042                 e2x = e2x.implicitCastTo(sc, exp.e1.type);
10043 
10044                 // Fix Issue 13435: https://issues.dlang.org/show_bug.cgi?id=13435
10045 
10046                 // If the implicit cast has failed and the assign expression is
10047                 // the initialization of a struct member field
10048                 if (e2x.op == EXP.error && exp.op == EXP.construct && t1.ty == Tstruct)
10049                 {
10050                     scope sd = (cast(TypeStruct)t1).sym;
10051                     Dsymbol opAssign = search_function(sd, Id.assign);
10052 
10053                     // and the struct defines an opAssign
10054                     if (opAssign)
10055                     {
10056                         // offer more information about the cause of the problem
10057                         errorSupplemental(exp.loc,
10058                                           "`%s` is the first assignment of `%s` therefore it represents its initialization",
10059                                           exp.toChars(), exp.e1.toChars());
10060                         errorSupplemental(exp.loc,
10061                                           "`opAssign` methods are not used for initialization, but for subsequent assignments");
10062                     }
10063                 }
10064             }
10065         }
10066         if (e2x.op == EXP.error)
10067         {
10068             result = e2x;
10069             return;
10070         }
10071         exp.e2 = e2x;
10072         t2 = exp.e2.type.toBasetype();
10073 
10074         /* Look for array operations
10075          */
10076         if ((t2.ty == Tarray || t2.ty == Tsarray) && isArrayOpValid(exp.e2))
10077         {
10078             // Look for valid array operations
10079             if (exp.memset != MemorySet.blockAssign &&
10080                 exp.e1.op == EXP.slice &&
10081                 (isUnaArrayOp(exp.e2.op) || isBinArrayOp(exp.e2.op)))
10082             {
10083                 exp.type = exp.e1.type;
10084                 if (exp.op == EXP.construct) // https://issues.dlang.org/show_bug.cgi?id=10282
10085                                         // tweak mutability of e1 element
10086                     exp.e1.type = exp.e1.type.nextOf().mutableOf().arrayOf();
10087                 result = arrayOp(exp, sc);
10088                 return;
10089             }
10090 
10091             // Drop invalid array operations in e2
10092             //  d = a[] + b[], d = (a[] + b[])[0..2], etc
10093             if (checkNonAssignmentArrayOp(exp.e2, exp.memset != MemorySet.blockAssign && exp.op == EXP.assign))
10094                 return setError();
10095 
10096             // Remains valid array assignments
10097             //  d = d[], d = [1,2,3], etc
10098         }
10099 
10100         /* Don't allow assignment to classes that were allocated on the stack with:
10101          *      scope Class c = new Class();
10102          */
10103         if (exp.e1.op == EXP.variable && exp.op == EXP.assign)
10104         {
10105             VarExp ve = cast(VarExp)exp.e1;
10106             VarDeclaration vd = ve.var.isVarDeclaration();
10107             if (vd && vd.onstack)
10108             {
10109                 assert(t1.ty == Tclass);
10110                 exp.error("cannot rebind scope variables");
10111             }
10112         }
10113 
10114         if (exp.e1.op == EXP.variable && (cast(VarExp)exp.e1).var.ident == Id.ctfe)
10115         {
10116             exp.error("cannot modify compiler-generated variable `__ctfe`");
10117         }
10118 
10119         exp.type = exp.e1.type;
10120         assert(exp.type);
10121         auto assignElem = exp.e2;
10122         auto res = exp.op == EXP.assign ? exp.reorderSettingAAElem(sc) : exp;
10123         /* https://issues.dlang.org/show_bug.cgi?id=22366
10124          *
10125          * `reorderSettingAAElem` creates a tree of comma expressions, however,
10126          * `checkAssignExp` expects only AssignExps.
10127          */
10128         if (res == exp) // no `AA[k] = v` rewrite was performed
10129             checkAssignEscape(sc, res, false, false);
10130         else
10131             checkNewEscape(sc, assignElem, false); // assigning to AA puts it on heap
10132 
10133         if (auto ae = res.isConstructExp())
10134         {
10135             Type t1b = ae.e1.type.toBasetype();
10136             if (t1b.ty != Tsarray && t1b.ty != Tarray)
10137                 return setResult(res);
10138 
10139             // only non-trivial array constructions may need to be lowered (non-POD elements basically)
10140             Type t1e = t1b.nextOf();
10141             TypeStruct ts = t1e.baseElemOf().isTypeStruct();
10142             if (!ts || (!ts.sym.postblit && !ts.sym.hasCopyCtor && !ts.sym.dtor))
10143                 return setResult(res);
10144 
10145             // don't lower ref-constructions etc.
10146             if (!(t1b.ty == Tsarray || ae.e1.isSliceExp) ||
10147                 (ae.e1.isVarExp && ae.e1.isVarExp.var.isVarDeclaration.isReference))
10148                 return setResult(res);
10149 
10150             // Construction from an equivalent other array?
10151             // Only lower with lvalue RHS elements; let the glue layer move rvalue elements.
10152             Type t2b = ae.e2.type.toBasetype();
10153             // skip over a (possibly implicit) cast of a static array RHS to a slice
10154             Expression rhs = ae.e2;
10155             Type rhsType = t2b;
10156             if (t2b.ty == Tarray)
10157             {
10158                 if (auto ce = rhs.isCastExp())
10159                 {
10160                     auto ct = ce.e1.type.toBasetype();
10161                     if (ct.ty == Tsarray)
10162                     {
10163                         rhs = ce.e1;
10164                         rhsType = ct;
10165                     }
10166                 }
10167             }
10168 
10169             if (!sc.needsCodegen()) // interpreter can handle these
10170                 return setResult(res);
10171 
10172             const lowerToArrayCtor =
10173                 ( (rhsType.ty == Tarray && !rhs.isArrayLiteralExp) ||
10174                   (rhsType.ty == Tsarray && rhs.isLvalue) ) &&
10175                 t1e.equivalent(t2b.nextOf);
10176 
10177             // Construction from a single element?
10178             // If the RHS is an rvalue, then we'll need to make a temporary for it (copied multiple times).
10179             const lowerToArraySetCtor = !lowerToArrayCtor && t1e.equivalent(t2b);
10180 
10181             if (lowerToArrayCtor || lowerToArraySetCtor)
10182             {
10183                 auto func = lowerToArrayCtor ? Id._d_arrayctor : Id._d_arraysetctor;
10184                 const other = lowerToArrayCtor ? "other array" : "value";
10185                 if (!verifyHookExist(exp.loc, *sc, func, "construct array with " ~ other, Id.object))
10186                     return setError();
10187 
10188                 // Lower to object._d_array{,set}ctor(e1, e2)
10189                 Expression id = new IdentifierExp(exp.loc, Id.empty);
10190                 id = new DotIdExp(exp.loc, id, Id.object);
10191                 id = new DotIdExp(exp.loc, id, func);
10192 
10193                 auto arguments = new Expressions();
10194                 arguments.push(new CastExp(ae.loc, ae.e1, t1e.arrayOf).expressionSemantic(sc));
10195                 if (lowerToArrayCtor)
10196                 {
10197                     arguments.push(new CastExp(ae.loc, rhs, t2b.nextOf.arrayOf).expressionSemantic(sc));
10198                     Expression ce = new CallExp(exp.loc, id, arguments);
10199                     res = ce.expressionSemantic(sc);
10200                 }
10201                 else
10202                 {
10203                     Expression e0;
10204                     // promote an rvalue RHS element to a temporary, it's passed by ref to _d_arraysetctor
10205                     if (!ae.e2.isLvalue)
10206                     {
10207                         auto vd = copyToTemp(STC.scope_, "__setctor", ae.e2);
10208                         e0 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10209                         arguments.push(new VarExp(vd.loc, vd).expressionSemantic(sc));
10210                     }
10211                     else
10212                         arguments.push(ae.e2);
10213 
10214                     Expression ce = new CallExp(exp.loc, id, arguments);
10215                     res = Expression.combine(e0, ce).expressionSemantic(sc);
10216                 }
10217 
10218                 if (global.params.verbose)
10219                     message("lowered   %s =>\n          %s", exp.toChars(), res.toChars());
10220             }
10221         }
10222         else if (auto ae = res.isAssignExp())
10223             res = lowerArrayAssign(ae);
10224         else if (auto ce = res.isCommaExp())
10225         {
10226             if (auto ae1 = ce.e1.isAssignExp())
10227                 ce.e1 = lowerArrayAssign(ae1, true);
10228             if (auto ae2 = ce.e2.isAssignExp())
10229                 ce.e2 = lowerArrayAssign(ae2, true);
10230         }
10231 
10232         return setResult(res);
10233     }
10234 
10235     /***************************************
10236      * Lower AssignExp to `_d_array{setassign,assign_l,assign_r}` if needed.
10237      *
10238      * Params:
10239      *      ae = the AssignExp to be lowered
10240      *      fromCommaExp = indicates whether `ae` is part of a CommaExp or not,
10241      *                     so no unnecessary temporay variable is created.
10242      * Returns:
10243      *      a CommaExp contiaining call a to `_d_array{setassign,assign_l,assign_r}`
10244      *      if needed or `ae` otherwise
10245      */
10246     private Expression lowerArrayAssign(AssignExp ae, bool fromCommaExp = false)
10247     {
10248         Type t1b = ae.e1.type.toBasetype();
10249         if (t1b.ty != Tsarray && t1b.ty != Tarray)
10250             return ae;
10251 
10252         const isArrayAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10253             (ae.e2.type.ty == Tsarray || ae.e2.type.ty == Tarray) &&
10254             (ae.e1.type.nextOf() && ae.e2.type.nextOf() && ae.e1.type.nextOf.mutableOf.equals(ae.e2.type.nextOf.mutableOf()));
10255 
10256         const isArraySetAssign = (ae.e1.isSliceExp() || ae.e1.type.ty == Tsarray) &&
10257             (ae.e1.type.nextOf() && ae.e2.type.implicitConvTo(ae.e1.type.nextOf()));
10258 
10259         if (!isArrayAssign && !isArraySetAssign)
10260             return ae;
10261 
10262         const ts = t1b.nextOf().baseElemOf().isTypeStruct();
10263         if (!ts || (!ts.sym.postblit && !ts.sym.dtor))
10264             return ae;
10265 
10266         Expression res;
10267         Identifier func = isArraySetAssign ? Id._d_arraysetassign :
10268             ae.e2.isLvalue() || ae.e2.isSliceExp() ? Id._d_arrayassign_l : Id._d_arrayassign_r;
10269 
10270         // Lower to `.object._d_array{setassign,assign_l,assign_r}(e1, e2)``
10271         Expression id = new IdentifierExp(ae.loc, Id.empty);
10272         id = new DotIdExp(ae.loc, id, Id.object);
10273         id = new DotIdExp(ae.loc, id, func);
10274 
10275         auto arguments = new Expressions();
10276         arguments.push(new CastExp(ae.loc, ae.e1, ae.e1.type.nextOf.arrayOf)
10277             .expressionSemantic(sc));
10278 
10279         Expression eValue2, value2 = ae.e2;
10280         if (isArrayAssign && value2.isLvalue())
10281             value2 = new CastExp(ae.loc, ae.e2, ae.e2.type.nextOf.arrayOf())
10282                 .expressionSemantic(sc);
10283         else if (!fromCommaExp &&
10284             (isArrayAssign || (isArraySetAssign && !value2.isLvalue())))
10285         {
10286             // Rvalues from CommaExps were introduced in `visit(AssignExp)`
10287             // and are temporary variables themselves. Rvalues from trivial
10288             // SliceExps are simply passed by reference without any copying.
10289 
10290             // `__assigntmp` will be destroyed together with the array `ae.e1`.
10291             // When `ae.e2` is a variadic arg array, it is also `scope`, so
10292             // `__assigntmp` may also be scope.
10293             StorageClass stc = STC.nodtor;
10294             if (isArrayAssign)
10295                 stc |= STC.rvalue | STC.scope_;
10296 
10297             auto vd = copyToTemp(stc, "__assigntmp", ae.e2);
10298             eValue2 = new DeclarationExp(vd.loc, vd).expressionSemantic(sc);
10299             value2 = new VarExp(vd.loc, vd).expressionSemantic(sc);
10300         }
10301         arguments.push(value2);
10302 
10303         Expression ce = new CallExp(ae.loc, id, arguments);
10304         res = Expression.combine(eValue2, ce).expressionSemantic(sc);
10305         if (isArrayAssign)
10306             res = Expression.combine(res, ae.e1).expressionSemantic(sc);
10307 
10308         if (global.params.verbose)
10309             message("lowered   %s =>\n          %s", ae.toChars(), res.toChars());
10310 
10311         return res;
10312     }
10313 
10314     override void visit(PowAssignExp exp)
10315     {
10316         if (exp.type)
10317         {
10318             result = exp;
10319             return;
10320         }
10321 
10322         Expression e = exp.op_overload(sc);
10323         if (e)
10324         {
10325             result = e;
10326             return;
10327         }
10328 
10329         if (exp.e1.checkReadModifyWrite(exp.op, exp.e2))
10330             return setError();
10331 
10332         assert(exp.e1.type && exp.e2.type);
10333         if (exp.e1.op == EXP.slice || exp.e1.type.ty == Tarray || exp.e1.type.ty == Tsarray)
10334         {
10335             if (checkNonAssignmentArrayOp(exp.e1))
10336                 return setError();
10337 
10338             // T[] ^^= ...
10339             if (exp.e2.implicitConvTo(exp.e1.type.nextOf()))
10340             {
10341                 // T[] ^^= T
10342                 exp.e2 = exp.e2.castTo(sc, exp.e1.type.nextOf());
10343             }
10344             else if (Expression ex = typeCombine(exp, sc))
10345             {
10346                 result = ex;
10347                 return;
10348             }
10349 
10350             // Check element types are arithmetic
10351             Type tb1 = exp.e1.type.nextOf().toBasetype();
10352             Type tb2 = exp.e2.type.toBasetype();
10353             if (tb2.ty == Tarray || tb2.ty == Tsarray)
10354                 tb2 = tb2.nextOf().toBasetype();
10355             if ((tb1.isintegral() || tb1.isfloating()) && (tb2.isintegral() || tb2.isfloating()))
10356             {
10357                 exp.type = exp.e1.type;
10358                 result = arrayOp(exp, sc);
10359                 return;
10360             }
10361         }
10362         else
10363         {
10364             exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10365         }
10366 
10367         if ((exp.e1.type.isintegral() || exp.e1.type.isfloating()) && (exp.e2.type.isintegral() || exp.e2.type.isfloating()))
10368         {
10369             Expression e0 = null;
10370             e = exp.reorderSettingAAElem(sc);
10371             e = Expression.extractLast(e, e0);
10372             assert(e == exp);
10373 
10374             if (exp.e1.op == EXP.variable)
10375             {
10376                 // Rewrite: e1 = e1 ^^ e2
10377                 e = new PowExp(exp.loc, exp.e1.syntaxCopy(), exp.e2);
10378                 e = new AssignExp(exp.loc, exp.e1, e);
10379             }
10380             else
10381             {
10382                 // Rewrite: ref tmp = e1; tmp = tmp ^^ e2
10383                 auto v = copyToTemp(STC.ref_, "__powtmp", exp.e1);
10384                 auto de = new DeclarationExp(exp.e1.loc, v);
10385                 auto ve = new VarExp(exp.e1.loc, v);
10386                 e = new PowExp(exp.loc, ve, exp.e2);
10387                 e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e);
10388                 e = new CommaExp(exp.loc, de, e);
10389             }
10390             e = Expression.combine(e0, e);
10391             e = e.expressionSemantic(sc);
10392             result = e;
10393             return;
10394         }
10395         result = exp.incompatibleTypes();
10396     }
10397 
10398     override void visit(CatAssignExp exp)
10399     {
10400         if (exp.type)
10401         {
10402             result = exp;
10403             return;
10404         }
10405 
10406         //printf("CatAssignExp::semantic() %s\n", exp.toChars());
10407         Expression e = exp.op_overload(sc);
10408         if (e)
10409         {
10410             result = e;
10411             return;
10412         }
10413 
10414         if (SliceExp se = exp.e1.isSliceExp())
10415         {
10416             if (se.e1.type.toBasetype().ty == Tsarray)
10417             {
10418                 exp.error("cannot append to static array `%s`", se.e1.type.toChars());
10419                 return setError();
10420             }
10421         }
10422 
10423         exp.e1 = exp.e1.modifiableLvalue(sc, exp.e1);
10424         if (exp.e1.op == EXP.error)
10425         {
10426             result = exp.e1;
10427             return;
10428         }
10429         if (exp.e2.op == EXP.error)
10430         {
10431             result = exp.e2;
10432             return;
10433         }
10434 
10435         if (checkNonAssignmentArrayOp(exp.e2))
10436             return setError();
10437 
10438         Type tb1 = exp.e1.type.toBasetype();
10439         Type tb1next = tb1.nextOf();
10440         Type tb2 = exp.e2.type.toBasetype();
10441 
10442         /* Possibilities:
10443          * EXP.concatenateAssign: appending T[] to T[]
10444          * EXP.concatenateElemAssign: appending T to T[]
10445          * EXP.concatenateDcharAssign: appending dchar to T[]
10446          */
10447         if ((tb1.ty == Tarray) &&
10448             (tb2.ty == Tarray || tb2.ty == Tsarray) &&
10449             (exp.e2.implicitConvTo(exp.e1.type) ||
10450              (tb2.nextOf().implicitConvTo(tb1next) &&
10451               (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
10452         {
10453             // EXP.concatenateAssign
10454             assert(exp.op == EXP.concatenateAssign);
10455             if (exp.e1.checkPostblit(sc, tb1next))
10456                 return setError();
10457 
10458             exp.e2 = exp.e2.castTo(sc, exp.e1.type);
10459         }
10460         else if ((tb1.ty == Tarray) && exp.e2.implicitConvTo(tb1next))
10461         {
10462             /* https://issues.dlang.org/show_bug.cgi?id=19782
10463              *
10464              * If e2 is implicitly convertible to tb1next, the conversion
10465              * might be done through alias this, in which case, e2 needs to
10466              * be modified accordingly (e2 => e2.aliasthis).
10467              */
10468             if (tb2.ty == Tstruct && (cast(TypeStruct)tb2).implicitConvToThroughAliasThis(tb1next))
10469                 goto Laliasthis;
10470             if (tb2.ty == Tclass && (cast(TypeClass)tb2).implicitConvToThroughAliasThis(tb1next))
10471                 goto Laliasthis;
10472             // Append element
10473             if (exp.e2.checkPostblit(sc, tb2))
10474                 return setError();
10475 
10476             if (checkNewEscape(sc, exp.e2, false))
10477                 return setError();
10478 
10479             exp = new CatElemAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, tb1next));
10480             exp.e2 = doCopyOrMove(sc, exp.e2);
10481         }
10482         else if (tb1.ty == Tarray &&
10483                  (tb1next.ty == Tchar || tb1next.ty == Twchar) &&
10484                  exp.e2.type.ty != tb1next.ty &&
10485                  exp.e2.implicitConvTo(Type.tdchar))
10486         {
10487             // Append dchar to char[] or wchar[]
10488             exp = new CatDcharAssignExp(exp.loc, exp.type, exp.e1, exp.e2.castTo(sc, Type.tdchar));
10489 
10490             /* Do not allow appending wchar to char[] because if wchar happens
10491              * to be a surrogate pair, nothing good can result.
10492              */
10493         }
10494         else
10495         {
10496             // Try alias this on first operand
10497             static Expression tryAliasThisForLhs(BinAssignExp exp, Scope* sc)
10498             {
10499                 AggregateDeclaration ad1 = isAggregate(exp.e1.type);
10500                 if (!ad1 || !ad1.aliasthis)
10501                     return null;
10502 
10503                 /* Rewrite (e1 op e2) as:
10504                  *      (e1.aliasthis op e2)
10505                  */
10506                 if (isRecursiveAliasThis(exp.att1, exp.e1.type))
10507                     return null;
10508                 //printf("att %s e1 = %s\n", Token.toChars(e.op), e.e1.type.toChars());
10509                 Expression e1 = new DotIdExp(exp.loc, exp.e1, ad1.aliasthis.ident);
10510                 BinExp be = cast(BinExp)exp.copy();
10511                 be.e1 = e1;
10512                 return be.trySemantic(sc);
10513             }
10514 
10515             // Try alias this on second operand
10516             static Expression tryAliasThisForRhs(BinAssignExp exp, Scope* sc)
10517             {
10518                 AggregateDeclaration ad2 = isAggregate(exp.e2.type);
10519                 if (!ad2 || !ad2.aliasthis)
10520                     return null;
10521                 /* Rewrite (e1 op e2) as:
10522                  *      (e1 op e2.aliasthis)
10523                  */
10524                 if (isRecursiveAliasThis(exp.att2, exp.e2.type))
10525                     return null;
10526                 //printf("att %s e2 = %s\n", Token.toChars(e.op), e.e2.type.toChars());
10527                 Expression e2 = new DotIdExp(exp.loc, exp.e2, ad2.aliasthis.ident);
10528                 BinExp be = cast(BinExp)exp.copy();
10529                 be.e2 = e2;
10530                 return be.trySemantic(sc);
10531             }
10532 
10533     Laliasthis:
10534             result = tryAliasThisForLhs(exp, sc);
10535             if (result)
10536                 return;
10537 
10538             result = tryAliasThisForRhs(exp, sc);
10539             if (result)
10540                 return;
10541 
10542             exp.error("cannot append type `%s` to type `%s`", tb2.toChars(), tb1.toChars());
10543             return setError();
10544         }
10545 
10546         if (exp.e2.checkValue() || exp.e2.checkSharedAccess(sc))
10547             return setError();
10548 
10549         exp.type = exp.e1.type;
10550         auto assignElem = exp.e2;
10551         auto res = exp.reorderSettingAAElem(sc);
10552         if (res != exp) // `AA[k] = v` rewrite was performed
10553             checkNewEscape(sc, assignElem, false);
10554         else if (exp.op == EXP.concatenateElemAssign || exp.op == EXP.concatenateDcharAssign)
10555             checkAssignEscape(sc, res, false, false);
10556 
10557         result = res;
10558 
10559         if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
10560             sc.needsCodegen())
10561         {
10562             // if aa ordering is triggered, `res` will be a CommaExp
10563             // and `.e2` will be the rewritten original expression.
10564 
10565             // `output` will point to the expression that the lowering will overwrite
10566             Expression* output;
10567             if (auto comma = res.isCommaExp())
10568             {
10569                 output = &comma.e2;
10570                 // manual cast because it could be either CatAssignExp or CatElemAssignExp
10571                 exp = cast(CatAssignExp)comma.e2;
10572             }
10573             else
10574             {
10575                 output = &result;
10576                 exp = cast(CatAssignExp)result;
10577             }
10578 
10579             if (exp.op == EXP.concatenateAssign)
10580             {
10581                 Identifier hook = global.params.tracegc ? Id._d_arrayappendTTrace : Id._d_arrayappendT;
10582 
10583                 if (!verifyHookExist(exp.loc, *sc, hook, "appending array to arrays", Id.object))
10584                     return setError();
10585 
10586                 // Lower to object._d_arrayappendT{,Trace}({file, line, funcname}, e1, e2)
10587                 Expression id = new IdentifierExp(exp.loc, Id.empty);
10588                 id = new DotIdExp(exp.loc, id, Id.object);
10589                 id = new DotIdExp(exp.loc, id, hook);
10590 
10591                 auto arguments = new Expressions();
10592                 arguments.reserve(5);
10593                 if (global.params.tracegc)
10594                 {
10595                     auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10596                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10597                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10598                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
10599                 }
10600 
10601                 arguments.push(exp.e1);
10602                 arguments.push(exp.e2);
10603                 Expression ce = new CallExp(exp.loc, id, arguments);
10604                 *output = ce.expressionSemantic(sc);
10605             }
10606             else if (exp.op == EXP.concatenateElemAssign)
10607             {
10608                 /* Do not lower concats to the indices array returned by
10609                  *`static foreach`, as this array is only used at compile-time.
10610                  */
10611                 if (auto ve = exp.e1.isVarExp)
10612                 {
10613                     import core.stdc.ctype : isdigit;
10614                     // The name of the indices array that static foreach loops uses.
10615                     // See dmd.cond.lowerNonArrayAggregate
10616                     enum varName = "__res";
10617                     const(char)[] id = ve.var.ident.toString;
10618                     if (ve.var.storage_class & STC.temp && id.length > varName.length &&
10619                         id[0 .. varName.length] == varName && id[varName.length].isdigit)
10620                         return;
10621                 }
10622 
10623                 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
10624                 if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
10625                     return setError();
10626 
10627                 // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
10628                 Expression id = new IdentifierExp(exp.loc, Id.empty);
10629                 id = new DotIdExp(exp.loc, id, Id.object);
10630                 auto tiargs = new Objects();
10631                 tiargs.push(exp.e1.type);
10632                 id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
10633                 id = new DotIdExp(exp.loc, id, hook);
10634 
10635                 auto arguments = new Expressions();
10636                 arguments.reserve(5);
10637                 if (global.params.tracegc)
10638                 {
10639                     auto funcname = (sc.callsc && sc.callsc.func) ? sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
10640                     arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
10641                     arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
10642                     arguments.push(new StringExp(exp.loc, funcname.toDString()));
10643                 }
10644 
10645                 Expression eValue1;
10646                 Expression value1 = extractSideEffect(sc, "__appendtmp", eValue1, exp.e1);
10647 
10648                 arguments.push(value1);
10649                 arguments.push(new IntegerExp(exp.loc, 1, Type.tsize_t));
10650 
10651                 Expression ce = new CallExp(exp.loc, id, arguments);
10652 
10653                 Expression eValue2;
10654                 Expression value2 = exp.e2;
10655                 if (!value2.isVarExp() && !value2.isConst())
10656                 {
10657                     /* Before the template hook, this check was performed in e2ir.d
10658                      * for expressions like `a ~= a[$-1]`. Here, $ will be modified
10659                      * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
10660                      * a temporary variable.
10661                      */
10662                     value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
10663                     exp.e2 = value2;
10664 
10665                     // `__appendtmp*` will be destroyed together with the array `exp.e1`.
10666                     auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
10667                     vd.storage_class |= STC.nodtor;
10668                     // Be more explicit that this "declaration" is local to the expression
10669                     vd.storage_class |= STC.exptemp;
10670                 }
10671 
10672                 auto ale = new ArrayLengthExp(exp.loc, value1);
10673                 auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1));
10674                 auto ae = new ConstructExp(exp.loc, elem, value2);
10675 
10676                 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
10677                 e0 = Expression.combine(e0, value1);
10678                 e0 = Expression.combine(eValue1, e0);
10679 
10680                 e0 = Expression.combine(eValue2, e0);
10681 
10682                 *output = e0.expressionSemantic(sc);
10683             }
10684         }
10685 
10686     }
10687 
10688     override void visit(AddExp exp)
10689     {
10690         static if (LOGSEMANTIC)
10691         {
10692             printf("AddExp::semantic('%s')\n", exp.toChars());
10693         }
10694         if (exp.type)
10695         {
10696             result = exp;
10697             return;
10698         }
10699 
10700         if (Expression ex = binSemanticProp(exp, sc))
10701         {
10702             result = ex;
10703             return;
10704         }
10705         Expression e = exp.op_overload(sc);
10706         if (e)
10707         {
10708             result = e;
10709             return;
10710         }
10711 
10712         /* ImportC: convert arrays to pointers, functions to pointers to functions
10713          */
10714         exp.e1 = exp.e1.arrayFuncConv(sc);
10715         exp.e2 = exp.e2.arrayFuncConv(sc);
10716 
10717         Type tb1 = exp.e1.type.toBasetype();
10718         Type tb2 = exp.e2.type.toBasetype();
10719 
10720         bool err = false;
10721         if (tb1.ty == Tdelegate || tb1.isPtrToFunction())
10722         {
10723             err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10724         }
10725         if (tb2.ty == Tdelegate || tb2.isPtrToFunction())
10726         {
10727             err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10728         }
10729         if (err)
10730             return setError();
10731 
10732         if (tb1.ty == Tpointer && exp.e2.type.isintegral() || tb2.ty == Tpointer && exp.e1.type.isintegral())
10733         {
10734             result = scaleFactor(exp, sc);
10735             return;
10736         }
10737 
10738         if (tb1.ty == Tpointer && tb2.ty == Tpointer)
10739         {
10740             result = exp.incompatibleTypes();
10741             return;
10742         }
10743 
10744         if (Expression ex = typeCombine(exp, sc))
10745         {
10746             result = ex;
10747             return;
10748         }
10749 
10750         Type tb = exp.type.toBasetype();
10751         if (tb.ty == Tarray || tb.ty == Tsarray)
10752         {
10753             if (!isArrayOpValid(exp))
10754             {
10755                 result = arrayOpInvalidError(exp);
10756                 return;
10757             }
10758             result = exp;
10759             return;
10760         }
10761 
10762         tb1 = exp.e1.type.toBasetype();
10763         if (!target.isVectorOpSupported(tb1, exp.op, tb2))
10764         {
10765             result = exp.incompatibleTypes();
10766             return;
10767         }
10768         if ((tb1.isreal() && exp.e2.type.isimaginary()) || (tb1.isimaginary() && exp.e2.type.isreal()))
10769         {
10770             switch (exp.type.toBasetype().ty)
10771             {
10772             case Tfloat32:
10773             case Timaginary32:
10774                 exp.type = Type.tcomplex32;
10775                 break;
10776 
10777             case Tfloat64:
10778             case Timaginary64:
10779                 exp.type = Type.tcomplex64;
10780                 break;
10781 
10782             case Tfloat80:
10783             case Timaginary80:
10784                 exp.type = Type.tcomplex80;
10785                 break;
10786 
10787             default:
10788                 assert(0);
10789             }
10790         }
10791         result = exp;
10792     }
10793 
10794     override void visit(MinExp exp)
10795     {
10796         static if (LOGSEMANTIC)
10797         {
10798             printf("MinExp::semantic('%s')\n", exp.toChars());
10799         }
10800         if (exp.type)
10801         {
10802             result = exp;
10803             return;
10804         }
10805 
10806         if (Expression ex = binSemanticProp(exp, sc))
10807         {
10808             result = ex;
10809             return;
10810         }
10811         Expression e = exp.op_overload(sc);
10812         if (e)
10813         {
10814             result = e;
10815             return;
10816         }
10817 
10818         /* ImportC: convert arrays to pointers, functions to pointers to functions
10819          */
10820         exp.e1 = exp.e1.arrayFuncConv(sc);
10821         exp.e2 = exp.e2.arrayFuncConv(sc);
10822 
10823         Type t1 = exp.e1.type.toBasetype();
10824         Type t2 = exp.e2.type.toBasetype();
10825 
10826         bool err = false;
10827         if (t1.ty == Tdelegate || t1.isPtrToFunction())
10828         {
10829             err |= exp.e1.checkArithmetic() || exp.e1.checkSharedAccess(sc);
10830         }
10831         if (t2.ty == Tdelegate || t2.isPtrToFunction())
10832         {
10833             err |= exp.e2.checkArithmetic() || exp.e2.checkSharedAccess(sc);
10834         }
10835         if (err)
10836             return setError();
10837 
10838         if (t1.ty == Tpointer)
10839         {
10840             if (t2.ty == Tpointer)
10841             {
10842                 // https://dlang.org/spec/expression.html#add_expressions
10843                 // "If both operands are pointers, and the operator is -, the pointers are
10844                 // subtracted and the result is divided by the size of the type pointed to
10845                 // by the operands. It is an error if the pointers point to different types."
10846                 Type p1 = t1.nextOf();
10847                 Type p2 = t2.nextOf();
10848 
10849                 if (!p1.equivalent(p2))
10850                 {
10851                     // Deprecation to remain for at least a year, after which this should be
10852                     // changed to an error
10853                     // See https://github.com/dlang/dmd/pull/7332
10854                     deprecation(exp.loc,
10855                         "cannot subtract pointers to different types: `%s` and `%s`.",
10856                         t1.toChars(), t2.toChars());
10857                 }
10858 
10859                 // Need to divide the result by the stride
10860                 // Replace (ptr - ptr) with (ptr - ptr) / stride
10861                 long stride;
10862 
10863                 // make sure pointer types are compatible
10864                 if (Expression ex = typeCombine(exp, sc))
10865                 {
10866                     result = ex;
10867                     return;
10868                 }
10869 
10870                 exp.type = Type.tptrdiff_t;
10871                 stride = t2.nextOf().size();
10872                 if (stride == 0)
10873                 {
10874                     e = new IntegerExp(exp.loc, 0, Type.tptrdiff_t);
10875                 }
10876                 else if (stride == cast(long)SIZE_INVALID)
10877                     e = ErrorExp.get();
10878                 else
10879                 {
10880                     e = new DivExp(exp.loc, exp, new IntegerExp(Loc.initial, stride, Type.tptrdiff_t));
10881                     e.type = Type.tptrdiff_t;
10882                 }
10883             }
10884             else if (t2.isintegral())
10885                 e = scaleFactor(exp, sc);
10886             else
10887             {
10888                 exp.error("can't subtract `%s` from pointer", t2.toChars());
10889                 e = ErrorExp.get();
10890             }
10891             result = e;
10892             return;
10893         }
10894         if (t2.ty == Tpointer)
10895         {
10896             exp.type = exp.e2.type;
10897             exp.error("can't subtract pointer from `%s`", exp.e1.type.toChars());
10898             return setError();
10899         }
10900 
10901         if (Expression ex = typeCombine(exp, sc))
10902         {
10903             result = ex;
10904             return;
10905         }
10906 
10907         Type tb = exp.type.toBasetype();
10908         if (tb.ty == Tarray || tb.ty == Tsarray)
10909         {
10910             if (!isArrayOpValid(exp))
10911             {
10912                 result = arrayOpInvalidError(exp);
10913                 return;
10914             }
10915             result = exp;
10916             return;
10917         }
10918 
10919         t1 = exp.e1.type.toBasetype();
10920         t2 = exp.e2.type.toBasetype();
10921         if (!target.isVectorOpSupported(t1, exp.op, t2))
10922         {
10923             result = exp.incompatibleTypes();
10924             return;
10925         }
10926         if ((t1.isreal() && t2.isimaginary()) || (t1.isimaginary() && t2.isreal()))
10927         {
10928             switch (exp.type.ty)
10929             {
10930             case Tfloat32:
10931             case Timaginary32:
10932                 exp.type = Type.tcomplex32;
10933                 break;
10934 
10935             case Tfloat64:
10936             case Timaginary64:
10937                 exp.type = Type.tcomplex64;
10938                 break;
10939 
10940             case Tfloat80:
10941             case Timaginary80:
10942                 exp.type = Type.tcomplex80;
10943                 break;
10944 
10945             default:
10946                 assert(0);
10947             }
10948         }
10949         result = exp;
10950         return;
10951     }
10952 
10953     /**
10954      * If the given expression is a `CatExp`, the function tries to lower it to
10955      * `_d_arraycatnTX`.
10956      *
10957      * Params:
10958      *      ee = the `CatExp` to lower
10959      * Returns:
10960      *      `_d_arraycatnTX(e1, e2, ..., en)` if `ee` is `e1 ~ e2 ~ ... en`
10961      *      `ee` otherwise
10962      */
10963     private Expression lowerToArrayCat(CatExp exp)
10964     {
10965         // String literals are concatenated by the compiler. No lowering is needed.
10966         if ((exp.e1.isStringExp() && (exp.e2.isIntegerExp() || exp.e2.isStringExp())) ||
10967             (exp.e2.isStringExp() && (exp.e1.isIntegerExp() || exp.e1.isStringExp())))
10968             return exp;
10969 
10970         Identifier hook = global.params.tracegc ? Id._d_arraycatnTXTrace : Id._d_arraycatnTX;
10971         if (!verifyHookExist(exp.loc, *sc, hook, "concatenating arrays"))
10972         {
10973             setError();
10974             return result;
10975         }
10976 
10977         void handleCatArgument(Expressions *arguments, Expression e)
10978         {
10979             if (auto ce = e.isCatExp())
10980             {
10981                 Expression lowering = ce.lowering;
10982 
10983                 /* Skip `file`, `line`, and `funcname` if the hook of the parent
10984                  * `CatExp` is `_d_arraycatnTXTrace`.
10985                  */
10986                 if (auto callExp = isRuntimeHook(lowering, hook))
10987                 {
10988                     if (hook == Id._d_arraycatnTX)
10989                         arguments.pushSlice((*callExp.arguments)[]);
10990                     else
10991                         arguments.pushSlice((*callExp.arguments)[3 .. $]);
10992                 }
10993             }
10994             else
10995                 arguments.push(e);
10996         }
10997 
10998         auto arguments = new Expressions();
10999         if (global.params.tracegc)
11000         {
11001             auto funcname = (sc.callsc && sc.callsc.func) ?
11002                 sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
11003             arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
11004             arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
11005             arguments.push(new StringExp(exp.loc, funcname.toDString()));
11006         }
11007 
11008         handleCatArgument(arguments, exp.e1);
11009         handleCatArgument(arguments, exp.e2);
11010 
11011         Expression id = new IdentifierExp(exp.loc, Id.empty);
11012         id = new DotIdExp(exp.loc, id, Id.object);
11013 
11014         auto tiargs = new Objects();
11015         tiargs.push(exp.type);
11016         id = new DotTemplateInstanceExp(exp.loc, id, hook, tiargs);
11017         id = new CallExp(exp.loc, id, arguments);
11018         return id.expressionSemantic(sc);
11019     }
11020 
11021     void trySetCatExpLowering(Expression exp)
11022     {
11023         /* `_d_arraycatnTX` canot be used with `-betterC`, but `CatExp`s may be
11024          * used with `-betterC`, but only during CTFE.
11025          */
11026         if (global.params.betterC || !sc.needsCodegen())
11027             return;
11028 
11029         if (auto ce = exp.isCatExp())
11030             ce.lowering = lowerToArrayCat(ce);
11031     }
11032 
11033     override void visit(CatExp exp)
11034     {
11035         // https://dlang.org/spec/expression.html#cat_expressions
11036         //printf("CatExp.semantic() %s\n", toChars());
11037         if (exp.type)
11038         {
11039             result = exp;
11040             return;
11041         }
11042 
11043         if (Expression ex = binSemanticProp(exp, sc))
11044         {
11045             result = ex;
11046             return;
11047         }
11048         Expression e = exp.op_overload(sc);
11049         if (e)
11050         {
11051             result = e;
11052             return;
11053         }
11054 
11055         Type tb1 = exp.e1.type.toBasetype();
11056         Type tb2 = exp.e2.type.toBasetype();
11057 
11058         auto f1 = checkNonAssignmentArrayOp(exp.e1);
11059         auto f2 = checkNonAssignmentArrayOp(exp.e2);
11060         if (f1 || f2)
11061             return setError();
11062 
11063         Type tb1next = tb1.nextOf();
11064         Type tb2next = tb2.nextOf();
11065 
11066         // Check for: array ~ array
11067         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)))
11068         {
11069             /* https://issues.dlang.org/show_bug.cgi?id=9248
11070              * Here to avoid the case of:
11071              *    void*[] a = [cast(void*)1];
11072              *    void*[] b = [cast(void*)2];
11073              *    a ~ b;
11074              * becoming:
11075              *    a ~ [cast(void*)b];
11076              */
11077 
11078             /* https://issues.dlang.org/show_bug.cgi?id=14682
11079              * Also to avoid the case of:
11080              *    int[][] a;
11081              *    a ~ [];
11082              * becoming:
11083              *    a ~ cast(int[])[];
11084              */
11085             goto Lpeer;
11086         }
11087 
11088         // Check for: array ~ element
11089         if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid)
11090         {
11091             if (exp.e1.op == EXP.arrayLiteral)
11092             {
11093                 exp.e2 = doCopyOrMove(sc, exp.e2);
11094                 // https://issues.dlang.org/show_bug.cgi?id=14686
11095                 // Postblit call appears in AST, and this is
11096                 // finally translated  to an ArrayLiteralExp in below optimize().
11097             }
11098             else if (exp.e1.op == EXP.string_)
11099             {
11100                 // No postblit call exists on character (integer) value.
11101             }
11102             else
11103             {
11104                 if (exp.e2.checkPostblit(sc, tb2))
11105                     return setError();
11106                 // Postblit call will be done in runtime helper function
11107             }
11108 
11109             if (exp.e1.op == EXP.arrayLiteral && exp.e1.implicitConvTo(tb2.arrayOf()))
11110             {
11111                 exp.e1 = exp.e1.implicitCastTo(sc, tb2.arrayOf());
11112                 exp.type = tb2.arrayOf();
11113                 goto L2elem;
11114             }
11115             if (exp.e2.implicitConvTo(tb1next) >= MATCH.convert)
11116             {
11117                 exp.e2 = exp.e2.implicitCastTo(sc, tb1next);
11118                 exp.type = tb1next.arrayOf();
11119             L2elem:
11120                 if (checkNewEscape(sc, exp.e2, false))
11121                     return setError();
11122                 result = exp.optimize(WANTvalue);
11123                 trySetCatExpLowering(result);
11124                 return;
11125             }
11126         }
11127         // Check for: element ~ array
11128         if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid)
11129         {
11130             if (exp.e2.op == EXP.arrayLiteral)
11131             {
11132                 exp.e1 = doCopyOrMove(sc, exp.e1);
11133             }
11134             else if (exp.e2.op == EXP.string_)
11135             {
11136             }
11137             else
11138             {
11139                 if (exp.e1.checkPostblit(sc, tb1))
11140                     return setError();
11141             }
11142 
11143             if (exp.e2.op == EXP.arrayLiteral && exp.e2.implicitConvTo(tb1.arrayOf()))
11144             {
11145                 exp.e2 = exp.e2.implicitCastTo(sc, tb1.arrayOf());
11146                 exp.type = tb1.arrayOf();
11147                 goto L1elem;
11148             }
11149             if (exp.e1.implicitConvTo(tb2next) >= MATCH.convert)
11150             {
11151                 exp.e1 = exp.e1.implicitCastTo(sc, tb2next);
11152                 exp.type = tb2next.arrayOf();
11153             L1elem:
11154                 if (checkNewEscape(sc, exp.e1, false))
11155                     return setError();
11156                 result = exp.optimize(WANTvalue);
11157                 trySetCatExpLowering(result);
11158                 return;
11159             }
11160         }
11161 
11162     Lpeer:
11163         if ((tb1.ty == Tsarray || tb1.ty == Tarray) && (tb2.ty == Tsarray || tb2.ty == Tarray) && (tb1next.mod || tb2next.mod) && (tb1next.mod != tb2next.mod))
11164         {
11165             Type t1 = tb1next.mutableOf().constOf().arrayOf();
11166             Type t2 = tb2next.mutableOf().constOf().arrayOf();
11167             if (exp.e1.op == EXP.string_ && !(cast(StringExp)exp.e1).committed)
11168                 exp.e1.type = t1;
11169             else
11170                 exp.e1 = exp.e1.castTo(sc, t1);
11171             if (exp.e2.op == EXP.string_ && !(cast(StringExp)exp.e2).committed)
11172                 exp.e2.type = t2;
11173             else
11174                 exp.e2 = exp.e2.castTo(sc, t2);
11175         }
11176 
11177         if (Expression ex = typeCombine(exp, sc))
11178         {
11179             result = ex;
11180             trySetCatExpLowering(result);
11181             return;
11182         }
11183         exp.type = exp.type.toHeadMutable();
11184 
11185         Type tb = exp.type.toBasetype();
11186         if (tb.ty == Tsarray)
11187             exp.type = tb.nextOf().arrayOf();
11188         if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
11189         {
11190             exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
11191         }
11192         if (Type tbn = tb.nextOf())
11193         {
11194             if (exp.checkPostblit(sc, tbn))
11195                 return setError();
11196         }
11197         Type t1 = exp.e1.type.toBasetype();
11198         Type t2 = exp.e2.type.toBasetype();
11199         if ((t1.ty == Tarray || t1.ty == Tsarray) &&
11200             (t2.ty == Tarray || t2.ty == Tsarray))
11201         {
11202             // Normalize to ArrayLiteralExp or StringExp as far as possible
11203             e = exp.optimize(WANTvalue);
11204         }
11205         else
11206         {
11207             //printf("(%s) ~ (%s)\n", e1.toChars(), e2.toChars());
11208             result = exp.incompatibleTypes();
11209             return;
11210         }
11211 
11212         result = e;
11213         trySetCatExpLowering(result);
11214     }
11215 
11216     override void visit(MulExp exp)
11217     {
11218         version (none)
11219         {
11220             printf("MulExp::semantic() %s\n", exp.toChars());
11221         }
11222         if (exp.type)
11223         {
11224             result = exp;
11225             return;
11226         }
11227 
11228         if (Expression ex = binSemanticProp(exp, sc))
11229         {
11230             result = ex;
11231             return;
11232         }
11233         Expression e = exp.op_overload(sc);
11234         if (e)
11235         {
11236             result = e;
11237             return;
11238         }
11239 
11240         if (Expression ex = typeCombine(exp, sc))
11241         {
11242             result = ex;
11243             return;
11244         }
11245 
11246         Type tb = exp.type.toBasetype();
11247         if (tb.ty == Tarray || tb.ty == Tsarray)
11248         {
11249             if (!isArrayOpValid(exp))
11250             {
11251                 result = arrayOpInvalidError(exp);
11252                 return;
11253             }
11254             result = exp;
11255             return;
11256         }
11257 
11258         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11259             return setError();
11260 
11261         if (exp.type.isfloating())
11262         {
11263             Type t1 = exp.e1.type;
11264             Type t2 = exp.e2.type;
11265 
11266             if (t1.isreal())
11267             {
11268                 exp.type = t2;
11269             }
11270             else if (t2.isreal())
11271             {
11272                 exp.type = t1;
11273             }
11274             else if (t1.isimaginary())
11275             {
11276                 if (t2.isimaginary())
11277                 {
11278                     switch (t1.toBasetype().ty)
11279                     {
11280                     case Timaginary32:
11281                         exp.type = Type.tfloat32;
11282                         break;
11283 
11284                     case Timaginary64:
11285                         exp.type = Type.tfloat64;
11286                         break;
11287 
11288                     case Timaginary80:
11289                         exp.type = Type.tfloat80;
11290                         break;
11291 
11292                     default:
11293                         assert(0);
11294                     }
11295 
11296                     // iy * iv = -yv
11297                     exp.e1.type = exp.type;
11298                     exp.e2.type = exp.type;
11299                     e = new NegExp(exp.loc, exp);
11300                     e = e.expressionSemantic(sc);
11301                     result = e;
11302                     return;
11303                 }
11304                 else
11305                     exp.type = t2; // t2 is complex
11306             }
11307             else if (t2.isimaginary())
11308             {
11309                 exp.type = t1; // t1 is complex
11310             }
11311         }
11312         else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11313         {
11314             result = exp.incompatibleTypes();
11315             return;
11316         }
11317         result = exp;
11318     }
11319 
11320     override void visit(DivExp exp)
11321     {
11322         if (exp.type)
11323         {
11324             result = exp;
11325             return;
11326         }
11327 
11328         if (Expression ex = binSemanticProp(exp, sc))
11329         {
11330             result = ex;
11331             return;
11332         }
11333         Expression e = exp.op_overload(sc);
11334         if (e)
11335         {
11336             result = e;
11337             return;
11338         }
11339 
11340         if (Expression ex = typeCombine(exp, sc))
11341         {
11342             result = ex;
11343             return;
11344         }
11345 
11346         Type tb = exp.type.toBasetype();
11347         if (tb.ty == Tarray || tb.ty == Tsarray)
11348         {
11349             if (!isArrayOpValid(exp))
11350             {
11351                 result = arrayOpInvalidError(exp);
11352                 return;
11353             }
11354             result = exp;
11355             return;
11356         }
11357 
11358         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11359             return setError();
11360 
11361         if (exp.type.isfloating())
11362         {
11363             Type t1 = exp.e1.type;
11364             Type t2 = exp.e2.type;
11365 
11366             if (t1.isreal())
11367             {
11368                 exp.type = t2;
11369                 if (t2.isimaginary())
11370                 {
11371                     // x/iv = i(-x/v)
11372                     exp.e2.type = t1;
11373                     e = new NegExp(exp.loc, exp);
11374                     e = e.expressionSemantic(sc);
11375                     result = e;
11376                     return;
11377                 }
11378             }
11379             else if (t2.isreal())
11380             {
11381                 exp.type = t1;
11382             }
11383             else if (t1.isimaginary())
11384             {
11385                 if (t2.isimaginary())
11386                 {
11387                     switch (t1.toBasetype().ty)
11388                     {
11389                     case Timaginary32:
11390                         exp.type = Type.tfloat32;
11391                         break;
11392 
11393                     case Timaginary64:
11394                         exp.type = Type.tfloat64;
11395                         break;
11396 
11397                     case Timaginary80:
11398                         exp.type = Type.tfloat80;
11399                         break;
11400 
11401                     default:
11402                         assert(0);
11403                     }
11404                 }
11405                 else
11406                     exp.type = t2; // t2 is complex
11407             }
11408             else if (t2.isimaginary())
11409             {
11410                 exp.type = t1; // t1 is complex
11411             }
11412         }
11413         else if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11414         {
11415             result = exp.incompatibleTypes();
11416             return;
11417         }
11418         result = exp;
11419     }
11420 
11421     override void visit(ModExp exp)
11422     {
11423         if (exp.type)
11424         {
11425             result = exp;
11426             return;
11427         }
11428 
11429         if (Expression ex = binSemanticProp(exp, sc))
11430         {
11431             result = ex;
11432             return;
11433         }
11434         Expression e = exp.op_overload(sc);
11435         if (e)
11436         {
11437             result = e;
11438             return;
11439         }
11440 
11441         if (Expression ex = typeCombine(exp, sc))
11442         {
11443             result = ex;
11444             return;
11445         }
11446 
11447         Type tb = exp.type.toBasetype();
11448         if (tb.ty == Tarray || tb.ty == Tsarray)
11449         {
11450             if (!isArrayOpValid(exp))
11451             {
11452                 result = arrayOpInvalidError(exp);
11453                 return;
11454             }
11455             result = exp;
11456             return;
11457         }
11458         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11459         {
11460             result = exp.incompatibleTypes();
11461             return;
11462         }
11463 
11464         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11465             return setError();
11466 
11467         if (exp.type.isfloating())
11468         {
11469             exp.type = exp.e1.type;
11470             if (exp.e2.type.iscomplex())
11471             {
11472                 exp.error("cannot perform modulo complex arithmetic");
11473                 return setError();
11474             }
11475         }
11476         result = exp;
11477     }
11478 
11479     override void visit(PowExp exp)
11480     {
11481         if (exp.type)
11482         {
11483             result = exp;
11484             return;
11485         }
11486 
11487         //printf("PowExp::semantic() %s\n", toChars());
11488         if (Expression ex = binSemanticProp(exp, sc))
11489         {
11490             result = ex;
11491             return;
11492         }
11493         Expression e = exp.op_overload(sc);
11494         if (e)
11495         {
11496             result = e;
11497             return;
11498         }
11499 
11500         if (Expression ex = typeCombine(exp, sc))
11501         {
11502             result = ex;
11503             return;
11504         }
11505 
11506         Type tb = exp.type.toBasetype();
11507         if (tb.ty == Tarray || tb.ty == Tsarray)
11508         {
11509             if (!isArrayOpValid(exp))
11510             {
11511                 result = arrayOpInvalidError(exp);
11512                 return;
11513             }
11514             result = exp;
11515             return;
11516         }
11517 
11518         if (exp.checkArithmeticBin() || exp.checkSharedAccessBin(sc))
11519             return setError();
11520 
11521         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11522         {
11523             result = exp.incompatibleTypes();
11524             return;
11525         }
11526 
11527         // First, attempt to fold the expression.
11528         e = exp.optimize(WANTvalue);
11529         if (e.op != EXP.pow)
11530         {
11531             e = e.expressionSemantic(sc);
11532             result = e;
11533             return;
11534         }
11535 
11536         Module mmath = Module.loadStdMath();
11537         if (!mmath)
11538         {
11539             e.error("`%s` requires `std.math` for `^^` operators", e.toChars());
11540             return setError();
11541         }
11542         e = new ScopeExp(exp.loc, mmath);
11543 
11544         if (exp.e2.op == EXP.float64 && exp.e2.toReal() == CTFloat.half)
11545         {
11546             // Replace e1 ^^ 0.5 with .std.math.sqrt(e1)
11547             e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._sqrt), exp.e1);
11548         }
11549         else
11550         {
11551             // Replace e1 ^^ e2 with .std.math.pow(e1, e2)
11552             e = new CallExp(exp.loc, new DotIdExp(exp.loc, e, Id._pow), exp.e1, exp.e2);
11553         }
11554         e = e.expressionSemantic(sc);
11555         result = e;
11556         return;
11557     }
11558 
11559     override void visit(ShlExp exp)
11560     {
11561         //printf("ShlExp::semantic(), type = %p\n", type);
11562         if (exp.type)
11563         {
11564             result = exp;
11565             return;
11566         }
11567 
11568         if (Expression ex = binSemanticProp(exp, sc))
11569         {
11570             result = ex;
11571             return;
11572         }
11573         Expression e = exp.op_overload(sc);
11574         if (e)
11575         {
11576             result = e;
11577             return;
11578         }
11579 
11580         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11581             return setError();
11582 
11583         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11584         {
11585             result = exp.incompatibleTypes();
11586             return;
11587         }
11588         exp.e1 = integralPromotions(exp.e1, sc);
11589         if (exp.e2.type.toBasetype().ty != Tvector)
11590             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11591 
11592         exp.type = exp.e1.type;
11593         result = exp;
11594     }
11595 
11596     override void visit(ShrExp exp)
11597     {
11598         if (exp.type)
11599         {
11600             result = exp;
11601             return;
11602         }
11603 
11604         if (Expression ex = binSemanticProp(exp, sc))
11605         {
11606             result = ex;
11607             return;
11608         }
11609         Expression e = exp.op_overload(sc);
11610         if (e)
11611         {
11612             result = e;
11613             return;
11614         }
11615 
11616         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11617             return setError();
11618 
11619         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11620         {
11621             result = exp.incompatibleTypes();
11622             return;
11623         }
11624         exp.e1 = integralPromotions(exp.e1, sc);
11625         if (exp.e2.type.toBasetype().ty != Tvector)
11626             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11627 
11628         exp.type = exp.e1.type;
11629         result = exp;
11630     }
11631 
11632     override void visit(UshrExp exp)
11633     {
11634         if (exp.type)
11635         {
11636             result = exp;
11637             return;
11638         }
11639 
11640         if (Expression ex = binSemanticProp(exp, sc))
11641         {
11642             result = ex;
11643             return;
11644         }
11645         Expression e = exp.op_overload(sc);
11646         if (e)
11647         {
11648             result = e;
11649             return;
11650         }
11651 
11652         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11653             return setError();
11654 
11655         if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
11656         {
11657             result = exp.incompatibleTypes();
11658             return;
11659         }
11660         exp.e1 = integralPromotions(exp.e1, sc);
11661         if (exp.e2.type.toBasetype().ty != Tvector)
11662             exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
11663 
11664         exp.type = exp.e1.type;
11665         result = exp;
11666     }
11667 
11668     override void visit(AndExp exp)
11669     {
11670         if (exp.type)
11671         {
11672             result = exp;
11673             return;
11674         }
11675 
11676         if (Expression ex = binSemanticProp(exp, sc))
11677         {
11678             result = ex;
11679             return;
11680         }
11681         Expression e = exp.op_overload(sc);
11682         if (e)
11683         {
11684             result = e;
11685             return;
11686         }
11687 
11688         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11689         {
11690             exp.type = exp.e1.type;
11691             result = exp;
11692             return;
11693         }
11694 
11695         if (Expression ex = typeCombine(exp, sc))
11696         {
11697             result = ex;
11698             return;
11699         }
11700 
11701         Type tb = exp.type.toBasetype();
11702         if (tb.ty == Tarray || tb.ty == Tsarray)
11703         {
11704             if (!isArrayOpValid(exp))
11705             {
11706                 result = arrayOpInvalidError(exp);
11707                 return;
11708             }
11709             result = exp;
11710             return;
11711         }
11712         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11713         {
11714             result = exp.incompatibleTypes();
11715             return;
11716         }
11717         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11718             return setError();
11719 
11720         result = exp;
11721     }
11722 
11723     override void visit(OrExp exp)
11724     {
11725         if (exp.type)
11726         {
11727             result = exp;
11728             return;
11729         }
11730 
11731         if (Expression ex = binSemanticProp(exp, sc))
11732         {
11733             result = ex;
11734             return;
11735         }
11736         Expression e = exp.op_overload(sc);
11737         if (e)
11738         {
11739             result = e;
11740             return;
11741         }
11742 
11743         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11744         {
11745             exp.type = exp.e1.type;
11746             result = exp;
11747             return;
11748         }
11749 
11750         if (Expression ex = typeCombine(exp, sc))
11751         {
11752             result = ex;
11753             return;
11754         }
11755 
11756         Type tb = exp.type.toBasetype();
11757         if (tb.ty == Tarray || tb.ty == Tsarray)
11758         {
11759             if (!isArrayOpValid(exp))
11760             {
11761                 result = arrayOpInvalidError(exp);
11762                 return;
11763             }
11764             result = exp;
11765             return;
11766         }
11767         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11768         {
11769             result = exp.incompatibleTypes();
11770             return;
11771         }
11772         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11773             return setError();
11774 
11775         result = exp;
11776     }
11777 
11778     override void visit(XorExp exp)
11779     {
11780         if (exp.type)
11781         {
11782             result = exp;
11783             return;
11784         }
11785 
11786         if (Expression ex = binSemanticProp(exp, sc))
11787         {
11788             result = ex;
11789             return;
11790         }
11791         Expression e = exp.op_overload(sc);
11792         if (e)
11793         {
11794             result = e;
11795             return;
11796         }
11797 
11798         if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
11799         {
11800             exp.type = exp.e1.type;
11801             result = exp;
11802             return;
11803         }
11804 
11805         if (Expression ex = typeCombine(exp, sc))
11806         {
11807             result = ex;
11808             return;
11809         }
11810 
11811         Type tb = exp.type.toBasetype();
11812         if (tb.ty == Tarray || tb.ty == Tsarray)
11813         {
11814             if (!isArrayOpValid(exp))
11815             {
11816                 result = arrayOpInvalidError(exp);
11817                 return;
11818             }
11819             result = exp;
11820             return;
11821         }
11822         if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
11823         {
11824             result = exp.incompatibleTypes();
11825             return;
11826         }
11827         if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
11828             return setError();
11829 
11830         result = exp;
11831     }
11832 
11833     override void visit(LogicalExp exp)
11834     {
11835         static if (LOGSEMANTIC)
11836         {
11837             printf("LogicalExp::semantic() %s\n", exp.toChars());
11838         }
11839 
11840         if (exp.type)
11841         {
11842             result = exp;
11843             return;
11844         }
11845 
11846         exp.setNoderefOperands();
11847 
11848         Expression e1x = exp.e1.expressionSemantic(sc);
11849 
11850         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11851         if (e1x.op == EXP.type)
11852             e1x = resolveAliasThis(sc, e1x);
11853 
11854         e1x = resolveProperties(sc, e1x);
11855         e1x = e1x.toBoolean(sc);
11856 
11857         if (sc.flags & SCOPE.condition)
11858         {
11859             /* If in static if, don't evaluate e2 if we don't have to.
11860              */
11861             e1x = e1x.optimize(WANTvalue);
11862             if (e1x.toBool().hasValue(exp.op == EXP.orOr))
11863             {
11864                 if (sc.flags & SCOPE.Cfile)
11865                     result = new IntegerExp(exp.op == EXP.orOr);
11866                 else
11867                     result = IntegerExp.createBool(exp.op == EXP.orOr);
11868                 return;
11869             }
11870         }
11871 
11872         CtorFlow ctorflow = sc.ctorflow.clone();
11873         Expression e2x = exp.e2.expressionSemantic(sc);
11874         sc.merge(exp.loc, ctorflow);
11875         ctorflow.freeFieldinit();
11876 
11877         // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
11878         if (e2x.op == EXP.type)
11879             e2x = resolveAliasThis(sc, e2x);
11880 
11881         e2x = resolveProperties(sc, e2x);
11882 
11883         auto f1 = checkNonAssignmentArrayOp(e1x);
11884         auto f2 = checkNonAssignmentArrayOp(e2x);
11885         if (f1 || f2)
11886             return setError();
11887 
11888         // Unless the right operand is 'void', the expression is converted to 'bool'.
11889         if (e2x.type.ty != Tvoid)
11890             e2x = e2x.toBoolean(sc);
11891 
11892         if (e2x.op == EXP.type || e2x.op == EXP.scope_)
11893         {
11894             exp.error("`%s` is not an expression", exp.e2.toChars());
11895             return setError();
11896         }
11897         if (e1x.op == EXP.error || e1x.type.ty == Tnoreturn)
11898         {
11899             result = e1x;
11900             return;
11901         }
11902         if (e2x.op == EXP.error)
11903         {
11904             result = e2x;
11905             return;
11906         }
11907 
11908         // The result type is 'bool', unless the right operand has type 'void'.
11909         if (e2x.type.ty == Tvoid)
11910             exp.type = Type.tvoid;
11911         else
11912             exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
11913 
11914         exp.e1 = e1x;
11915         exp.e2 = e2x;
11916         result = exp;
11917     }
11918 
11919 
11920     override void visit(CmpExp exp)
11921     {
11922         static if (LOGSEMANTIC)
11923         {
11924             printf("CmpExp::semantic('%s')\n", exp.toChars());
11925         }
11926         if (exp.type)
11927         {
11928             result = exp;
11929             return;
11930         }
11931 
11932         exp.setNoderefOperands();
11933 
11934         if (Expression ex = binSemanticProp(exp, sc))
11935         {
11936             result = ex;
11937             return;
11938         }
11939         Type t1 = exp.e1.type.toBasetype();
11940         Type t2 = exp.e2.type.toBasetype();
11941         if (t1.ty == Tclass && exp.e2.op == EXP.null_ || t2.ty == Tclass && exp.e1.op == EXP.null_)
11942         {
11943             exp.error("do not use `null` when comparing class types");
11944             return setError();
11945         }
11946 
11947 
11948         EXP cmpop = exp.op;
11949         if (auto e = exp.op_overload(sc, &cmpop))
11950         {
11951             if (!e.type.isscalar() && e.type.equals(exp.e1.type))
11952             {
11953                 exp.error("recursive `opCmp` expansion");
11954                 return setError();
11955             }
11956             if (e.op == EXP.call)
11957             {
11958 
11959                 if (t1.ty == Tclass && t2.ty == Tclass)
11960                 {
11961                     // Lower to object.__cmp(e1, e2)
11962                     Expression cl = new IdentifierExp(exp.loc, Id.empty);
11963                     cl = new DotIdExp(exp.loc, cl, Id.object);
11964                     cl = new DotIdExp(exp.loc, cl, Id.__cmp);
11965                     cl = cl.expressionSemantic(sc);
11966 
11967                     auto arguments = new Expressions();
11968                     // Check if op_overload found a better match by calling e2.opCmp(e1)
11969                     // If the operands were swapped, then the result must be reversed
11970                     // e1.opCmp(e2) == -e2.opCmp(e1)
11971                     // cmpop takes care of this
11972                     if (exp.op == cmpop)
11973                     {
11974                         arguments.push(exp.e1);
11975                         arguments.push(exp.e2);
11976                     }
11977                     else
11978                     {
11979                         // Use better match found by op_overload
11980                         arguments.push(exp.e2);
11981                         arguments.push(exp.e1);
11982                     }
11983 
11984                     cl = new CallExp(exp.loc, cl, arguments);
11985                     cl = new CmpExp(cmpop, exp.loc, cl, new IntegerExp(0));
11986                     result = cl.expressionSemantic(sc);
11987                     return;
11988                 }
11989 
11990                 e = new CmpExp(cmpop, exp.loc, e, IntegerExp.literal!0);
11991                 e = e.expressionSemantic(sc);
11992             }
11993             result = e;
11994             return;
11995         }
11996 
11997 
11998         if (Expression ex = typeCombine(exp, sc))
11999         {
12000             result = ex;
12001             return;
12002         }
12003 
12004         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12005         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12006         if (f1 || f2)
12007             return setError();
12008 
12009         exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12010 
12011         // Special handling for array comparisons
12012         Expression arrayLowering = null;
12013         t1 = exp.e1.type.toBasetype();
12014         t2 = exp.e2.type.toBasetype();
12015         if ((t1.ty == Tarray || t1.ty == Tsarray || t1.ty == Tpointer) && (t2.ty == Tarray || t2.ty == Tsarray || t2.ty == Tpointer))
12016         {
12017             Type t1next = t1.nextOf();
12018             Type t2next = t2.nextOf();
12019             if (t1next.implicitConvTo(t2next) < MATCH.constant && t2next.implicitConvTo(t1next) < MATCH.constant && (t1next.ty != Tvoid && t2next.ty != Tvoid))
12020             {
12021                 exp.error("array comparison type mismatch, `%s` vs `%s`", t1next.toChars(), t2next.toChars());
12022                 return setError();
12023             }
12024 
12025             if (sc.needsCodegen() &&
12026                 (t1.ty == Tarray || t1.ty == Tsarray) &&
12027                 (t2.ty == Tarray || t2.ty == Tsarray))
12028             {
12029                 if (!verifyHookExist(exp.loc, *sc, Id.__cmp, "comparing arrays"))
12030                     return setError();
12031 
12032                 // Lower to object.__cmp(e1, e2)
12033                 Expression al = new IdentifierExp(exp.loc, Id.empty);
12034                 al = new DotIdExp(exp.loc, al, Id.object);
12035                 al = new DotIdExp(exp.loc, al, Id.__cmp);
12036                 al = al.expressionSemantic(sc);
12037 
12038                 auto arguments = new Expressions(2);
12039                 (*arguments)[0] = exp.e1;
12040                 (*arguments)[1] = exp.e2;
12041 
12042                 al = new CallExp(exp.loc, al, arguments);
12043                 al = new CmpExp(exp.op, exp.loc, al, IntegerExp.literal!0);
12044 
12045                 arrayLowering = al;
12046             }
12047         }
12048         else if (t1.ty == Tstruct || t2.ty == Tstruct || (t1.ty == Tclass && t2.ty == Tclass))
12049         {
12050             if (t2.ty == Tstruct)
12051                 exp.error("need member function `opCmp()` for %s `%s` to compare", t2.toDsymbol(sc).kind(), t2.toChars());
12052             else
12053                 exp.error("need member function `opCmp()` for %s `%s` to compare", t1.toDsymbol(sc).kind(), t1.toChars());
12054             return setError();
12055         }
12056         else if (t1.iscomplex() || t2.iscomplex())
12057         {
12058             exp.error("compare not defined for complex operands");
12059             return setError();
12060         }
12061         else if (t1.ty == Taarray || t2.ty == Taarray)
12062         {
12063             exp.error("`%s` is not defined for associative arrays", EXPtoString(exp.op).ptr);
12064             return setError();
12065         }
12066         else if (!target.isVectorOpSupported(t1, exp.op, t2))
12067         {
12068             result = exp.incompatibleTypes();
12069             return;
12070         }
12071         else
12072         {
12073             bool r1 = exp.e1.checkValue() || exp.e1.checkSharedAccess(sc);
12074             bool r2 = exp.e2.checkValue() || exp.e2.checkSharedAccess(sc);
12075             if (r1 || r2)
12076                 return setError();
12077         }
12078 
12079         //printf("CmpExp: %s, type = %s\n", e.toChars(), e.type.toChars());
12080         if (arrayLowering)
12081         {
12082             arrayLowering = arrayLowering.expressionSemantic(sc);
12083             result = arrayLowering;
12084             return;
12085         }
12086 
12087         if (auto tv = t1.isTypeVector())
12088             exp.type = tv.toBooleanVector();
12089 
12090         result = exp;
12091         return;
12092     }
12093 
12094     override void visit(InExp exp)
12095     {
12096         if (exp.type)
12097         {
12098             result = exp;
12099             return;
12100         }
12101 
12102         if (Expression ex = binSemanticProp(exp, sc))
12103         {
12104             result = ex;
12105             return;
12106         }
12107         Expression e = exp.op_overload(sc);
12108         if (e)
12109         {
12110             result = e;
12111             return;
12112         }
12113 
12114         Type t2b = exp.e2.type.toBasetype();
12115         switch (t2b.ty)
12116         {
12117         case Taarray:
12118             {
12119                 TypeAArray ta = cast(TypeAArray)t2b;
12120 
12121                 // Special handling for array keys
12122                 if (!arrayTypeCompatibleWithoutCasting(exp.e1.type, ta.index))
12123                 {
12124                     // Convert key to type of key
12125                     exp.e1 = exp.e1.implicitCastTo(sc, ta.index);
12126                 }
12127 
12128                 semanticTypeInfo(sc, ta.index);
12129 
12130                 // Return type is pointer to value
12131                 exp.type = ta.nextOf().pointerTo();
12132                 break;
12133             }
12134 
12135         case Terror:
12136             return setError();
12137 
12138         case Tarray, Tsarray:
12139             result = exp.incompatibleTypes();
12140             exp.errorSupplemental("`in` is only allowed on associative arrays");
12141             const(char)* slice = (t2b.ty == Tsarray) ? "[]" : "";
12142             exp.errorSupplemental("perhaps use `std.algorithm.find(%s, %s%s)` instead",
12143                 exp.e1.toChars(), exp.e2.toChars(), slice);
12144             return;
12145 
12146         default:
12147             result = exp.incompatibleTypes();
12148             return;
12149         }
12150         result = exp;
12151     }
12152 
12153     override void visit(RemoveExp e)
12154     {
12155         if (Expression ex = binSemantic(e, sc))
12156         {
12157             result = ex;
12158             return;
12159         }
12160         result = e;
12161     }
12162 
12163     override void visit(EqualExp exp)
12164     {
12165         //printf("EqualExp::semantic('%s')\n", exp.toChars());
12166         if (exp.type)
12167         {
12168             result = exp;
12169             return;
12170         }
12171 
12172         exp.setNoderefOperands();
12173 
12174         if (auto e = binSemanticProp(exp, sc))
12175         {
12176             result = e;
12177             return;
12178         }
12179         if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12180         {
12181             /* https://issues.dlang.org/show_bug.cgi?id=12520
12182              * empty tuples are represented as types so special cases are added
12183              * so that they can be compared for equality with tuples of values.
12184              */
12185             static auto extractTypeTupAndExpTup(Expression e)
12186             {
12187                 static struct Result { bool ttEmpty; bool te; }
12188                 auto tt = e.op == EXP.type ? e.isTypeExp().type.isTypeTuple() : null;
12189                 return Result(tt && (!tt.arguments || !tt.arguments.length), e.isTupleExp() !is null);
12190             }
12191             auto tups1 = extractTypeTupAndExpTup(exp.e1);
12192             auto tups2 = extractTypeTupAndExpTup(exp.e2);
12193             // AliasSeq!() == AliasSeq!(<at least a value>)
12194             if (tups1.ttEmpty && tups2.te)
12195             {
12196                 result = IntegerExp.createBool(exp.op != EXP.equal);
12197                 return;
12198             }
12199             // AliasSeq!(<at least a value>) == AliasSeq!()
12200             else if (tups1.te && tups2.ttEmpty)
12201             {
12202                 result = IntegerExp.createBool(exp.op != EXP.equal);
12203                 return;
12204             }
12205             // AliasSeq!() == AliasSeq!()
12206             else if (tups1.ttEmpty && tups2.ttEmpty)
12207             {
12208                 result = IntegerExp.createBool(exp.op == EXP.equal);
12209                 return;
12210             }
12211             // otherwise, two types are really not comparable
12212             result = exp.incompatibleTypes();
12213             return;
12214         }
12215 
12216         {
12217             auto t1 = exp.e1.type;
12218             auto t2 = exp.e2.type;
12219             if (t1.ty == Tenum && t2.ty == Tenum && !t1.equivalent(t2))
12220                 exp.error("comparison between different enumeration types `%s` and `%s`; If this behavior is intended consider using `std.conv.asOriginalType`",
12221                     t1.toChars(), t2.toChars());
12222         }
12223 
12224         /* Before checking for operator overloading, check to see if we're
12225          * comparing the addresses of two statics. If so, we can just see
12226          * if they are the same symbol.
12227          */
12228         if (exp.e1.op == EXP.address && exp.e2.op == EXP.address)
12229         {
12230             AddrExp ae1 = cast(AddrExp)exp.e1;
12231             AddrExp ae2 = cast(AddrExp)exp.e2;
12232             if (ae1.e1.op == EXP.variable && ae2.e1.op == EXP.variable)
12233             {
12234                 VarExp ve1 = cast(VarExp)ae1.e1;
12235                 VarExp ve2 = cast(VarExp)ae2.e1;
12236                 if (ve1.var == ve2.var)
12237                 {
12238                     // They are the same, result is 'true' for ==, 'false' for !=
12239                     result = IntegerExp.createBool(exp.op == EXP.equal);
12240                     return;
12241                 }
12242             }
12243         }
12244 
12245         Type t1 = exp.e1.type.toBasetype();
12246         Type t2 = exp.e2.type.toBasetype();
12247 
12248         // Indicates whether the comparison of the 2 specified array types
12249         // requires an object.__equals() lowering.
12250         static bool needsDirectEq(Type t1, Type t2, Scope* sc)
12251         {
12252             Type t1n = t1.nextOf().toBasetype();
12253             Type t2n = t2.nextOf().toBasetype();
12254             if ((t1n.ty.isSomeChar && t2n.ty.isSomeChar) ||
12255                 (t1n.ty == Tvoid || t2n.ty == Tvoid))
12256             {
12257                 return false;
12258             }
12259             if (t1n.constOf() != t2n.constOf())
12260                 return true;
12261 
12262             Type t = t1n;
12263             while (t.toBasetype().nextOf())
12264                 t = t.nextOf().toBasetype();
12265             if (auto ts = t.isTypeStruct())
12266             {
12267                 // semanticTypeInfo() makes sure hasIdentityEquals has been computed
12268                 if (global.params.useTypeInfo && Type.dtypeinfo)
12269                     semanticTypeInfo(sc, ts);
12270 
12271                 return ts.sym.hasIdentityEquals; // has custom opEquals
12272             }
12273 
12274             return false;
12275         }
12276 
12277         if (auto e = exp.op_overload(sc))
12278         {
12279             result = e;
12280             return;
12281         }
12282 
12283 
12284         const isArrayComparison = (t1.ty == Tarray || t1.ty == Tsarray) &&
12285                                   (t2.ty == Tarray || t2.ty == Tsarray);
12286         const needsArrayLowering = isArrayComparison && needsDirectEq(t1, t2, sc);
12287 
12288         if (!needsArrayLowering)
12289         {
12290             // https://issues.dlang.org/show_bug.cgi?id=23783
12291             if (exp.e1.checkSharedAccess(sc) || exp.e2.checkSharedAccess(sc))
12292                 return setError();
12293             if (auto e = typeCombine(exp, sc))
12294             {
12295                 result = e;
12296                 return;
12297             }
12298         }
12299 
12300         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12301         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12302         if (f1 || f2)
12303             return setError();
12304 
12305         exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
12306 
12307         if (!isArrayComparison)
12308         {
12309             if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12310             {
12311                 // Cast both to complex
12312                 exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12313                 exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12314             }
12315         }
12316 
12317         // lower some array comparisons to object.__equals(e1, e2)
12318         if (needsArrayLowering || (t1.ty == Tarray && t2.ty == Tarray))
12319         {
12320             //printf("Lowering to __equals %s %s\n", exp.e1.toChars(), exp.e2.toChars());
12321 
12322             // https://issues.dlang.org/show_bug.cgi?id=22390
12323             // Equality comparison between array of noreturns simply lowers to length equality comparison
12324             if (t1.nextOf.isTypeNoreturn() && t2.nextOf.isTypeNoreturn())
12325             {
12326                 Expression exp_l1 = new DotIdExp(exp.e1.loc, exp.e1, Id.length);
12327                 Expression exp_l2 = new DotIdExp(exp.e2.loc, exp.e2, Id.length);
12328                 auto e = new EqualExp(EXP.equal, exp.loc, exp_l1, exp_l2);
12329                 result = e.expressionSemantic(sc);
12330                 return;
12331             }
12332 
12333             if (!verifyHookExist(exp.loc, *sc, Id.__equals, "equal checks on arrays"))
12334                 return setError();
12335 
12336             Expression __equals = new IdentifierExp(exp.loc, Id.empty);
12337             Identifier id = Identifier.idPool("__equals");
12338             __equals = new DotIdExp(exp.loc, __equals, Id.object);
12339             __equals = new DotIdExp(exp.loc, __equals, id);
12340 
12341             /* https://issues.dlang.org/show_bug.cgi?id=23674
12342              *
12343              * Optimize before creating the call expression to the
12344              * druntime hook as the optimizer may output errors
12345              * that will get swallowed otherwise.
12346              */
12347             exp.e1 = exp.e1.optimize(WANTvalue);
12348             exp.e2 = exp.e2.optimize(WANTvalue);
12349 
12350             auto arguments = new Expressions(2);
12351             (*arguments)[0] = exp.e1;
12352             (*arguments)[1] = exp.e2;
12353 
12354             __equals = new CallExp(exp.loc, __equals, arguments);
12355             if (exp.op == EXP.notEqual)
12356             {
12357                 __equals = new NotExp(exp.loc, __equals);
12358             }
12359             __equals = __equals.trySemantic(sc); // for better error message
12360             if (!__equals)
12361             {
12362                 exp.error("incompatible types for array comparison: `%s` and `%s`",
12363                           exp.e1.type.toChars(), exp.e2.type.toChars());
12364                 __equals = ErrorExp.get();
12365             }
12366 
12367             result = __equals;
12368             return;
12369         }
12370 
12371         if (exp.e1.type.toBasetype().ty == Taarray)
12372             semanticTypeInfo(sc, exp.e1.type.toBasetype());
12373 
12374 
12375         if (!target.isVectorOpSupported(t1, exp.op, t2))
12376         {
12377             result = exp.incompatibleTypes();
12378             return;
12379         }
12380 
12381         if (auto tv = t1.isTypeVector())
12382             exp.type = tv.toBooleanVector();
12383 
12384         result = exp;
12385     }
12386 
12387     override void visit(IdentityExp exp)
12388     {
12389         if (exp.type)
12390         {
12391             result = exp;
12392             return;
12393         }
12394 
12395         exp.setNoderefOperands();
12396 
12397         if (auto e = binSemanticProp(exp, sc))
12398         {
12399             result = e;
12400             return;
12401         }
12402 
12403         if (auto e = typeCombine(exp, sc))
12404         {
12405             result = e;
12406             return;
12407         }
12408 
12409         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12410         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12411         if (f1 || f2)
12412             return setError();
12413 
12414         if (exp.e1.op == EXP.type || exp.e2.op == EXP.type)
12415         {
12416             result = exp.incompatibleTypes();
12417             return;
12418         }
12419 
12420         exp.type = Type.tbool;
12421 
12422         if (exp.e1.type != exp.e2.type && exp.e1.type.isfloating() && exp.e2.type.isfloating())
12423         {
12424             // Cast both to complex
12425             exp.e1 = exp.e1.castTo(sc, Type.tcomplex80);
12426             exp.e2 = exp.e2.castTo(sc, Type.tcomplex80);
12427         }
12428 
12429         auto tb1 = exp.e1.type.toBasetype();
12430         auto tb2 = exp.e2.type.toBasetype();
12431         if (!target.isVectorOpSupported(tb1, exp.op, tb2))
12432         {
12433             result = exp.incompatibleTypes();
12434             return;
12435         }
12436 
12437         if (exp.e1.op == EXP.call)
12438             exp.e1 = (cast(CallExp)exp.e1).addDtorHook(sc);
12439         if (exp.e2.op == EXP.call)
12440             exp.e2 = (cast(CallExp)exp.e2).addDtorHook(sc);
12441 
12442         if (exp.e1.type.toBasetype().ty == Tsarray ||
12443             exp.e2.type.toBasetype().ty == Tsarray)
12444             exp.deprecation("identity comparison of static arrays "
12445                 ~ "implicitly coerces them to slices, "
12446                 ~ "which are compared by reference");
12447 
12448         result = exp;
12449     }
12450 
12451     override void visit(CondExp exp)
12452     {
12453         static if (LOGSEMANTIC)
12454         {
12455             printf("CondExp::semantic('%s')\n", exp.toChars());
12456         }
12457         if (exp.type)
12458         {
12459             result = exp;
12460             return;
12461         }
12462 
12463         if (auto die = exp.econd.isDotIdExp())
12464             die.noderef = true;
12465 
12466         Expression ec = exp.econd.expressionSemantic(sc);
12467         ec = resolveProperties(sc, ec);
12468         ec = ec.toBoolean(sc);
12469 
12470         CtorFlow ctorflow_root = sc.ctorflow.clone();
12471         Expression e1x = exp.e1.expressionSemantic(sc).arrayFuncConv(sc);
12472         e1x = resolveProperties(sc, e1x);
12473 
12474         CtorFlow ctorflow1 = sc.ctorflow;
12475         sc.ctorflow = ctorflow_root;
12476         Expression e2x = exp.e2.expressionSemantic(sc).arrayFuncConv(sc);
12477         e2x = resolveProperties(sc, e2x);
12478 
12479         sc.merge(exp.loc, ctorflow1);
12480         ctorflow1.freeFieldinit();
12481 
12482         if (ec.op == EXP.error)
12483         {
12484             result = ec;
12485             return;
12486         }
12487         if (ec.type == Type.terror)
12488             return setError();
12489         exp.econd = ec;
12490 
12491         if (e1x.op == EXP.error)
12492         {
12493             result = e1x;
12494             return;
12495         }
12496         if (e1x.type == Type.terror)
12497             return setError();
12498         exp.e1 = e1x;
12499 
12500         if (e2x.op == EXP.error)
12501         {
12502             result = e2x;
12503             return;
12504         }
12505         if (e2x.type == Type.terror)
12506             return setError();
12507         exp.e2 = e2x;
12508 
12509         auto f0 = checkNonAssignmentArrayOp(exp.econd);
12510         auto f1 = checkNonAssignmentArrayOp(exp.e1);
12511         auto f2 = checkNonAssignmentArrayOp(exp.e2);
12512         if (f0 || f1 || f2)
12513             return setError();
12514 
12515         Type t1 = exp.e1.type;
12516         Type t2 = exp.e2.type;
12517 
12518         // https://issues.dlang.org/show_bug.cgi?id=23767
12519         // `cast(void*) 0` should be treated as `null` so the ternary expression
12520         // gets the pointer type of the other branch
12521         if (sc.flags & SCOPE.Cfile)
12522         {
12523             static void rewriteCNull(ref Expression e, ref Type t)
12524             {
12525                 if (!t.isTypePointer())
12526                     return;
12527                 if (auto ie = e.optimize(WANTvalue).isIntegerExp())
12528                 {
12529                     if (ie.getInteger() == 0)
12530                     {
12531                         e = new NullExp(e.loc, Type.tnull);
12532                         t = Type.tnull;
12533                     }
12534                 }
12535             }
12536             rewriteCNull(exp.e1, t1);
12537             rewriteCNull(exp.e2, t2);
12538         }
12539 
12540         if (t1.ty == Tnoreturn)
12541         {
12542             exp.type = t2;
12543             exp.e1 = specialNoreturnCast(exp.e1, exp.type);
12544         }
12545         else if (t2.ty == Tnoreturn)
12546         {
12547             exp.type = t1;
12548             exp.e2 = specialNoreturnCast(exp.e2, exp.type);
12549         }
12550         // If either operand is void the result is void, we have to cast both
12551         // the expression to void so that we explicitly discard the expression
12552         // value if any
12553         // https://issues.dlang.org/show_bug.cgi?id=16598
12554         else if (t1.ty == Tvoid || t2.ty == Tvoid)
12555         {
12556             exp.type = Type.tvoid;
12557             exp.e1 = exp.e1.castTo(sc, exp.type);
12558             exp.e2 = exp.e2.castTo(sc, exp.type);
12559         }
12560         else if (t1 == t2)
12561             exp.type = t1;
12562         else
12563         {
12564             if (Expression ex = typeCombine(exp, sc))
12565             {
12566                 result = ex;
12567                 return;
12568             }
12569 
12570             switch (exp.e1.type.toBasetype().ty)
12571             {
12572             case Tcomplex32:
12573             case Tcomplex64:
12574             case Tcomplex80:
12575                 exp.e2 = exp.e2.castTo(sc, exp.e1.type);
12576                 break;
12577             default:
12578                 break;
12579             }
12580             switch (exp.e2.type.toBasetype().ty)
12581             {
12582             case Tcomplex32:
12583             case Tcomplex64:
12584             case Tcomplex80:
12585                 exp.e1 = exp.e1.castTo(sc, exp.e2.type);
12586                 break;
12587             default:
12588                 break;
12589             }
12590             if (exp.type.toBasetype().ty == Tarray)
12591             {
12592                 exp.e1 = exp.e1.castTo(sc, exp.type);
12593                 exp.e2 = exp.e2.castTo(sc, exp.type);
12594             }
12595         }
12596         exp.type = exp.type.merge2();
12597         version (none)
12598         {
12599             printf("res: %s\n", exp.type.toChars());
12600             printf("e1 : %s\n", exp.e1.type.toChars());
12601             printf("e2 : %s\n", exp.e2.type.toChars());
12602         }
12603 
12604         /* https://issues.dlang.org/show_bug.cgi?id=14696
12605          * If either e1 or e2 contain temporaries which need dtor,
12606          * make them conditional.
12607          * Rewrite:
12608          *      cond ? (__tmp1 = ..., __tmp1) : (__tmp2 = ..., __tmp2)
12609          * to:
12610          *      (auto __cond = cond) ? (... __tmp1) : (... __tmp2)
12611          * and replace edtors of __tmp1 and __tmp2 with:
12612          *      __tmp1.edtor --> __cond && __tmp1.dtor()
12613          *      __tmp2.edtor --> __cond || __tmp2.dtor()
12614          */
12615         exp.hookDtors(sc);
12616 
12617         result = exp;
12618     }
12619 
12620     override void visit(GenericExp exp)
12621     {
12622         static if (LOGSEMANTIC)
12623         {
12624             printf("GenericExp::semantic('%s')\n", exp.toChars());
12625         }
12626         // C11 6.5.1.1 Generic Selection
12627 
12628         auto ec = exp.cntlExp.expressionSemantic(sc).arrayFuncConv(sc);
12629         bool errors = ec.isErrorExp() !is null;
12630         auto tc = ec.type;
12631 
12632         auto types = (*exp.types)[];
12633         foreach (i, ref t; types)
12634         {
12635             if (!t)
12636                 continue;       // `default:` case
12637             t = t.typeSemantic(ec.loc, sc);
12638             if (t.isTypeError())
12639             {
12640                 errors = true;
12641                 continue;
12642             }
12643 
12644             /* C11 6.5.1-2 duplicate check
12645              */
12646             /* C11 distinguishes int, long, and long long. But D doesn't, so depending on the
12647              * C target, a long may have the same type as `int` in the D type system.
12648              * So, skip checks when this may be the case. Later pick the first match
12649              */
12650             if (
12651                 (t.ty == Tint32 || t.ty == Tuns32) && target.c.longsize == 4 ||
12652                 (t.ty == Tint64 || t.ty == Tuns64) && target.c.longsize == 8 ||
12653                 (t.ty == Tfloat64 || t.ty == Timaginary64 || t.ty == Tcomplex64) && target.c.long_doublesize == 8
12654                )
12655                 continue;
12656 
12657             foreach (t2; types[0 .. i])
12658             {
12659                 if (t2 && t2.equals(t))
12660                 {
12661                     error(ec.loc, "generic association type `%s` can only appear once", t.toChars());
12662                     errors = true;
12663                     break;
12664                 }
12665             }
12666         }
12667 
12668         auto exps = (*exp.exps)[];
12669         foreach (ref e; exps)
12670         {
12671             e = e.expressionSemantic(sc);
12672             if (e.isErrorExp())
12673                 errors = true;
12674         }
12675 
12676         if (errors)
12677             return setError();
12678 
12679         enum size_t None = ~0;
12680         size_t imatch = None;
12681         size_t idefault = None;
12682         foreach (const i, t; types)
12683         {
12684             if (t)
12685             {
12686                 /* if tc is compatible with t, it's a match
12687                  * C11 6.2.7 defines a compatible type as being the same type, including qualifiers
12688                  */
12689                 if (tc.equals(t))
12690                 {
12691                     assert(imatch == None);
12692                     imatch = i;
12693                     break;              // pick first match
12694                 }
12695             }
12696             else
12697                 idefault = i;  // multiple defaults are not allowed, and are caught by cparse
12698         }
12699 
12700         if (imatch == None)
12701             imatch = idefault;
12702         if (imatch == None)
12703         {
12704             error(exp.loc, "no compatible generic association type for controlling expression type `%s`", tc.toChars());
12705             return setError();
12706         }
12707 
12708         result = exps[imatch];
12709     }
12710 
12711     override void visit(FileInitExp e)
12712     {
12713         //printf("FileInitExp::semantic()\n");
12714         e.type = Type.tstring;
12715         result = e;
12716     }
12717 
12718     override void visit(LineInitExp e)
12719     {
12720         e.type = Type.tint32;
12721         result = e;
12722     }
12723 
12724     override void visit(ModuleInitExp e)
12725     {
12726         //printf("ModuleInitExp::semantic()\n");
12727         e.type = Type.tstring;
12728         result = e;
12729     }
12730 
12731     override void visit(FuncInitExp e)
12732     {
12733         //printf("FuncInitExp::semantic()\n");
12734         e.type = Type.tstring;
12735         if (sc.func)
12736         {
12737             result = e.resolveLoc(Loc.initial, sc);
12738             return;
12739         }
12740         result = e;
12741     }
12742 
12743     override void visit(PrettyFuncInitExp e)
12744     {
12745         //printf("PrettyFuncInitExp::semantic()\n");
12746         e.type = Type.tstring;
12747         if (sc.func)
12748         {
12749             result = e.resolveLoc(Loc.initial, sc);
12750             return;
12751         }
12752 
12753         result = e;
12754     }
12755 }
12756 
12757 /**********************************
12758  * Try to run semantic routines.
12759  * If they fail, return NULL.
12760  */
12761 Expression trySemantic(Expression exp, Scope* sc)
12762 {
12763     //printf("+trySemantic(%s)\n", exp.toChars());
12764     uint errors = global.startGagging();
12765     Expression e = expressionSemantic(exp, sc);
12766     if (global.endGagging(errors))
12767     {
12768         e = null;
12769     }
12770     //printf("-trySemantic(%s)\n", exp.toChars());
12771     return e;
12772 }
12773 
12774 /**************************
12775  * Helper function for easy error propagation.
12776  * If error occurs, returns ErrorExp. Otherwise returns NULL.
12777  */
12778 Expression unaSemantic(UnaExp e, Scope* sc)
12779 {
12780     static if (LOGSEMANTIC)
12781     {
12782         printf("UnaExp::semantic('%s')\n", e.toChars());
12783     }
12784     Expression e1x = e.e1.expressionSemantic(sc);
12785     if (e1x.op == EXP.error)
12786         return e1x;
12787     e.e1 = e1x;
12788     return null;
12789 }
12790 
12791 /**************************
12792  * Helper function for easy error propagation.
12793  * If error occurs, returns ErrorExp. Otherwise returns NULL.
12794  */
12795 Expression binSemantic(BinExp e, Scope* sc)
12796 {
12797     static if (LOGSEMANTIC)
12798     {
12799         printf("BinExp::semantic('%s')\n", e.toChars());
12800     }
12801     Expression e1x = e.e1.expressionSemantic(sc);
12802     Expression e2x = e.e2.expressionSemantic(sc);
12803 
12804     // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
12805     if (e1x.op == EXP.type)
12806         e1x = resolveAliasThis(sc, e1x);
12807     if (e2x.op == EXP.type)
12808         e2x = resolveAliasThis(sc, e2x);
12809 
12810     if (e1x.op == EXP.error)
12811         return e1x;
12812     if (e2x.op == EXP.error)
12813         return e2x;
12814     e.e1 = e1x;
12815     e.e2 = e2x;
12816     return null;
12817 }
12818 
12819 Expression binSemanticProp(BinExp e, Scope* sc)
12820 {
12821     if (Expression ex = binSemantic(e, sc))
12822         return ex;
12823     Expression e1x = resolveProperties(sc, e.e1);
12824     Expression e2x = resolveProperties(sc, e.e2);
12825     if (e1x.op == EXP.error)
12826         return e1x;
12827     if (e2x.op == EXP.error)
12828         return e2x;
12829     e.e1 = e1x;
12830     e.e2 = e2x;
12831     return null;
12832 }
12833 
12834 // entrypoint for semantic ExpressionSemanticVisitor
12835 extern (C++) Expression expressionSemantic(Expression e, Scope* sc)
12836 {
12837     scope v = new ExpressionSemanticVisitor(sc);
12838     e.accept(v);
12839     return v.result;
12840 }
12841 
12842 private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
12843 {
12844     //printf("DotIdExp::semanticX(this = %p, '%s')\n", this, toChars());
12845     if (Expression ex = unaSemantic(exp, sc))
12846         return ex;
12847 
12848     if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
12849     {
12850         // symbol.mangleof
12851 
12852         // return mangleof as an Expression
12853         static Expression dotMangleof(const ref Loc loc, Scope* sc, Dsymbol ds)
12854         {
12855             assert(ds);
12856             if (auto f = ds.isFuncDeclaration())
12857             {
12858                 if (f.checkForwardRef(loc))
12859                     return ErrorExp.get();
12860 
12861                 if (f.purityInprocess || f.safetyInprocess || f.nothrowInprocess || f.nogcInprocess)
12862                 {
12863                     f.error(loc, "cannot retrieve its `.mangleof` while inferring attributes");
12864                     return ErrorExp.get();
12865                 }
12866             }
12867             OutBuffer buf;
12868             mangleToBuffer(ds, &buf);
12869             Expression e = new StringExp(loc, buf.extractSlice());
12870             return e.expressionSemantic(sc);
12871         }
12872 
12873         Dsymbol ds;
12874         switch (exp.e1.op)
12875         {
12876             case EXP.scope_:      return dotMangleof(exp.loc, sc, exp.e1.isScopeExp().sds);
12877             case EXP.variable:    return dotMangleof(exp.loc, sc, exp.e1.isVarExp().var);
12878             case EXP.dotVariable: return dotMangleof(exp.loc, sc, exp.e1.isDotVarExp().var);
12879             case EXP.overloadSet: return dotMangleof(exp.loc, sc, exp.e1.isOverExp().vars);
12880             case EXP.template_:
12881             {
12882                 TemplateExp te = exp.e1.isTemplateExp();
12883                 return dotMangleof(exp.loc, sc, ds = te.fd ? te.fd.isDsymbol() : te.td);
12884             }
12885 
12886             default:
12887                 break;
12888         }
12889     }
12890 
12891     if (exp.e1.isVarExp() && exp.e1.type.toBasetype().isTypeSArray() && exp.ident == Id.length)
12892     {
12893         // bypass checkPurity
12894         return exp.e1.type.dotExp(sc, exp.e1, exp.ident, cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref));
12895     }
12896 
12897     if (!exp.e1.isDotExp())
12898     {
12899         exp.e1 = resolvePropertiesX(sc, exp.e1);
12900     }
12901 
12902     if (auto te = exp.e1.isTupleExp())
12903     {
12904         if (exp.ident == Id.offsetof)
12905         {
12906             /* 'distribute' the .offsetof to each of the tuple elements.
12907              */
12908             auto exps = new Expressions(te.exps.length);
12909             foreach (i, e; (*te.exps)[])
12910             {
12911                 (*exps)[i] = new DotIdExp(e.loc, e, Id.offsetof);
12912             }
12913             // Don't evaluate te.e0 in runtime
12914             Expression e = new TupleExp(exp.loc, null, exps);
12915             e = e.expressionSemantic(sc);
12916             return e;
12917         }
12918         if (exp.ident == Id.length)
12919         {
12920             // Don't evaluate te.e0 in runtime
12921             return new IntegerExp(exp.loc, te.exps.length, Type.tsize_t);
12922         }
12923     }
12924 
12925     // https://issues.dlang.org/show_bug.cgi?id=14416
12926     // Template has no built-in properties except for 'stringof'.
12927     if ((exp.e1.isDotTemplateExp() || exp.e1.isTemplateExp()) && exp.ident != Id.stringof)
12928     {
12929         exp.error("template `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12930         return ErrorExp.get();
12931     }
12932     if (!exp.e1.type)
12933     {
12934         exp.error("expression `%s` does not have property `%s`", exp.e1.toChars(), exp.ident.toChars());
12935         return ErrorExp.get();
12936     }
12937 
12938     return exp;
12939 }
12940 
12941 /******************************
12942  * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
12943  * Params:
12944  *      exp = expression to resolve
12945  *      sc = context
12946  *      gag = do not emit error messages, just return `null`
12947  * Returns:
12948  *      resolved expression, null if error
12949  */
12950 Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
12951 {
12952     //printf("DotIdExp::semanticY(this = %p, '%s')\n", exp, exp.toChars());
12953 
12954     //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
12955 
12956     const cfile = (sc.flags & SCOPE.Cfile) != 0;
12957 
12958     /* Special case: rewrite this.id and super.id
12959      * to be classtype.id and baseclasstype.id
12960      * if we have no this pointer.
12961      */
12962     if ((exp.e1.isThisExp() || exp.e1.isSuperExp()) && !hasThis(sc))
12963     {
12964         if (AggregateDeclaration ad = sc.getStructClassScope())
12965         {
12966             if (exp.e1.isThisExp())
12967             {
12968                 exp.e1 = new TypeExp(exp.e1.loc, ad.type);
12969             }
12970             else
12971             {
12972                 if (auto cd = ad.isClassDeclaration())
12973                 {
12974                     if (cd.baseClass)
12975                         exp.e1 = new TypeExp(exp.e1.loc, cd.baseClass.type);
12976                 }
12977             }
12978         }
12979     }
12980 
12981     {
12982         Expression e = dotIdSemanticPropX(exp, sc);
12983         if (e != exp)
12984             return e;
12985     }
12986 
12987     Expression eleft;
12988     Expression eright;
12989     if (auto de = exp.e1.isDotExp())
12990     {
12991         eleft = de.e1;
12992         eright = de.e2;
12993     }
12994     else
12995     {
12996         eleft = null;
12997         eright = exp.e1;
12998     }
12999 
13000     Type t1b = exp.e1.type.toBasetype();
13001 
13002     if (auto ie = eright.isScopeExp()) // also used for template alias's
13003     {
13004         auto flags = SearchLocalsOnly;
13005         /* Disable access to another module's private imports.
13006          * The check for 'is sds our current module' is because
13007          * the current module should have access to its own imports.
13008          */
13009         if (ie.sds.isModule() && ie.sds != sc._module)
13010             flags |= IgnorePrivateImports;
13011         if (sc.flags & SCOPE.ignoresymbolvisibility)
13012             flags |= IgnoreSymbolVisibility;
13013         Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
13014         /* Check for visibility before resolving aliases because public
13015          * aliases to private symbols are public.
13016          */
13017         if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
13018         {
13019             s = null;
13020         }
13021         if (s)
13022         {
13023             auto p = s.isPackage();
13024             if (p && checkAccess(sc, p))
13025             {
13026                 s = null;
13027             }
13028         }
13029         if (s)
13030         {
13031             // if 's' is a tuple variable, the tuple is returned.
13032             s = s.toAlias();
13033 
13034             exp.checkDeprecated(sc, s);
13035             exp.checkDisabled(sc, s);
13036 
13037             if (auto em = s.isEnumMember())
13038             {
13039                 return em.getVarExp(exp.loc, sc);
13040             }
13041             if (auto v = s.isVarDeclaration())
13042             {
13043                 //printf("DotIdExp:: Identifier '%s' is a variable, type '%s'\n", toChars(), v.type.toChars());
13044                 if (!v.type ||
13045                     !v.type.deco && v.inuse)
13046                 {
13047                     if (v.inuse)
13048                         exp.error("circular reference to %s `%s`", v.kind(), v.toPrettyChars());
13049                     else
13050                         exp.error("forward reference to %s `%s`", v.kind(), v.toPrettyChars());
13051                     return ErrorExp.get();
13052                 }
13053                 if (v.type.isTypeError())
13054                     return ErrorExp.get();
13055 
13056                 if ((v.storage_class & STC.manifest) && v._init && !exp.wantsym)
13057                 {
13058                     /* Normally, the replacement of a symbol with its initializer is supposed to be in semantic2().
13059                      * Introduced by https://github.com/dlang/dmd/pull/5588 which should probably
13060                      * be reverted. `wantsym` is the hack to work around the problem.
13061                      */
13062                     if (v.inuse)
13063                     {
13064                         error(exp.loc, "circular initialization of %s `%s`", v.kind(), v.toPrettyChars());
13065                         return ErrorExp.get();
13066                     }
13067                     auto e = v.expandInitializer(exp.loc);
13068                     v.inuse++;
13069                     e = e.expressionSemantic(sc);
13070                     v.inuse--;
13071                     return e;
13072                 }
13073 
13074                 Expression e;
13075                 if (v.needThis())
13076                 {
13077                     if (!eleft)
13078                         eleft = new ThisExp(exp.loc);
13079                     e = new DotVarExp(exp.loc, eleft, v);
13080                     e = e.expressionSemantic(sc);
13081                 }
13082                 else
13083                 {
13084                     e = new VarExp(exp.loc, v);
13085                     if (eleft)
13086                     {
13087                         e = new CommaExp(exp.loc, eleft, e);
13088                         e.type = v.type;
13089                     }
13090                 }
13091                 e = e.deref();
13092                 return e.expressionSemantic(sc);
13093             }
13094 
13095             if (auto f = s.isFuncDeclaration())
13096             {
13097                 //printf("it's a function\n");
13098                 if (!f.functionSemantic())
13099                     return ErrorExp.get();
13100                 Expression e;
13101                 if (f.needThis())
13102                 {
13103                     if (!eleft)
13104                         eleft = new ThisExp(exp.loc);
13105                     e = new DotVarExp(exp.loc, eleft, f, true);
13106                     e = e.expressionSemantic(sc);
13107                 }
13108                 else
13109                 {
13110                     e = new VarExp(exp.loc, f, true);
13111                     if (eleft)
13112                     {
13113                         e = new CommaExp(exp.loc, eleft, e);
13114                         e.type = f.type;
13115                     }
13116                 }
13117                 return e;
13118             }
13119             if (auto td = s.isTemplateDeclaration())
13120             {
13121                 Expression e;
13122                 if (eleft)
13123                     e = new DotTemplateExp(exp.loc, eleft, td);
13124                 else
13125                     e = new TemplateExp(exp.loc, td);
13126                 e = e.expressionSemantic(sc);
13127                 return e;
13128             }
13129             if (OverDeclaration od = s.isOverDeclaration())
13130             {
13131                 Expression e = new VarExp(exp.loc, od, true);
13132                 if (eleft)
13133                 {
13134                     e = new CommaExp(exp.loc, eleft, e);
13135                     e.type = Type.tvoid; // ambiguous type?
13136                 }
13137                 return e.expressionSemantic(sc);
13138             }
13139             if (auto o = s.isOverloadSet())
13140             {
13141                 //printf("'%s' is an overload set\n", o.toChars());
13142                 return new OverExp(exp.loc, o);
13143             }
13144 
13145             if (auto t = s.getType())
13146             {
13147                 return (new TypeExp(exp.loc, t)).expressionSemantic(sc);
13148             }
13149 
13150             if (auto tup = s.isTupleDeclaration())
13151             {
13152                 if (eleft)
13153                 {
13154                     Expression e = new DotVarExp(exp.loc, eleft, tup);
13155                     e = e.expressionSemantic(sc);
13156                     return e;
13157                 }
13158                 Expression e = new TupleExp(exp.loc, tup);
13159                 e = e.expressionSemantic(sc);
13160                 return e;
13161             }
13162 
13163             if (auto sds = s.isScopeDsymbol())
13164             {
13165                 //printf("it's a ScopeDsymbol %s\n", ident.toChars());
13166                 Expression e = new ScopeExp(exp.loc, sds);
13167                 e = e.expressionSemantic(sc);
13168                 if (eleft)
13169                     e = new DotExp(exp.loc, eleft, e);
13170                 return e;
13171             }
13172 
13173             if (auto imp = s.isImport())
13174             {
13175                 Expression se = new ScopeExp(exp.loc, imp.pkg);
13176                 return se.expressionSemantic(sc);
13177             }
13178 
13179             if (auto attr = s.isAttribDeclaration())
13180             {
13181                 if (auto sm = ie.sds.search(exp.loc, exp.ident, flags))
13182                 {
13183                     auto es = new DsymbolExp(exp.loc, sm);
13184                     return es;
13185                 }
13186             }
13187 
13188             // BUG: handle other cases like in IdentifierExp::semantic()
13189             debug
13190             {
13191                 printf("s = %p '%s', kind = '%s'\n", s, s.toChars(), s.kind());
13192             }
13193             assert(0);
13194         }
13195         else if (exp.ident == Id.stringof)
13196         {
13197             Expression e = new StringExp(exp.loc, ie.toString());
13198             e = e.expressionSemantic(sc);
13199             return e;
13200         }
13201         if (ie.sds.isPackage() || ie.sds.isImport() || ie.sds.isModule())
13202         {
13203             gag = false;
13204         }
13205         if (gag)
13206             return null;
13207         s = ie.sds.search_correct(exp.ident);
13208         if (s && symbolIsVisible(sc, s))
13209         {
13210             if (s.isPackage())
13211                 exp.error("undefined identifier `%s` in %s `%s`, perhaps add `static import %s;`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.toPrettyChars());
13212             else
13213                 exp.error("undefined identifier `%s` in %s `%s`, did you mean %s `%s`?", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars(), s.kind(), s.toChars());
13214         }
13215         else
13216             exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
13217         return ErrorExp.get();
13218     }
13219     else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
13220              !(
13221                exp.ident == Id.__sizeof ||
13222                exp.ident == Id.__xalignof ||
13223                !cfile &&
13224                 (exp.ident == Id._mangleof ||
13225                  exp.ident == Id.offsetof ||
13226                  exp.ident == Id._init ||
13227                  exp.ident == Id.stringof)
13228               ))
13229     {
13230         Type t1bn = t1b.nextOf();
13231         if (gag)
13232         {
13233             if (AggregateDeclaration ad = isAggregate(t1bn))
13234             {
13235                 if (!ad.members) // https://issues.dlang.org/show_bug.cgi?id=11312
13236                     return null;
13237             }
13238         }
13239 
13240         /* Rewrite:
13241          *   p.ident
13242          * as:
13243          *   (*p).ident
13244          */
13245         if (gag && t1bn.ty == Tvoid)
13246             return null;
13247         Expression e = new PtrExp(exp.loc, exp.e1);
13248         e = e.expressionSemantic(sc);
13249         const newFlag = cast(DotExpFlag) (gag * DotExpFlag.gag | exp.noderef * DotExpFlag.noDeref);
13250         return e.type.dotExp(sc, e, exp.ident, newFlag);
13251     }
13252     else if (exp.ident == Id.__xalignof &&
13253              exp.e1.isVarExp() &&
13254              exp.e1.isVarExp().var.isVarDeclaration() &&
13255              !exp.e1.isVarExp().var.isVarDeclaration().alignment.isUnknown())
13256     {
13257         // For `x.alignof` get the alignment of the variable, not the alignment of its type
13258         const explicitAlignment = exp.e1.isVarExp().var.isVarDeclaration().alignment;
13259         const naturalAlignment = exp.e1.type.alignsize();
13260         const actualAlignment = explicitAlignment.isDefault() ? naturalAlignment : explicitAlignment.get();
13261         Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
13262         return e;
13263     }
13264     else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13265              exp.e1.isVarExp() &&
13266              exp.e1.isVarExp().var.isBitFieldDeclaration())
13267     {
13268         // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13269         auto bf = exp.e1.isVarExp().var.isBitFieldDeclaration();
13270         return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13271     }
13272     else if ((exp.ident == Id.max || exp.ident == Id.min) &&
13273              exp.e1.isDotVarExp() &&
13274              exp.e1.isDotVarExp().var.isBitFieldDeclaration())
13275     {
13276         // For `x.max` and `x.min` get the max/min of the bitfield, not the max/min of its type
13277         auto bf = exp.e1.isDotVarExp().var.isBitFieldDeclaration();
13278         return new IntegerExp(exp.loc, bf.getMinMax(exp.ident), bf.type);
13279     }
13280     else
13281     {
13282         if (exp.e1.isTypeExp() || exp.e1.isTemplateExp())
13283             gag = false;
13284 
13285         const flag = cast(DotExpFlag) (exp.noderef * DotExpFlag.noDeref | gag * DotExpFlag.gag);
13286 
13287         Expression e = exp.e1.type.dotExp(sc, exp.e1, exp.ident, flag);
13288         if (e)
13289         {
13290             e = e.expressionSemantic(sc);
13291         }
13292         return e;
13293     }
13294 }
13295 
13296 /**
13297  * Resolve `e1.ident!tiargs` without seeing UFCS.
13298  * Params:
13299  *     exp = the `DotTemplateInstanceExp` to resolve
13300  *     sc = the semantic scope
13301  *     gag = stop "not a property" error and return `null`.
13302  * Returns:
13303  *     `null` if error or not found, or the resolved expression.
13304  */
13305 Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool gag)
13306 {
13307     static if (LOGSEMANTIC)
13308     {
13309         printf("DotTemplateInstanceExpY::semantic('%s')\n", exp.toChars());
13310     }
13311 
13312     static Expression errorExp()
13313     {
13314         return ErrorExp.get();
13315     }
13316 
13317     Expression e1 = exp.e1;
13318 
13319     if (exp.ti.tempdecl && exp.ti.tempdecl.parent && exp.ti.tempdecl.parent.isTemplateMixin())
13320     {
13321         // if 'ti.tempdecl' happens to be found in a mixin template don't lose that info
13322         // and do the symbol search in that context (Issue: 19476)
13323         auto tm = cast(TemplateMixin)exp.ti.tempdecl.parent;
13324         e1 = new DotExp(exp.e1.loc, exp.e1, new ScopeExp(tm.loc, tm));
13325     }
13326 
13327     auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
13328 
13329     Expression e = die.dotIdSemanticPropX(sc);
13330     if (e == die)
13331     {
13332         exp.e1 = die.e1; // take back
13333         Type t1b = exp.e1.type.toBasetype();
13334         if (t1b.ty == Tarray || t1b.ty == Tsarray || t1b.ty == Taarray || t1b.ty == Tnull || (t1b.isTypeBasic() && t1b.ty != Tvoid))
13335         {
13336             /* No built-in type has templatized properties, so do shortcut.
13337              * It is necessary in: 1024.max!"a < b"
13338              */
13339             if (gag)
13340                 return null;
13341         }
13342         e = die.dotIdSemanticProp(sc, gag);
13343         if (gag)
13344         {
13345             if (!e ||
13346                 isDotOpDispatch(e))
13347             {
13348                 /* opDispatch!tiargs would be a function template that needs IFTI,
13349                  * so it's not a template
13350                  */
13351                 return null;
13352             }
13353         }
13354     }
13355     assert(e);
13356 
13357     if (e.op == EXP.error)
13358         return e;
13359     if (DotVarExp dve = e.isDotVarExp())
13360     {
13361         if (FuncDeclaration fd = dve.var.isFuncDeclaration())
13362         {
13363             if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13364             {
13365                 e = new DotTemplateExp(dve.loc, dve.e1, td);
13366                 e = e.expressionSemantic(sc);
13367             }
13368         }
13369         else if (OverDeclaration od = dve.var.isOverDeclaration())
13370         {
13371             exp.e1 = dve.e1; // pull semantic() result
13372 
13373             if (!exp.findTempDecl(sc))
13374                 goto Lerr;
13375             if (exp.ti.needsTypeInference(sc))
13376                 return exp;
13377             exp.ti.dsymbolSemantic(sc);
13378             if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13379                 return errorExp();
13380 
13381             if (Declaration v = exp.ti.toAlias().isDeclaration())
13382             {
13383                 if (v.type && !v.type.deco)
13384                     v.type = v.type.typeSemantic(v.loc, sc);
13385                 return new DotVarExp(exp.loc, exp.e1, v)
13386                        .expressionSemantic(sc);
13387             }
13388             return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13389                    .expressionSemantic(sc);
13390         }
13391     }
13392     else if (e.op == EXP.variable)
13393     {
13394         VarExp ve = cast(VarExp)e;
13395         if (FuncDeclaration fd = ve.var.isFuncDeclaration())
13396         {
13397             if (TemplateDeclaration td = fd.findTemplateDeclRoot())
13398             {
13399                 e = new TemplateExp(ve.loc, td)
13400                     .expressionSemantic(sc);
13401             }
13402         }
13403         else if (OverDeclaration od = ve.var.isOverDeclaration())
13404         {
13405             exp.ti.tempdecl = od;
13406             return new ScopeExp(exp.loc, exp.ti)
13407                    .expressionSemantic(sc);
13408         }
13409     }
13410 
13411     if (DotTemplateExp dte = e.isDotTemplateExp())
13412     {
13413         exp.e1 = dte.e1; // pull semantic() result
13414 
13415         exp.ti.tempdecl = dte.td;
13416         if (!exp.ti.semanticTiargs(sc))
13417             return errorExp();
13418         if (exp.ti.needsTypeInference(sc))
13419             return exp;
13420         exp.ti.dsymbolSemantic(sc);
13421         if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13422             return errorExp();
13423 
13424         if (Declaration v = exp.ti.toAlias().isDeclaration())
13425         {
13426             return new DotVarExp(exp.loc, exp.e1, v)
13427                    .expressionSemantic(sc);
13428         }
13429         return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13430                .expressionSemantic(sc);
13431     }
13432     else if (e.op == EXP.template_)
13433     {
13434         exp.ti.tempdecl = (cast(TemplateExp)e).td;
13435         return new ScopeExp(exp.loc, exp.ti)
13436                .expressionSemantic(sc);
13437     }
13438     else if (DotExp de = e.isDotExp())
13439     {
13440         if (de.e2.op == EXP.overloadSet)
13441         {
13442             if (!exp.findTempDecl(sc) || !exp.ti.semanticTiargs(sc))
13443             {
13444                 return errorExp();
13445             }
13446             if (exp.ti.needsTypeInference(sc))
13447                 return exp;
13448             exp.ti.dsymbolSemantic(sc);
13449             if (!exp.ti.inst || exp.ti.errors) // if template failed to expand
13450                 return errorExp();
13451 
13452             if (Declaration v = exp.ti.toAlias().isDeclaration())
13453             {
13454                 if (v.type && !v.type.deco)
13455                     v.type = v.type.typeSemantic(v.loc, sc);
13456                 return new DotVarExp(exp.loc, exp.e1, v)
13457                        .expressionSemantic(sc);
13458             }
13459             return new DotExp(exp.loc, exp.e1, new ScopeExp(exp.loc, exp.ti))
13460                    .expressionSemantic(sc);
13461         }
13462     }
13463     else if (OverExp oe = e.isOverExp())
13464     {
13465         exp.ti.tempdecl = oe.vars;
13466         return new ScopeExp(exp.loc, exp.ti)
13467                .expressionSemantic(sc);
13468     }
13469 
13470 Lerr:
13471     exp.error("`%s` isn't a template", e.toChars());
13472     return errorExp();
13473 }
13474 
13475 /***************************************
13476  * If expression is shared, check that we can access it.
13477  * Give error message if not.
13478  *
13479  * Params:
13480  *      e = expression to check
13481  *      sc = context
13482  *      returnRef = Whether this expression is for a `return` statement
13483  *                  off a `ref` function, in which case a single level
13484  *                  of dereference is allowed (e.g. `shared(int)*`).
13485  * Returns:
13486  *      true on error
13487  */
13488 bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
13489 {
13490     if (global.params.noSharedAccess != FeatureState.enabled ||
13491         !sc ||
13492         sc.intypeof ||
13493         sc.flags & SCOPE.ctfe)
13494     {
13495         return false;
13496     }
13497 
13498     //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
13499 
13500     bool check(Expression e, bool allowRef)
13501     {
13502         bool sharedError(Expression e)
13503         {
13504             // https://dlang.org/phobos/core_atomic.html
13505             e.error("direct access to shared `%s` is not allowed, see `core.atomic`", e.toChars());
13506             return true;
13507         }
13508 
13509         // Error by default
13510         bool visit(Expression e)
13511         {
13512             // https://issues.dlang.org/show_bug.cgi?id=23639
13513             // Should be able to cast(shared)
13514             if (!e.isCastExp() && e.type.isShared())
13515                 return sharedError(e);
13516             return false;
13517         }
13518 
13519         bool visitNew(NewExp e)
13520         {
13521             if (e.thisexp)
13522                 check(e.thisexp, false);
13523             return false;
13524         }
13525 
13526         bool visitVar(VarExp e)
13527         {
13528             // https://issues.dlang.org/show_bug.cgi?id=20908
13529             // direct access to init symbols is ok as they
13530             // cannot be modified.
13531             if (e.var.isSymbolDeclaration())
13532                 return false;
13533 
13534             // https://issues.dlang.org/show_bug.cgi?id=22626
13535             // Synchronized functions don't need to use core.atomic
13536             // when accessing `this`.
13537             if (sc.func && sc.func.isSynchronized())
13538             {
13539                 if (e.var.isThisDeclaration())
13540                     return false;
13541                 else
13542                     return sharedError(e);
13543             }
13544             else if (!allowRef && e.var.type.isShared())
13545                 return sharedError(e);
13546 
13547             return false;
13548         }
13549 
13550         bool visitAddr(AddrExp e)
13551         {
13552             return check(e.e1, true);
13553         }
13554 
13555         bool visitPtr(PtrExp e)
13556         {
13557             if (!allowRef && e.type.isShared())
13558                 return sharedError(e);
13559 
13560             if (e.e1.type.isShared())
13561                 return sharedError(e);
13562 
13563             return check(e.e1, false);
13564         }
13565 
13566         bool visitDotVar(DotVarExp e)
13567         {
13568             //printf("dotvarexp = %s\n", e.toChars());
13569             if (e.type.isShared())
13570             {
13571                 if (e.e1.isThisExp())
13572                 {
13573                     // https://issues.dlang.org/show_bug.cgi?id=22626
13574                     if (sc.func && sc.func.isSynchronized())
13575                         return false;
13576 
13577                     // https://issues.dlang.org/show_bug.cgi?id=23790
13578                     if (e.e1.type.isTypeStruct())
13579                         return false;
13580                 }
13581 
13582                 auto fd = e.var.isFuncDeclaration();
13583                 const sharedFunc = fd && fd.type.isShared;
13584                 if (!allowRef && !sharedFunc)
13585                     return sharedError(e);
13586 
13587                 // Allow using `DotVarExp` within value types
13588                 if (e.e1.type.isTypeSArray() || e.e1.type.isTypeStruct())
13589                     return check(e.e1, allowRef);
13590 
13591                 // If we end up with a single `VarExp`, it might be a `ref` param
13592                 // `shared ref T` param == `shared(T)*`.
13593                 if (auto ve = e.e1.isVarExp())
13594                 {
13595                     return check(e.e1, allowRef && (ve.var.storage_class & STC.ref_));
13596                 }
13597 
13598                 return sharedError(e);
13599             }
13600 
13601             return check(e.e1, false);
13602         }
13603 
13604         bool visitIndex(IndexExp e)
13605         {
13606             if (!allowRef && e.type.isShared())
13607                 return sharedError(e);
13608 
13609             if (e.e1.type.isShared())
13610                 return sharedError(e);
13611 
13612             return check(e.e1, false);
13613         }
13614 
13615         bool visitComma(CommaExp e)
13616         {
13617             // Cannot be `return ref` since we can't use the return,
13618             // but it's better to show that error than an unrelated `shared` one
13619             return check(e.e2, true);
13620         }
13621 
13622         switch (e.op)
13623         {
13624             default:              return visit(e);
13625 
13626             // Those have no indirections / can be ignored
13627             case EXP.call:
13628             case EXP.error:
13629             case EXP.complex80:
13630             case EXP.int64:
13631             case EXP.null_:       return false;
13632 
13633             case EXP.variable:    return visitVar(e.isVarExp());
13634             case EXP.new_:        return visitNew(e.isNewExp());
13635             case EXP.address:     return visitAddr(e.isAddrExp());
13636             case EXP.star:        return visitPtr(e.isPtrExp());
13637             case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
13638             case EXP.index:       return visitIndex(e.isIndexExp());
13639         }
13640     }
13641 
13642     return check(e, returnRef);
13643 }
13644 
13645 
13646 
13647 /****************************************************
13648  * Determine if `exp`, which gets its address taken, can do so safely.
13649  * Params:
13650  *      sc = context
13651  *      exp = expression having its address taken
13652  *      v = the variable getting its address taken
13653  * Returns:
13654  *      `true` if ok, `false` for error
13655  */
13656 bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
13657 {
13658     //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
13659     if (v is null)
13660         return true;
13661 
13662     if (!v.canTakeAddressOf())
13663     {
13664         exp.error("cannot take address of `%s`", exp.toChars());
13665         return false;
13666     }
13667     if (sc.func && !sc.intypeof && !v.isDataseg())
13668     {
13669         if (global.params.useDIP1000 != FeatureState.enabled &&
13670             !(v.storage_class & STC.temp) &&
13671             sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
13672         {
13673             return false;
13674         }
13675     }
13676     return true;
13677 }
13678 
13679 /**************************************
13680  * This check ensures that the object in `exp` can have its address taken, or
13681  * issue a diagnostic error.
13682  * Params:
13683  *      e = expression to check
13684  *      sc = context
13685  * Returns:
13686  *      true if the expression is addressable
13687  */
13688 bool checkAddressable(Expression e, Scope* sc)
13689 {
13690     Expression ex = e;
13691     while (true)
13692     {
13693         switch (ex.op)
13694         {
13695             case EXP.dotVariable:
13696                 // https://issues.dlang.org/show_bug.cgi?id=22749
13697                 // Error about taking address of any bit-field, regardless of
13698                 // whether SCOPE.Cfile is set.
13699                 if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
13700                 {
13701                     e.error("cannot take address of bit-field `%s`", bf.toChars());
13702                     return false;
13703                 }
13704                 goto case EXP.cast_;
13705 
13706             case EXP.index:
13707                 ex = ex.isBinExp().e1;
13708                 continue;
13709 
13710             case EXP.address:
13711             case EXP.array:
13712             case EXP.cast_:
13713                 ex = ex.isUnaExp().e1;
13714                 continue;
13715 
13716             case EXP.variable:
13717                 if (sc.flags & SCOPE.Cfile)
13718                 {
13719                     // C11 6.5.3.2: A variable that has its address taken cannot be
13720                     // stored in a register.
13721                     // C11 6.3.2.1: An array that has its address computed with `[]`
13722                     // or cast to an lvalue pointer cannot be stored in a register.
13723                     if (ex.isVarExp().var.storage_class & STC.register)
13724                     {
13725                         if (e.isIndexExp())
13726                             e.error("cannot index through register variable `%s`", ex.toChars());
13727                         else
13728                             e.error("cannot take address of register variable `%s`", ex.toChars());
13729                         return false;
13730                     }
13731                 }
13732                 break;
13733 
13734             default:
13735                 break;
13736         }
13737         break;
13738     }
13739     return true;
13740 }
13741 
13742 
13743 /*******************************
13744  * Checks the attributes of a function.
13745  * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
13746  * and usage of `deprecated` and `@disabled`-ed symbols are checked.
13747  *
13748  * Params:
13749  *  exp = expression to check attributes for
13750  *  sc  = scope of the function
13751  *  f   = function to be checked
13752  * Returns: `true` if error occur.
13753  */
13754 private bool checkFunctionAttributes(Expression exp, Scope* sc, FuncDeclaration f)
13755 {
13756     with(exp)
13757     {
13758         bool error = checkDisabled(sc, f);
13759         error |= checkDeprecated(sc, f);
13760         error |= checkPurity(sc, f);
13761         error |= checkSafety(sc, f);
13762         error |= checkNogc(sc, f);
13763         return error;
13764     }
13765 }
13766 
13767 /*******************************
13768  * Helper function for `getRightThis()`.
13769  * Gets `this` of the next outer aggregate.
13770  * Params:
13771  *      loc = location to use for error messages
13772  *      sc = context
13773  *      s = the parent symbol of the existing `this`
13774  *      ad = struct or class we need the correct `this` for
13775  *      e1 = existing `this`
13776  *      t = type of the existing `this`
13777  *      var = the specific member of ad we're accessing
13778  *      flag = if true, return `null` instead of throwing an error
13779  * Returns:
13780  *      Expression representing the `this` for the var
13781  */
13782 Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, AggregateDeclaration ad, Expression e1, Type t, Dsymbol var, bool flag = false)
13783 {
13784     int n = 0;
13785     while (s && s.isFuncDeclaration())
13786     {
13787         FuncDeclaration f = s.isFuncDeclaration();
13788         if (f.vthis)
13789         {
13790             n++;
13791             e1 = new VarExp(loc, f.vthis);
13792             if (f.hasDualContext())
13793             {
13794                 // (*__this)[i]
13795                 if (n > 1)
13796                     e1 = e1.expressionSemantic(sc);
13797                 e1 = new PtrExp(loc, e1);
13798                 uint i = f.followInstantiationContext(ad);
13799                 e1 = new IndexExp(loc, e1, new IntegerExp(i));
13800                 s = f.toParentP(ad);
13801                 continue;
13802             }
13803         }
13804         else
13805         {
13806             if (flag)
13807                 return null;
13808             e1.error("need `this` of type `%s` to access member `%s` from static function `%s`", ad.toChars(), var.toChars(), f.toChars());
13809             e1 = ErrorExp.get();
13810             return e1;
13811         }
13812         s = s.toParent2();
13813     }
13814     if (n > 1 || e1.op == EXP.index)
13815         e1 = e1.expressionSemantic(sc);
13816     if (s && e1.type.equivalent(Type.tvoidptr))
13817     {
13818         if (auto sad = s.isAggregateDeclaration())
13819         {
13820             Type ta = sad.handleType();
13821             if (ta.ty == Tstruct)
13822                 ta = ta.pointerTo();
13823             e1.type = ta;
13824         }
13825     }
13826     e1.type = e1.type.addMod(t.mod);
13827     return e1;
13828 }
13829 
13830 /*******************************
13831  * Make a dual-context container for use as a `this` argument.
13832  * Params:
13833  *      loc = location to use for error messages
13834  *      sc = current scope
13835  *      fd = target function that will take the `this` argument
13836  * Returns:
13837  *      Temporary closure variable.
13838  * Note:
13839  *      The function `fd` is added to the nested references of the
13840  *      newly created variable such that a closure is made for the variable when
13841  *      the address of `fd` is taken.
13842  */
13843 VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
13844 {
13845     Type tthis2 = Type.tvoidptr.sarrayOf(2);
13846     VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
13847     vthis2.storage_class |= STC.temp;
13848     vthis2.dsymbolSemantic(sc);
13849     vthis2.parent = sc.parent;
13850     // make it a closure var
13851     assert(sc.func);
13852     sc.func.closureVars.push(vthis2);
13853     // add `fd` to the nested refs
13854     vthis2.nestedrefs.push(fd);
13855     return vthis2;
13856 }
13857 
13858 /*******************************
13859  * Make sure that the runtime hook `id` exists.
13860  * Params:
13861  *      loc = location to use for error messages
13862  *      sc = current scope
13863  *      id = the hook identifier
13864  *      description = what the hook does
13865  *      module_ = what module the hook is located in
13866  * Returns:
13867  *      a `bool` indicating if the hook is present.
13868  */
13869 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
13870 {
13871     auto rootSymbol = sc.search(loc, Id.empty, null);
13872     if (auto moduleSymbol = rootSymbol.search(loc, module_))
13873         if (moduleSymbol.search(loc, id))
13874           return true;
13875     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);
13876     return false;
13877 }
13878 
13879 /***************************************
13880  * Fit elements[] to the corresponding types of the `sd`'s fields.
13881  *
13882  * Params:
13883  *      sd = the struct declaration
13884  *      loc = location to use for error messages
13885  *      sc = context
13886  *      elements = explicit arguments used to construct object
13887  *      stype = the constructed object type.
13888  * Returns:
13889  *      false if any errors occur,
13890  *      otherwise true and elements[] are rewritten for the output.
13891  */
13892 private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
13893 {
13894     if (!elements)
13895         return true;
13896 
13897     const nfields = sd.nonHiddenFields();
13898     size_t offset = 0;
13899     for (size_t i = 0; i < elements.length; i++)
13900     {
13901         Expression e = (*elements)[i];
13902         if (!e)
13903             continue;
13904 
13905         e = resolveProperties(sc, e);
13906         if (i >= nfields)
13907         {
13908             if (i < sd.fields.length && e.op == EXP.null_)
13909             {
13910                 // CTFE sometimes creates null as hidden pointer; we'll allow this.
13911                 continue;
13912             }
13913                 .error(loc, "more initializers than fields (%llu) of `%s`", cast(ulong)nfields, sd.toChars());
13914             return false;
13915         }
13916         VarDeclaration v = sd.fields[i];
13917         if (v.offset < offset)
13918         {
13919             .error(loc, "overlapping initialization for `%s`", v.toChars());
13920             if (!sd.isUnionDeclaration())
13921             {
13922                 enum errorMsg = "`struct` initializers that contain anonymous unions" ~
13923                     " must initialize only the first member of a `union`. All subsequent" ~
13924                     " non-overlapping fields are default initialized";
13925                 .errorSupplemental(loc, errorMsg);
13926             }
13927             return false;
13928         }
13929         const vsize = v.type.size();
13930         if (vsize == SIZE_INVALID)
13931             return false;
13932         offset = cast(uint)(v.offset + vsize);
13933 
13934         Type t = v.type;
13935         if (stype)
13936             t = t.addMod(stype.mod);
13937         Type origType = t;
13938         Type tb = t.toBasetype();
13939 
13940         const hasPointers = tb.hasPointers();
13941         if (hasPointers)
13942         {
13943             if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
13944                  (v.offset & (target.ptrsize - 1))) &&
13945                 (sc.setUnsafe(false, loc,
13946                     "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
13947             {
13948                 return false;
13949             }
13950         }
13951 
13952         /* Look for case of initializing a static array with a too-short
13953          * string literal, such as:
13954          *  char[5] foo = "abc";
13955          * Allow this by doing an explicit cast, which will lengthen the string
13956          * literal.
13957          */
13958         if (e.op == EXP.string_ && tb.ty == Tsarray)
13959         {
13960             StringExp se = cast(StringExp)e;
13961             Type typeb = se.type.toBasetype();
13962             TY tynto = tb.nextOf().ty;
13963             if (!se.committed &&
13964                 (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
13965                 se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
13966             {
13967                 e = se.castTo(sc, t);
13968                 goto L1;
13969             }
13970         }
13971 
13972         while (!e.implicitConvTo(t) && tb.ty == Tsarray)
13973         {
13974             /* Static array initialization, as in:
13975              *  T[3][5] = e;
13976              */
13977             t = tb.nextOf();
13978             tb = t.toBasetype();
13979         }
13980         if (!e.implicitConvTo(t))
13981             t = origType; // restore type for better diagnostic
13982 
13983         e = e.implicitCastTo(sc, t);
13984     L1:
13985         if (e.op == EXP.error)
13986             return false;
13987 
13988         (*elements)[i] = doCopyOrMove(sc, e);
13989     }
13990     return true;
13991 }
13992 
13993 
13994 /**
13995  * Returns `em` as a VariableExp
13996  * Params:
13997  *     em = the EnumMember to wrap
13998  *     loc = location of use of em
13999  *     sc = scope of use of em
14000  * Returns:
14001  *     VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
14002  */
14003 Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
14004 {
14005     dsymbolSemantic(em, sc);
14006     if (em.errors)
14007         return ErrorExp.get();
14008     em.checkDisabled(loc, sc);
14009 
14010     if (em.depdecl && !em.depdecl._scope)
14011         em.depdecl._scope = sc;
14012     em.checkDeprecated(loc, sc);
14013 
14014     if (em.errors)
14015         return ErrorExp.get();
14016     Expression e = new VarExp(loc, em);
14017     e = e.expressionSemantic(sc);
14018     if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
14019     {
14020         /* C11 types them as int. But if in D file,
14021          * type qualified names as the enum
14022          */
14023         e.type = em.parent.isEnumDeclaration().type;
14024         assert(e.type);
14025     }
14026     return e;
14027 }
14028 
14029 
14030 /*****************************
14031  * Try to treat `exp` as a boolean,
14032  * Params:
14033  *     exp = the expression
14034  *     sc = scope to evalute `exp` in
14035  * Returns:
14036  *     Modified expression on success, ErrorExp on error
14037  */
14038 Expression toBoolean(Expression exp, Scope* sc)
14039 {
14040     switch(exp.op)
14041     {
14042         case EXP.delete_:
14043             exp.error("`delete` does not give a boolean result");
14044             return ErrorExp.get();
14045 
14046         case EXP.comma:
14047             auto ce = exp.isCommaExp();
14048             auto ex2 = ce.e2.toBoolean(sc);
14049             if (ex2.op == EXP.error)
14050                 return ex2;
14051             ce.e2 = ex2;
14052             ce.type = ce.e2.type;
14053             return ce;
14054 
14055         case EXP.assign:
14056         case EXP.construct:
14057         case EXP.blit:
14058         case EXP.loweredAssignExp:
14059             if (sc.flags & SCOPE.Cfile)
14060                 return exp;
14061             // Things like:
14062             //  if (a = b) ...
14063             // are usually mistakes.
14064             exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
14065             return ErrorExp.get();
14066 
14067         //LogicalExp
14068         case EXP.andAnd:
14069         case EXP.orOr:
14070             auto le = exp.isLogicalExp();
14071             auto ex2 = le.e2.toBoolean(sc);
14072             if (ex2.op == EXP.error)
14073                 return ex2;
14074             le.e2 = ex2;
14075             return le;
14076 
14077         case EXP.question:
14078             auto ce = exp.isCondExp();
14079             auto ex1 = ce.e1.toBoolean(sc);
14080             auto ex2 = ce.e2.toBoolean(sc);
14081             if (ex1.op == EXP.error)
14082                 return ex1;
14083             if (ex2.op == EXP.error)
14084                 return ex2;
14085             ce.e1 = ex1;
14086             ce.e2 = ex2;
14087             return ce;
14088 
14089 
14090         default:
14091             // Default is 'yes' - do nothing
14092             Expression e = arrayFuncConv(exp, sc);
14093             Type t = e.type;
14094             Type tb = t.toBasetype();
14095             Type att = null;
14096 
14097             while (1)
14098             {
14099                 // Structs can be converted to bool using opCast(bool)()
14100                 if (auto ts = tb.isTypeStruct())
14101                 {
14102                     AggregateDeclaration ad = ts.sym;
14103                     /* Don't really need to check for opCast first, but by doing so we
14104                      * get better error messages if it isn't there.
14105                      */
14106                     if (Dsymbol fd = search_function(ad, Id._cast))
14107                     {
14108                         e = new CastExp(exp.loc, e, Type.tbool);
14109                         e = e.expressionSemantic(sc);
14110                         return e;
14111                     }
14112 
14113                     // Forward to aliasthis.
14114                     if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
14115                     {
14116                         e = resolveAliasThis(sc, e);
14117                         t = e.type;
14118                         tb = e.type.toBasetype();
14119                         continue;
14120                     }
14121                 }
14122                 break;
14123             }
14124 
14125             if (!t.isBoolean())
14126             {
14127                 if (tb != Type.terror)
14128                     exp.error("expression `%s` of type `%s` does not have a boolean value",
14129                               exp.toChars(), t.toChars());
14130                 return ErrorExp.get();
14131             }
14132             return e;
14133     }
14134 }