1 /**
2  * Defines the bulk of the classes which represent the AST at the expression level.
3  *
4  * Specification: ($LINK2 https://dlang.org/spec/expression.html, Expressions)
5  *
6  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/expression.d, _expression.d)
10  * Documentation:  https://dlang.org/phobos/dmd_expression.html
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/expression.d
12  */
13 
14 module dmd.expression;
15 
16 import core.stdc.stdarg;
17 import core.stdc.stdio;
18 import core.stdc.string;
19 
20 import dmd.aggregate;
21 import dmd.aliasthis;
22 import dmd.apply;
23 import dmd.arrayop;
24 import dmd.arraytypes;
25 import dmd.ast_node;
26 import dmd.gluelayer;
27 import dmd.canthrow;
28 import dmd.complex;
29 import dmd.constfold;
30 import dmd.ctfeexpr;
31 import dmd.ctorflow;
32 import dmd.dcast;
33 import dmd.dclass;
34 import dmd.declaration;
35 import dmd.delegatize;
36 import dmd.dimport;
37 import dmd.dinterpret;
38 import dmd.dmodule;
39 import dmd.dscope;
40 import dmd.dstruct;
41 import dmd.dsymbol;
42 import dmd.dsymbolsem;
43 import dmd.dtemplate;
44 import dmd.errors;
45 import dmd.escape;
46 import dmd.expressionsem;
47 import dmd.func;
48 import dmd.globals;
49 import dmd.hdrgen;
50 import dmd.id;
51 import dmd.identifier;
52 import dmd.inline;
53 import dmd.mtype;
54 import dmd.nspace;
55 import dmd.objc;
56 import dmd.opover;
57 import dmd.optimize;
58 import dmd.root.ctfloat;
59 import dmd.root.filename;
60 import dmd.root.outbuffer;
61 import dmd.root.rmem;
62 import dmd.root.rootobject;
63 import dmd.root.string;
64 import dmd.safe;
65 import dmd.sideeffect;
66 import dmd.target;
67 import dmd.tokens;
68 import dmd.typesem;
69 import dmd.utf;
70 import dmd.visitor;
71 
72 enum LOGSEMANTIC = false;
73 void emplaceExp(T : Expression, Args...)(void* p, Args args)
74 {
75     scope tmp = new T(args);
76     memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T));
77 }
78 
79 void emplaceExp(T : UnionExp)(T* p, Expression e)
80 {
81     memcpy(p, cast(void*)e, e.size);
82 }
83 
84 // Return value for `checkModifiable`
85 enum Modifiable
86 {
87     /// Not modifiable
88     no,
89     /// Modifiable (the type is mutable)
90     yes,
91     /// Modifiable because it is initialization
92     initialization,
93 }
94 
95 /****************************************
96  * Find the first non-comma expression.
97  * Params:
98  *      e = Expressions connected by commas
99  * Returns:
100  *      left-most non-comma expression
101  */
102 inout(Expression) firstComma(inout Expression e)
103 {
104     Expression ex = cast()e;
105     while (ex.op == TOK.comma)
106         ex = (cast(CommaExp)ex).e1;
107     return cast(inout)ex;
108 
109 }
110 
111 /****************************************
112  * Find the last non-comma expression.
113  * Params:
114  *      e = Expressions connected by commas
115  * Returns:
116  *      right-most non-comma expression
117  */
118 
119 inout(Expression) lastComma(inout Expression e)
120 {
121     Expression ex = cast()e;
122     while (ex.op == TOK.comma)
123         ex = (cast(CommaExp)ex).e2;
124     return cast(inout)ex;
125 
126 }
127 
128 /*****************************************
129  * Determine if `this` is available by walking up the enclosing
130  * scopes until a function is found.
131  *
132  * Params:
133  *      sc = where to start looking for the enclosing function
134  * Returns:
135  *      Found function if it satisfies `isThis()`, otherwise `null`
136  */
137 FuncDeclaration hasThis(Scope* sc)
138 {
139     //printf("hasThis()\n");
140     Dsymbol p = sc.parent;
141     while (p && p.isTemplateMixin())
142         p = p.parent;
143     FuncDeclaration fdthis = p ? p.isFuncDeclaration() : null;
144     //printf("fdthis = %p, '%s'\n", fdthis, fdthis ? fdthis.toChars() : "");
145 
146     // Go upwards until we find the enclosing member function
147     FuncDeclaration fd = fdthis;
148     while (1)
149     {
150         if (!fd)
151         {
152             return null;
153         }
154         if (!fd.isNested() || fd.isThis() || (fd.isThis2 && fd.isMember2()))
155             break;
156 
157         Dsymbol parent = fd.parent;
158         while (1)
159         {
160             if (!parent)
161                 return null;
162             TemplateInstance ti = parent.isTemplateInstance();
163             if (ti)
164                 parent = ti.parent;
165             else
166                 break;
167         }
168         fd = parent.isFuncDeclaration();
169     }
170 
171     if (!fd.isThis() && !(fd.isThis2 && fd.isMember2()))
172     {
173         return null;
174     }
175 
176     assert(fd.vthis);
177     return fd;
178 
179 }
180 
181 /***********************************
182  * Determine if a `this` is needed to access `d`.
183  * Params:
184  *      sc = context
185  *      d = declaration to check
186  * Returns:
187  *      true means a `this` is needed
188  */
189 bool isNeedThisScope(Scope* sc, Declaration d)
190 {
191     if (sc.intypeof == 1)
192         return false;
193 
194     AggregateDeclaration ad = d.isThis();
195     if (!ad)
196         return false;
197     //printf("d = %s, ad = %s\n", d.toChars(), ad.toChars());
198 
199     for (Dsymbol s = sc.parent; s; s = s.toParentLocal())
200     {
201         //printf("\ts = %s %s, toParent2() = %p\n", s.kind(), s.toChars(), s.toParent2());
202         if (AggregateDeclaration ad2 = s.isAggregateDeclaration())
203         {
204             if (ad2 == ad)
205                 return false;
206             else if (ad2.isNested())
207                 continue;
208             else
209                 return true;
210         }
211         if (FuncDeclaration f = s.isFuncDeclaration())
212         {
213             if (f.isMemberLocal())
214                 break;
215         }
216     }
217     return true;
218 }
219 
220 /******************************
221  * check e is exp.opDispatch!(tiargs) or not
222  * It's used to switch to UFCS the semantic analysis path
223  */
224 bool isDotOpDispatch(Expression e)
225 {
226     if (auto dtie = e.isDotTemplateInstanceExp())
227         return dtie.ti.name == Id.opDispatch;
228     return false;
229 }
230 
231 /****************************************
232  * Expand tuples.
233  * Input:
234  *      exps    aray of Expressions
235  * Output:
236  *      exps    rewritten in place
237  */
238 extern (C++) void expandTuples(Expressions* exps)
239 {
240     //printf("expandTuples()\n");
241     if (exps is null)
242         return;
243 
244     for (size_t i = 0; i < exps.dim; i++)
245     {
246         Expression arg = (*exps)[i];
247         if (!arg)
248             continue;
249 
250         // Look for tuple with 0 members
251         if (auto e = arg.isTypeExp())
252         {
253             if (auto tt = e.type.toBasetype().isTypeTuple())
254             {
255                 if (!tt.arguments || tt.arguments.dim == 0)
256                 {
257                     exps.remove(i);
258                     if (i == exps.dim)
259                         return;
260                 }
261                 else // Expand a TypeTuple
262                 {
263                     exps.remove(i);
264                     auto texps = new Expressions(tt.arguments.length);
265                     foreach (j, a; *tt.arguments)
266                         (*texps)[j] = new TypeExp(e.loc, a.type);
267                     exps.insert(i, texps);
268                 }
269                 i--;
270                 continue;
271             }
272         }
273 
274         // Inline expand all the tuples
275         while (arg.op == TOK.tuple)
276         {
277             TupleExp te = cast(TupleExp)arg;
278             exps.remove(i); // remove arg
279             exps.insert(i, te.exps); // replace with tuple contents
280             if (i == exps.dim)
281                 return; // empty tuple, no more arguments
282             (*exps)[i] = Expression.combine(te.e0, (*exps)[i]);
283             arg = (*exps)[i];
284         }
285     }
286 }
287 
288 /****************************************
289  * Expand alias this tuples.
290  */
291 TupleDeclaration isAliasThisTuple(Expression e)
292 {
293     if (!e.type)
294         return null;
295 
296     Type t = e.type.toBasetype();
297     while (true)
298     {
299         if (Dsymbol s = t.toDsymbol(null))
300         {
301             if (auto ad = s.isAggregateDeclaration())
302             {
303                 s = ad.aliasthis ? ad.aliasthis.sym : null;
304                 if (s && s.isVarDeclaration())
305                 {
306                     TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
307                     if (td && td.isexp)
308                         return td;
309                 }
310                 if (Type att = t.aliasthisOf())
311                 {
312                     t = att;
313                     continue;
314                 }
315             }
316         }
317         return null;
318     }
319 }
320 
321 int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
322 {
323     if (!exps || exps.dim == 0)
324         return -1;
325 
326     for (size_t u = starti; u < exps.dim; u++)
327     {
328         Expression exp = (*exps)[u];
329         if (TupleDeclaration td = exp.isAliasThisTuple)
330         {
331             exps.remove(u);
332             foreach (i, o; *td.objects)
333             {
334                 auto d = o.isExpression().isDsymbolExp().s.isDeclaration();
335                 auto e = new DotVarExp(exp.loc, exp, d);
336                 assert(d.type);
337                 e.type = d.type;
338                 exps.insert(u + i, e);
339             }
340             version (none)
341             {
342                 printf("expansion ->\n");
343                 foreach (e; exps)
344                 {
345                     printf("\texps[%d] e = %s %s\n", i, Token.tochars[e.op], e.toChars());
346                 }
347             }
348             return cast(int)u;
349         }
350     }
351     return -1;
352 }
353 
354 /****************************************
355  * If `s` is a function template, i.e. the only member of a template
356  * and that member is a function, return that template.
357  * Params:
358  *      s = symbol that might be a function template
359  * Returns:
360  *      template for that function, otherwise null
361  */
362 TemplateDeclaration getFuncTemplateDecl(Dsymbol s)
363 {
364     FuncDeclaration f = s.isFuncDeclaration();
365     if (f && f.parent)
366     {
367         if (auto ti = f.parent.isTemplateInstance())
368         {
369             if (!ti.isTemplateMixin() && ti.tempdecl)
370             {
371                 auto td = ti.tempdecl.isTemplateDeclaration();
372                 if (td.onemember && td.ident == f.ident)
373                 {
374                     return td;
375                 }
376             }
377         }
378     }
379     return null;
380 }
381 
382 /************************************************
383  * If we want the value of this expression, but do not want to call
384  * the destructor on it.
385  */
386 Expression valueNoDtor(Expression e)
387 {
388     auto ex = lastComma(e);
389 
390     if (auto ce = ex.isCallExp())
391     {
392         /* The struct value returned from the function is transferred
393          * so do not call the destructor on it.
394          * Recognize:
395          *       ((S _ctmp = S.init), _ctmp).this(...)
396          * and make sure the destructor is not called on _ctmp
397          * BUG: if ex is a CommaExp, we should go down the right side.
398          */
399         if (auto dve = ce.e1.isDotVarExp())
400         {
401             if (dve.var.isCtorDeclaration())
402             {
403                 // It's a constructor call
404                 if (auto comma = dve.e1.isCommaExp())
405                 {
406                     if (auto ve = comma.e2.isVarExp())
407                     {
408                         VarDeclaration ctmp = ve.var.isVarDeclaration();
409                         if (ctmp)
410                         {
411                             ctmp.storage_class |= STC.nodtor;
412                             assert(!ce.isLvalue());
413                         }
414                     }
415                 }
416             }
417         }
418     }
419     else if (auto ve = ex.isVarExp())
420     {
421         auto vtmp = ve.var.isVarDeclaration();
422         if (vtmp && (vtmp.storage_class & STC.rvalue))
423         {
424             vtmp.storage_class |= STC.nodtor;
425         }
426     }
427     return e;
428 }
429 
430 /*********************************************
431  * If e is an instance of a struct, and that struct has a copy constructor,
432  * rewrite e as:
433  *    (tmp = e),tmp
434  * Input:
435  *      sc = just used to specify the scope of created temporary variable
436  *      destinationType = the type of the object on which the copy constructor is called;
437  *                        may be null if the struct defines a postblit
438  */
439 private Expression callCpCtor(Scope* sc, Expression e, Type destinationType)
440 {
441     if (auto ts = e.type.baseElemOf().isTypeStruct())
442     {
443         StructDeclaration sd = ts.sym;
444         if (sd.postblit || sd.hasCopyCtor)
445         {
446             /* Create a variable tmp, and replace the argument e with:
447              *      (tmp = e),tmp
448              * and let AssignExp() handle the construction.
449              * This is not the most efficient, ideally tmp would be constructed
450              * directly onto the stack.
451              */
452             auto tmp = copyToTemp(STC.rvalue, "__copytmp", e);
453             if (sd.hasCopyCtor && destinationType)
454                 tmp.type = destinationType;
455             tmp.storage_class |= STC.nodtor;
456             tmp.dsymbolSemantic(sc);
457             Expression de = new DeclarationExp(e.loc, tmp);
458             Expression ve = new VarExp(e.loc, tmp);
459             de.type = Type.tvoid;
460             ve.type = e.type;
461             return Expression.combine(de, ve);
462         }
463     }
464     return e;
465 }
466 
467 /************************************************
468  * Handle the postblit call on lvalue, or the move of rvalue.
469  *
470  * Params:
471  *   sc = the scope where the expression is encountered
472  *   e = the expression the needs to be moved or copied (source)
473  *   t = if the struct defines a copy constructor, the type of the destination
474  *
475  * Returns:
476  *  The expression that copy constructs or moves the value.
477  */
478 extern (D) Expression doCopyOrMove(Scope *sc, Expression e, Type t = null)
479 {
480     if (auto ce = e.isCondExp())
481     {
482         ce.e1 = doCopyOrMove(sc, ce.e1);
483         ce.e2 = doCopyOrMove(sc, ce.e2);
484     }
485     else
486     {
487         e = e.isLvalue() ? callCpCtor(sc, e, t) : valueNoDtor(e);
488     }
489     return e;
490 }
491 
492 /****************************************************************/
493 /* A type meant as a union of all the Expression types,
494  * to serve essentially as a Variant that will sit on the stack
495  * during CTFE to reduce memory consumption.
496  */
497 extern (C++) struct UnionExp
498 {
499     // yes, default constructor does nothing
500     extern (D) this(Expression e)
501     {
502         memcpy(&this, cast(void*)e, e.size);
503     }
504 
505     /* Extract pointer to Expression
506      */
507     extern (C++) Expression exp() return
508     {
509         return cast(Expression)&u;
510     }
511 
512     /* Convert to an allocated Expression
513      */
514     extern (C++) Expression copy()
515     {
516         Expression e = exp();
517         //if (e.size > sizeof(u)) printf("%s\n", Token::toChars(e.op));
518         assert(e.size <= u.sizeof);
519         switch (e.op)
520         {
521             case TOK.cantExpression:    return CTFEExp.cantexp;
522             case TOK.voidExpression:    return CTFEExp.voidexp;
523             case TOK.break_:            return CTFEExp.breakexp;
524             case TOK.continue_:         return CTFEExp.continueexp;
525             case TOK.goto_:             return CTFEExp.gotoexp;
526             default:                    return e.copy();
527         }
528     }
529 
530 private:
531     // Ensure that the union is suitably aligned.
532     align(8) union __AnonStruct__u
533     {
534         char[__traits(classInstanceSize, Expression)] exp;
535         char[__traits(classInstanceSize, IntegerExp)] integerexp;
536         char[__traits(classInstanceSize, ErrorExp)] errorexp;
537         char[__traits(classInstanceSize, RealExp)] realexp;
538         char[__traits(classInstanceSize, ComplexExp)] complexexp;
539         char[__traits(classInstanceSize, SymOffExp)] symoffexp;
540         char[__traits(classInstanceSize, StringExp)] stringexp;
541         char[__traits(classInstanceSize, ArrayLiteralExp)] arrayliteralexp;
542         char[__traits(classInstanceSize, AssocArrayLiteralExp)] assocarrayliteralexp;
543         char[__traits(classInstanceSize, StructLiteralExp)] structliteralexp;
544         char[__traits(classInstanceSize, NullExp)] nullexp;
545         char[__traits(classInstanceSize, DotVarExp)] dotvarexp;
546         char[__traits(classInstanceSize, AddrExp)] addrexp;
547         char[__traits(classInstanceSize, IndexExp)] indexexp;
548         char[__traits(classInstanceSize, SliceExp)] sliceexp;
549         char[__traits(classInstanceSize, VectorExp)] vectorexp;
550     }
551 
552     __AnonStruct__u u;
553 }
554 
555 /********************************
556  * Test to see if two reals are the same.
557  * Regard NaN's as equivalent.
558  * Regard +0 and -0 as different.
559  * Params:
560  *      x1 = first operand
561  *      x2 = second operand
562  * Returns:
563  *      true if x1 is x2
564  *      else false
565  */
566 bool RealIdentical(real_t x1, real_t x2)
567 {
568     return (CTFloat.isNaN(x1) && CTFloat.isNaN(x2)) || CTFloat.isIdentical(x1, x2);
569 }
570 
571 /************************ TypeDotIdExp ************************************/
572 /* Things like:
573  *      int.size
574  *      foo.size
575  *      (foo).size
576  *      cast(foo).size
577  */
578 DotIdExp typeDotIdExp(const ref Loc loc, Type type, Identifier ident)
579 {
580     return new DotIdExp(loc, new TypeExp(loc, type), ident);
581 }
582 
583 /***************************************************
584  * Given an Expression, find the variable it really is.
585  *
586  * For example, `a[index]` is really `a`, and `s.f` is really `s`.
587  * Params:
588  *      e = Expression to look at
589  * Returns:
590  *      variable if there is one, null if not
591  */
592 VarDeclaration expToVariable(Expression e)
593 {
594     while (1)
595     {
596         switch (e.op)
597         {
598             case TOK.variable:
599                 return (cast(VarExp)e).var.isVarDeclaration();
600 
601             case TOK.dotVariable:
602                 e = (cast(DotVarExp)e).e1;
603                 continue;
604 
605             case TOK.index:
606             {
607                 IndexExp ei = cast(IndexExp)e;
608                 e = ei.e1;
609                 Type ti = e.type.toBasetype();
610                 if (ti.ty == Tsarray)
611                     continue;
612                 return null;
613             }
614 
615             case TOK.slice:
616             {
617                 SliceExp ei = cast(SliceExp)e;
618                 e = ei.e1;
619                 Type ti = e.type.toBasetype();
620                 if (ti.ty == Tsarray)
621                     continue;
622                 return null;
623             }
624 
625             case TOK.this_:
626             case TOK.super_:
627                 return (cast(ThisExp)e).var.isVarDeclaration();
628 
629             default:
630                 return null;
631         }
632     }
633 }
634 
635 enum OwnedBy : ubyte
636 {
637     code,          // normal code expression in AST
638     ctfe,          // value expression for CTFE
639     cache,         // constant value cached for CTFE
640 }
641 
642 enum WANTvalue  = 0;    // default
643 enum WANTexpand = 1;    // expand const/immutable variables if possible
644 
645 /***********************************************************
646  * http://dlang.org/spec/expression.html#expression
647  */
648 extern (C++) abstract class Expression : ASTNode
649 {
650     const TOK op;   // to minimize use of dynamic_cast
651     ubyte size;     // # of bytes in Expression so we can copy() it
652     ubyte parens;   // if this is a parenthesized expression
653     Type type;      // !=null means that semantic() has been run
654     Loc loc;        // file location
655 
656     extern (D) this(const ref Loc loc, TOK op, int size)
657     {
658         //printf("Expression::Expression(op = %d) this = %p\n", op, this);
659         this.loc = loc;
660         this.op = op;
661         this.size = cast(ubyte)size;
662     }
663 
664     static void _init()
665     {
666         CTFEExp.cantexp = new CTFEExp(TOK.cantExpression);
667         CTFEExp.voidexp = new CTFEExp(TOK.voidExpression);
668         CTFEExp.breakexp = new CTFEExp(TOK.break_);
669         CTFEExp.continueexp = new CTFEExp(TOK.continue_);
670         CTFEExp.gotoexp = new CTFEExp(TOK.goto_);
671         CTFEExp.showcontext = new CTFEExp(TOK.showCtfeContext);
672     }
673 
674     /**
675      * Deinitializes the global state of the compiler.
676      *
677      * This can be used to restore the state set by `_init` to its original
678      * state.
679      */
680     static void deinitialize()
681     {
682         CTFEExp.cantexp = CTFEExp.cantexp.init;
683         CTFEExp.voidexp = CTFEExp.voidexp.init;
684         CTFEExp.breakexp = CTFEExp.breakexp.init;
685         CTFEExp.continueexp = CTFEExp.continueexp.init;
686         CTFEExp.gotoexp = CTFEExp.gotoexp.init;
687         CTFEExp.showcontext = CTFEExp.showcontext.init;
688     }
689 
690     /*********************************
691      * Does *not* do a deep copy.
692      */
693     final Expression copy()
694     {
695         Expression e;
696         if (!size)
697         {
698             debug
699             {
700                 fprintf(stderr, "No expression copy for: %s\n", toChars());
701                 printf("op = %d\n", op);
702             }
703             assert(0);
704         }
705 
706         // memory never freed, so can use the faster bump-pointer-allocation
707         e = cast(Expression)allocmemory(size);
708         //printf("Expression::copy(op = %d) e = %p\n", op, e);
709         return cast(Expression)memcpy(cast(void*)e, cast(void*)this, size);
710     }
711 
712     Expression syntaxCopy()
713     {
714         //printf("Expression::syntaxCopy()\n");
715         //print();
716         return copy();
717     }
718 
719     // kludge for template.isExpression()
720     override final DYNCAST dyncast() const
721     {
722         return DYNCAST.expression;
723     }
724 
725     override const(char)* toChars() const
726     {
727         OutBuffer buf;
728         HdrGenState hgs;
729         toCBuffer(this, &buf, &hgs);
730         return buf.extractChars();
731     }
732 
733     static if (__VERSION__ < 2092)
734     {
735         final void error(const(char)* format, ...) const
736         {
737             if (type != Type.terror)
738             {
739                 va_list ap;
740                 va_start(ap, format);
741                 .verror(loc, format, ap);
742                 va_end(ap);
743             }
744         }
745 
746         final void errorSupplemental(const(char)* format, ...)
747         {
748             if (type == Type.terror)
749                 return;
750 
751             va_list ap;
752             va_start(ap, format);
753             .verrorSupplemental(loc, format, ap);
754             va_end(ap);
755         }
756 
757         final void warning(const(char)* format, ...) const
758         {
759             if (type != Type.terror)
760             {
761                 va_list ap;
762                 va_start(ap, format);
763                 .vwarning(loc, format, ap);
764                 va_end(ap);
765             }
766         }
767 
768         final void deprecation(const(char)* format, ...) const
769         {
770             if (type != Type.terror)
771             {
772                 va_list ap;
773                 va_start(ap, format);
774                 .vdeprecation(loc, format, ap);
775                 va_end(ap);
776             }
777         }
778     }
779     else
780     {
781         pragma(printf) final void error(const(char)* format, ...) const
782         {
783             if (type != Type.terror)
784             {
785                 va_list ap;
786                 va_start(ap, format);
787                 .verror(loc, format, ap);
788                 va_end(ap);
789             }
790         }
791 
792         pragma(printf) final void errorSupplemental(const(char)* format, ...)
793         {
794             if (type == Type.terror)
795                 return;
796 
797             va_list ap;
798             va_start(ap, format);
799             .verrorSupplemental(loc, format, ap);
800             va_end(ap);
801         }
802 
803         pragma(printf) final void warning(const(char)* format, ...) const
804         {
805             if (type != Type.terror)
806             {
807                 va_list ap;
808                 va_start(ap, format);
809                 .vwarning(loc, format, ap);
810                 va_end(ap);
811             }
812         }
813 
814         pragma(printf) final void deprecation(const(char)* format, ...) const
815         {
816             if (type != Type.terror)
817             {
818                 va_list ap;
819                 va_start(ap, format);
820                 .vdeprecation(loc, format, ap);
821                 va_end(ap);
822             }
823         }
824     }
825 
826     /**********************************
827      * Combine e1 and e2 by CommaExp if both are not NULL.
828      */
829     extern (D) static Expression combine(Expression e1, Expression e2)
830     {
831         if (e1)
832         {
833             if (e2)
834             {
835                 e1 = new CommaExp(e1.loc, e1, e2);
836                 e1.type = e2.type;
837             }
838         }
839         else
840             e1 = e2;
841         return e1;
842     }
843 
844     extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
845     {
846         return combine(combine(e1, e2), e3);
847     }
848 
849     extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4)
850     {
851         return combine(combine(e1, e2), combine(e3, e4));
852     }
853 
854     /**********************************
855      * If 'e' is a tree of commas, returns the rightmost expression
856      * by stripping off it from the tree. The remained part of the tree
857      * is returned via e0.
858      * Otherwise 'e' is directly returned and e0 is set to NULL.
859      */
860     extern (D) static Expression extractLast(Expression e, out Expression e0)
861     {
862         if (e.op != TOK.comma)
863         {
864             return e;
865         }
866 
867         CommaExp ce = cast(CommaExp)e;
868         if (ce.e2.op != TOK.comma)
869         {
870             e0 = ce.e1;
871             return ce.e2;
872         }
873         else
874         {
875             e0 = e;
876 
877             Expression* pce = &ce.e2;
878             while ((cast(CommaExp)(*pce)).e2.op == TOK.comma)
879             {
880                 pce = &(cast(CommaExp)(*pce)).e2;
881             }
882             assert((*pce).op == TOK.comma);
883             ce = cast(CommaExp)(*pce);
884             *pce = ce.e1;
885 
886             return ce.e2;
887         }
888     }
889 
890     extern (D) static Expressions* arraySyntaxCopy(Expressions* exps)
891     {
892         Expressions* a = null;
893         if (exps)
894         {
895             a = new Expressions(exps.dim);
896             foreach (i, e; *exps)
897             {
898                 (*a)[i] = e ? e.syntaxCopy() : null;
899             }
900         }
901         return a;
902     }
903 
904     dinteger_t toInteger()
905     {
906         //printf("Expression %s\n", Token::toChars(op));
907         error("integer constant expression expected instead of `%s`", toChars());
908         return 0;
909     }
910 
911     uinteger_t toUInteger()
912     {
913         //printf("Expression %s\n", Token::toChars(op));
914         return cast(uinteger_t)toInteger();
915     }
916 
917     real_t toReal()
918     {
919         error("floating point constant expression expected instead of `%s`", toChars());
920         return CTFloat.zero;
921     }
922 
923     real_t toImaginary()
924     {
925         error("floating point constant expression expected instead of `%s`", toChars());
926         return CTFloat.zero;
927     }
928 
929     complex_t toComplex()
930     {
931         error("floating point constant expression expected instead of `%s`", toChars());
932         return complex_t(CTFloat.zero);
933     }
934 
935     StringExp toStringExp()
936     {
937         return null;
938     }
939 
940     TupleExp toTupleExp()
941     {
942         return null;
943     }
944 
945     /***************************************
946      * Return !=0 if expression is an lvalue.
947      */
948     bool isLvalue()
949     {
950         return false;
951     }
952 
953     /*******************************
954      * Give error if we're not an lvalue.
955      * If we can, convert expression to be an lvalue.
956      */
957     Expression toLvalue(Scope* sc, Expression e)
958     {
959         if (!e)
960             e = this;
961         else if (!loc.isValid())
962             loc = e.loc;
963 
964         if (e.op == TOK.type)
965             error("`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
966         else
967             error("`%s` is not an lvalue and cannot be modified", e.toChars());
968 
969         return ErrorExp.get();
970     }
971 
972     Expression modifiableLvalue(Scope* sc, Expression e)
973     {
974         //printf("Expression::modifiableLvalue() %s, type = %s\n", toChars(), type.toChars());
975         // See if this expression is a modifiable lvalue (i.e. not const)
976         if (checkModifiable(sc) == Modifiable.yes)
977         {
978             assert(type);
979             if (!type.isMutable())
980             {
981                 if (auto dve = this.isDotVarExp())
982                 {
983                     if (isNeedThisScope(sc, dve.var))
984                         for (Dsymbol s = sc.func; s; s = s.toParentLocal())
985                     {
986                         FuncDeclaration ff = s.isFuncDeclaration();
987                         if (!ff)
988                             break;
989                         if (!ff.type.isMutable)
990                         {
991                             error("cannot modify `%s` in `%s` function", toChars(), MODtoChars(type.mod));
992                             return ErrorExp.get();
993                         }
994                     }
995                 }
996                 error("cannot modify `%s` expression `%s`", MODtoChars(type.mod), toChars());
997                 return ErrorExp.get();
998             }
999             else if (!type.isAssignable())
1000             {
1001                 error("cannot modify struct instance `%s` of type `%s` because it contains `const` or `immutable` members",
1002                     toChars(), type.toChars());
1003                 return ErrorExp.get();
1004             }
1005         }
1006         return toLvalue(sc, e);
1007     }
1008 
1009     final Expression implicitCastTo(Scope* sc, Type t)
1010     {
1011         return .implicitCastTo(this, sc, t);
1012     }
1013 
1014     final MATCH implicitConvTo(Type t)
1015     {
1016         return .implicitConvTo(this, t);
1017     }
1018 
1019     final Expression castTo(Scope* sc, Type t)
1020     {
1021         return .castTo(this, sc, t);
1022     }
1023 
1024     /****************************************
1025      * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
1026      */
1027     Expression resolveLoc(const ref Loc loc, Scope* sc)
1028     {
1029         this.loc = loc;
1030         return this;
1031     }
1032 
1033     /****************************************
1034      * Check that the expression has a valid type.
1035      * If not, generates an error "... has no type".
1036      * Returns:
1037      *      true if the expression is not valid.
1038      * Note:
1039      *      When this function returns true, `checkValue()` should also return true.
1040      */
1041     bool checkType()
1042     {
1043         return false;
1044     }
1045 
1046     /****************************************
1047      * Check that the expression has a valid value.
1048      * If not, generates an error "... has no value".
1049      * Returns:
1050      *      true if the expression is not valid or has void type.
1051      */
1052     bool checkValue()
1053     {
1054         if (type && type.toBasetype().ty == Tvoid)
1055         {
1056             error("expression `%s` is `void` and has no value", toChars());
1057             //print(); assert(0);
1058             if (!global.gag)
1059                 type = Type.terror;
1060             return true;
1061         }
1062         return false;
1063     }
1064 
1065     extern (D) final bool checkScalar()
1066     {
1067         if (op == TOK.error)
1068             return true;
1069         if (type.toBasetype().ty == Terror)
1070             return true;
1071         if (!type.isscalar())
1072         {
1073             error("`%s` is not a scalar, it is a `%s`", toChars(), type.toChars());
1074             return true;
1075         }
1076         return checkValue();
1077     }
1078 
1079     extern (D) final bool checkNoBool()
1080     {
1081         if (op == TOK.error)
1082             return true;
1083         if (type.toBasetype().ty == Terror)
1084             return true;
1085         if (type.toBasetype().ty == Tbool)
1086         {
1087             error("operation not allowed on `bool` `%s`", toChars());
1088             return true;
1089         }
1090         return false;
1091     }
1092 
1093     extern (D) final bool checkIntegral()
1094     {
1095         if (op == TOK.error)
1096             return true;
1097         if (type.toBasetype().ty == Terror)
1098             return true;
1099         if (!type.isintegral())
1100         {
1101             error("`%s` is not of integral type, it is a `%s`", toChars(), type.toChars());
1102             return true;
1103         }
1104         return checkValue();
1105     }
1106 
1107     extern (D) final bool checkArithmetic()
1108     {
1109         if (op == TOK.error)
1110             return true;
1111         if (type.toBasetype().ty == Terror)
1112             return true;
1113         if (!type.isintegral() && !type.isfloating())
1114         {
1115             error("`%s` is not of arithmetic type, it is a `%s`", toChars(), type.toChars());
1116             return true;
1117         }
1118         return checkValue();
1119     }
1120 
1121     final bool checkDeprecated(Scope* sc, Dsymbol s)
1122     {
1123         return s.checkDeprecated(loc, sc);
1124     }
1125 
1126     extern (D) final bool checkDisabled(Scope* sc, Dsymbol s)
1127     {
1128         if (auto d = s.isDeclaration())
1129         {
1130             return d.checkDisabled(loc, sc);
1131         }
1132 
1133         return false;
1134     }
1135 
1136     /*********************************************
1137      * Calling function f.
1138      * Check the purity, i.e. if we're in a pure function
1139      * we can only call other pure functions.
1140      * Returns true if error occurs.
1141      */
1142     extern (D) final bool checkPurity(Scope* sc, FuncDeclaration f)
1143     {
1144         if (!sc.func)
1145             return false;
1146         if (sc.func == f)
1147             return false;
1148         if (sc.intypeof == 1)
1149             return false;
1150         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1151             return false;
1152 
1153         // If the call has a pure parent, then the called func must be pure.
1154         if (!f.isPure() && checkImpure(sc))
1155         {
1156             error("`pure` %s `%s` cannot call impure %s `%s`",
1157                 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1158                 f.toPrettyChars());
1159 
1160             checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
1161             return true;
1162         }
1163         return false;
1164     }
1165 
1166     /**
1167      * Checks whether `f` is a generated `DtorDeclaration` that hides a user-defined one
1168      * which passes `check` while `f` doesn't (e.g. when the user defined dtor is pure but
1169      * the generated dtor is not).
1170      * In that case the method will identify and print all members causing the attribute
1171      * missmatch.
1172      *
1173      * Params:
1174      *   sc = scope
1175      *   f  = potential `DtorDeclaration`
1176      *   check = current check (e.g. whether it's pure)
1177      *   checkName = the kind of check (e.g. `"pure"`)
1178      */
1179     extern (D) final void checkOverridenDtor(Scope* sc, FuncDeclaration f,
1180                 scope bool function(DtorDeclaration) check, const string checkName
1181     ) {
1182         auto dd = f.isDtorDeclaration();
1183         if (!dd || !dd.generated)
1184             return;
1185 
1186         // DtorDeclaration without parents should fail at an earlier stage
1187         auto ad = cast(AggregateDeclaration) f.toParent2();
1188         assert(ad);
1189         assert(ad.dtors.length);
1190 
1191         // Search for the user-defined destructor (if any)
1192         foreach(dtor; ad.dtors)
1193         {
1194             if (dtor.generated)
1195                 continue;
1196 
1197             if (!check(dtor)) // doesn't match check (e.g. is impure as well)
1198                 return;
1199 
1200             // Sanity check
1201             assert(!check(cast(DtorDeclaration) ad.fieldDtor));
1202             break;
1203         }
1204 
1205         dd.loc.errorSupplemental("%s`%s.~this` is %.*s because of the following field's destructors:",
1206                             dd.generated ? "generated " : "".ptr,
1207                             ad.toChars,
1208                             cast(int) checkName.length, checkName.ptr);
1209 
1210         // Search for the offending fields
1211         foreach (field; ad.fields)
1212         {
1213             // Only structs may define automatically called destructors
1214             auto ts = field.type.isTypeStruct();
1215             if (!ts)
1216             {
1217                 // But they might be part of a static array
1218                 auto ta = field.type.isTypeSArray();
1219                 if (!ta)
1220                     continue;
1221 
1222                 ts = ta.baseElemOf().isTypeStruct();
1223                 if (!ts)
1224                     continue;
1225             }
1226 
1227             auto fieldSym = ts.toDsymbol(sc);
1228             assert(fieldSym); // Resolving ts must succeed because missing defs. should error before
1229 
1230             auto fieldSd = fieldSym.isStructDeclaration();
1231             assert(fieldSd); // ts is a TypeStruct, this would imply a malformed ASR
1232 
1233             if (fieldSd.dtor && !check(fieldSd.dtor))
1234             {
1235                 field.loc.errorSupplemental(" - %s %s", field.type.toChars(), field.toChars());
1236 
1237                 if (fieldSd.dtor.generated)
1238                     checkOverridenDtor(sc, fieldSd.dtor, check, checkName);
1239                 else
1240                     fieldSd.dtor.loc.errorSupplemental("   %.*s `%s.~this` is declared here",
1241                                             cast(int) checkName.length, checkName.ptr, fieldSd.toChars());
1242             }
1243         }
1244     }
1245 
1246     /*******************************************
1247      * Accessing variable v.
1248      * Check for purity and safety violations.
1249      * Returns true if error occurs.
1250      */
1251     extern (D) final bool checkPurity(Scope* sc, VarDeclaration v)
1252     {
1253         //printf("v = %s %s\n", v.type.toChars(), v.toChars());
1254         /* Look for purity and safety violations when accessing variable v
1255          * from current function.
1256          */
1257         if (!sc.func)
1258             return false;
1259         if (sc.intypeof == 1)
1260             return false; // allow violations inside typeof(expression)
1261         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1262             return false; // allow violations inside compile-time evaluated expressions and debug conditionals
1263         if (v.ident == Id.ctfe)
1264             return false; // magic variable never violates pure and safe
1265         if (v.isImmutable())
1266             return false; // always safe and pure to access immutables...
1267         if (v.isConst() && !v.isRef() && (v.isDataseg() || v.isParameter()) && v.type.implicitConvTo(v.type.immutableOf()))
1268             return false; // or const global/parameter values which have no mutable indirections
1269         if (v.storage_class & STC.manifest)
1270             return false; // ...or manifest constants
1271 
1272         // accessing empty structs is pure
1273         if (v.type.ty == Tstruct)
1274         {
1275             StructDeclaration sd = (cast(TypeStruct)v.type).sym;
1276             if (sd.members) // not opaque
1277             {
1278                 sd.determineSize(v.loc);
1279                 if (sd.hasNoFields)
1280                     return false;
1281             }
1282         }
1283 
1284         bool err = false;
1285         if (v.isDataseg())
1286         {
1287             // https://issues.dlang.org/show_bug.cgi?id=7533
1288             // Accessing implicit generated __gate is pure.
1289             if (v.ident == Id.gate)
1290                 return false;
1291 
1292             if (checkImpure(sc))
1293             {
1294                 error("`pure` %s `%s` cannot access mutable static data `%s`",
1295                     sc.func.kind(), sc.func.toPrettyChars(), v.toChars());
1296                 err = true;
1297             }
1298         }
1299         else
1300         {
1301             /* Given:
1302              * void f() {
1303              *   int fx;
1304              *   pure void g() {
1305              *     int gx;
1306              *     /+pure+/ void h() {
1307              *       int hx;
1308              *       /+pure+/ void i() { }
1309              *     }
1310              *   }
1311              * }
1312              * i() can modify hx and gx but not fx
1313              */
1314 
1315             Dsymbol vparent = v.toParent2();
1316             for (Dsymbol s = sc.func; !err && s; s = s.toParentP(vparent))
1317             {
1318                 if (s == vparent)
1319                     break;
1320 
1321                 if (AggregateDeclaration ad = s.isAggregateDeclaration())
1322                 {
1323                     if (ad.isNested())
1324                         continue;
1325                     break;
1326                 }
1327                 FuncDeclaration ff = s.isFuncDeclaration();
1328                 if (!ff)
1329                     break;
1330                 if (ff.isNested() || ff.isThis())
1331                 {
1332                     if (ff.type.isImmutable() ||
1333                         ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
1334                     {
1335                         OutBuffer ffbuf;
1336                         OutBuffer vbuf;
1337                         MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
1338                         MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
1339                         error("%s%s `%s` cannot access %sdata `%s`",
1340                             ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
1341                         err = true;
1342                         break;
1343                     }
1344                     continue;
1345                 }
1346                 break;
1347             }
1348         }
1349 
1350         /* Do not allow safe functions to access __gshared data
1351          */
1352         if (v.storage_class & STC.gshared)
1353         {
1354             if (sc.func.setUnsafe())
1355             {
1356                 error("`@safe` %s `%s` cannot access `__gshared` data `%s`",
1357                     sc.func.kind(), sc.func.toChars(), v.toChars());
1358                 err = true;
1359             }
1360         }
1361 
1362         return err;
1363     }
1364 
1365     /*
1366     Check if sc.func is impure or can be made impure.
1367     Returns true on error, i.e. if sc.func is pure and cannot be made impure.
1368     */
1369     private static bool checkImpure(Scope* sc)
1370     {
1371         return sc.func && (sc.flags & SCOPE.compile
1372                 ? sc.func.isPureBypassingInference() >= PURE.weak
1373                 : sc.func.setImpure());
1374     }
1375 
1376     /*********************************************
1377      * Calling function f.
1378      * Check the safety, i.e. if we're in a @safe function
1379      * we can only call @safe or @trusted functions.
1380      * Returns true if error occurs.
1381      */
1382     extern (D) final bool checkSafety(Scope* sc, FuncDeclaration f)
1383     {
1384         if (!sc.func)
1385             return false;
1386         if (sc.func == f)
1387             return false;
1388         if (sc.intypeof == 1)
1389             return false;
1390         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1391             return false;
1392 
1393         if (!f.isSafe() && !f.isTrusted())
1394         {
1395             if (sc.flags & SCOPE.compile ? sc.func.isSafeBypassingInference() : sc.func.setUnsafe())
1396             {
1397                 if (!loc.isValid()) // e.g. implicitly generated dtor
1398                     loc = sc.func.loc;
1399 
1400                 const prettyChars = f.toPrettyChars();
1401                 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
1402                     sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
1403                     prettyChars);
1404                 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
1405 
1406                 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
1407 
1408                 return true;
1409             }
1410         }
1411         return false;
1412     }
1413 
1414     /*********************************************
1415      * Calling function f.
1416      * Check the @nogc-ness, i.e. if we're in a @nogc function
1417      * we can only call other @nogc functions.
1418      * Returns true if error occurs.
1419      */
1420     extern (D) final bool checkNogc(Scope* sc, FuncDeclaration f)
1421     {
1422         if (!sc.func)
1423             return false;
1424         if (sc.func == f)
1425             return false;
1426         if (sc.intypeof == 1)
1427             return false;
1428         if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
1429             return false;
1430 
1431         if (!f.isNogc())
1432         {
1433             if (sc.flags & SCOPE.compile ? sc.func.isNogcBypassingInference() : sc.func.setGC())
1434             {
1435                 if (loc.linnum == 0) // e.g. implicitly generated dtor
1436                     loc = sc.func.loc;
1437 
1438                 // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
1439                 // so don't print anything to avoid double error messages.
1440                 if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT))
1441                     error("`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
1442                         sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
1443 
1444                 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().isnogc, "non-@nogc");
1445 
1446                 return true;
1447             }
1448         }
1449         return false;
1450     }
1451 
1452     /********************************************
1453      * Check that the postblit is callable if t is an array of structs.
1454      * Returns true if error happens.
1455      */
1456     extern (D) final bool checkPostblit(Scope* sc, Type t)
1457     {
1458         if (auto ts = t.baseElemOf().isTypeStruct())
1459         {
1460             if (global.params.useTypeInfo)
1461             {
1462                 // https://issues.dlang.org/show_bug.cgi?id=11395
1463                 // Require TypeInfo generation for array concatenation
1464                 semanticTypeInfo(sc, t);
1465             }
1466 
1467             StructDeclaration sd = ts.sym;
1468             if (sd.postblit)
1469             {
1470                 if (sd.postblit.checkDisabled(loc, sc))
1471                     return true;
1472 
1473                 //checkDeprecated(sc, sd.postblit);        // necessary?
1474                 checkPurity(sc, sd.postblit);
1475                 checkSafety(sc, sd.postblit);
1476                 checkNogc(sc, sd.postblit);
1477                 //checkAccess(sd, loc, sc, sd.postblit);   // necessary?
1478                 return false;
1479             }
1480         }
1481         return false;
1482     }
1483 
1484     extern (D) final bool checkRightThis(Scope* sc)
1485     {
1486         if (op == TOK.error)
1487             return true;
1488         if (op == TOK.variable && type.ty != Terror)
1489         {
1490             VarExp ve = cast(VarExp)this;
1491             if (isNeedThisScope(sc, ve.var))
1492             {
1493                 //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
1494                 //        sc.intypeof, sc.getStructClassScope(), func, fdthis);
1495                 error("need `this` for `%s` of type `%s`", ve.var.toChars(), ve.var.type.toChars());
1496                 return true;
1497             }
1498         }
1499         return false;
1500     }
1501 
1502     /*******************************
1503      * Check whether the expression allows RMW operations, error with rmw operator diagnostic if not.
1504      * ex is the RHS expression, or NULL if ++/-- is used (for diagnostics)
1505      * Returns true if error occurs.
1506      */
1507     extern (D) final bool checkReadModifyWrite(TOK rmwOp, Expression ex = null)
1508     {
1509         //printf("Expression::checkReadModifyWrite() %s %s", toChars(), ex ? ex.toChars() : "");
1510         if (!type || !type.isShared() || type.isTypeStruct() || type.isTypeClass())
1511             return false;
1512 
1513         // atomicOp uses opAssign (+=/-=) rather than opOp (++/--) for the CT string literal.
1514         switch (rmwOp)
1515         {
1516         case TOK.plusPlus:
1517         case TOK.prePlusPlus:
1518             rmwOp = TOK.addAssign;
1519             break;
1520         case TOK.minusMinus:
1521         case TOK.preMinusMinus:
1522             rmwOp = TOK.minAssign;
1523             break;
1524         default:
1525             break;
1526         }
1527 
1528         error("read-modify-write operations are not allowed for `shared` variables");
1529         errorSupplemental("Use `core.atomic.atomicOp!\"%s\"(%s, %s)` instead",
1530                           Token.toChars(rmwOp), toChars(), ex ? ex.toChars() : "1");
1531         return true;
1532     }
1533 
1534     /***************************************
1535      * Parameters:
1536      *      sc:     scope
1537      *      flag:   1: do not issue error message for invalid modification
1538      * Returns:
1539      *      Whether the type is modifiable
1540      */
1541     Modifiable checkModifiable(Scope* sc, int flag = 0)
1542     {
1543         return type ? Modifiable.yes : Modifiable.no; // default modifiable
1544     }
1545 
1546     /*****************************
1547      * If expression can be tested for true or false,
1548      * returns the modified expression.
1549      * Otherwise returns ErrorExp.
1550      */
1551     Expression toBoolean(Scope* sc)
1552     {
1553         // Default is 'yes' - do nothing
1554         Expression e = this;
1555         Type t = type;
1556         Type tb = type.toBasetype();
1557         Type att = null;
1558 
1559         while (1)
1560         {
1561             // Structs can be converted to bool using opCast(bool)()
1562             if (auto ts = tb.isTypeStruct())
1563             {
1564                 AggregateDeclaration ad = ts.sym;
1565                 /* Don't really need to check for opCast first, but by doing so we
1566                  * get better error messages if it isn't there.
1567                  */
1568                 if (Dsymbol fd = search_function(ad, Id._cast))
1569                 {
1570                     e = new CastExp(loc, e, Type.tbool);
1571                     e = e.expressionSemantic(sc);
1572                     return e;
1573                 }
1574 
1575                 // Forward to aliasthis.
1576                 if (ad.aliasthis && !(att && tb.equivalent(att)))
1577                 {
1578                     if (!att && tb.checkAliasThisRec())
1579                         att = tb;
1580                     e = resolveAliasThis(sc, e);
1581                     t = e.type;
1582                     tb = e.type.toBasetype();
1583                     continue;
1584                 }
1585             }
1586             break;
1587         }
1588 
1589         if (!t.isBoolean())
1590         {
1591             if (tb != Type.terror)
1592                 error("expression `%s` of type `%s` does not have a boolean value", toChars(), t.toChars());
1593             return ErrorExp.get();
1594         }
1595         return e;
1596     }
1597 
1598     /************************************************
1599      * Destructors are attached to VarDeclarations.
1600      * Hence, if expression returns a temp that needs a destructor,
1601      * make sure and create a VarDeclaration for that temp.
1602      */
1603     Expression addDtorHook(Scope* sc)
1604     {
1605         return this;
1606     }
1607 
1608     /******************************
1609      * Take address of expression.
1610      */
1611     final Expression addressOf()
1612     {
1613         //printf("Expression::addressOf()\n");
1614         debug
1615         {
1616             assert(op == TOK.error || isLvalue());
1617         }
1618         Expression e = new AddrExp(loc, this, type.pointerTo());
1619         return e;
1620     }
1621 
1622     /******************************
1623      * If this is a reference, dereference it.
1624      */
1625     final Expression deref()
1626     {
1627         //printf("Expression::deref()\n");
1628         // type could be null if forward referencing an 'auto' variable
1629         if (type)
1630             if (auto tr = type.isTypeReference())
1631             {
1632                 Expression e = new PtrExp(loc, this, tr.next);
1633                 return e;
1634             }
1635         return this;
1636     }
1637 
1638     final Expression optimize(int result, bool keepLvalue = false)
1639     {
1640         return Expression_optimize(this, result, keepLvalue);
1641     }
1642 
1643     // Entry point for CTFE.
1644     // A compile-time result is required. Give an error if not possible
1645     final Expression ctfeInterpret()
1646     {
1647         return .ctfeInterpret(this);
1648     }
1649 
1650     final int isConst()
1651     {
1652         return .isConst(this);
1653     }
1654 
1655     /********************************
1656      * Does this expression statically evaluate to a boolean 'result' (true or false)?
1657      */
1658     bool isBool(bool result)
1659     {
1660         return false;
1661     }
1662 
1663     bool hasCode()
1664     {
1665         return true;
1666     }
1667 
1668     final pure inout nothrow @nogc
1669     {
1670         inout(IntegerExp)   isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
1671         inout(ErrorExp)     isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
1672         inout(VoidInitExp)  isVoidInitExp() { return op == TOK.void_ ? cast(typeof(return))this : null; }
1673         inout(RealExp)      isRealExp() { return op == TOK.float64 ? cast(typeof(return))this : null; }
1674         inout(ComplexExp)   isComplexExp() { return op == TOK.complex80 ? cast(typeof(return))this : null; }
1675         inout(IdentifierExp) isIdentifierExp() { return op == TOK.identifier ? cast(typeof(return))this : null; }
1676         inout(DollarExp)    isDollarExp() { return op == TOK.dollar ? cast(typeof(return))this : null; }
1677         inout(DsymbolExp)   isDsymbolExp() { return op == TOK.dSymbol ? cast(typeof(return))this : null; }
1678         inout(ThisExp)      isThisExp() { return op == TOK.this_ ? cast(typeof(return))this : null; }
1679         inout(SuperExp)     isSuperExp() { return op == TOK.super_ ? cast(typeof(return))this : null; }
1680         inout(NullExp)      isNullExp() { return op == TOK.null_ ? cast(typeof(return))this : null; }
1681         inout(StringExp)    isStringExp() { return op == TOK.string_ ? cast(typeof(return))this : null; }
1682         inout(TupleExp)     isTupleExp() { return op == TOK.tuple ? cast(typeof(return))this : null; }
1683         inout(ArrayLiteralExp) isArrayLiteralExp() { return op == TOK.arrayLiteral ? cast(typeof(return))this : null; }
1684         inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == TOK.assocArrayLiteral ? cast(typeof(return))this : null; }
1685         inout(StructLiteralExp) isStructLiteralExp() { return op == TOK.structLiteral ? cast(typeof(return))this : null; }
1686         inout(TypeExp)      isTypeExp() { return op == TOK.type ? cast(typeof(return))this : null; }
1687         inout(ScopeExp)     isScopeExp() { return op == TOK.scope_ ? cast(typeof(return))this : null; }
1688         inout(TemplateExp)  isTemplateExp() { return op == TOK.template_ ? cast(typeof(return))this : null; }
1689         inout(NewExp) isNewExp() { return op == TOK.new_ ? cast(typeof(return))this : null; }
1690         inout(NewAnonClassExp) isNewAnonClassExp() { return op == TOK.newAnonymousClass ? cast(typeof(return))this : null; }
1691         inout(SymOffExp)    isSymOffExp() { return op == TOK.symbolOffset ? cast(typeof(return))this : null; }
1692         inout(VarExp)       isVarExp() { return op == TOK.variable ? cast(typeof(return))this : null; }
1693         inout(OverExp)      isOverExp() { return op == TOK.overloadSet ? cast(typeof(return))this : null; }
1694         inout(FuncExp)      isFuncExp() { return op == TOK.function_ ? cast(typeof(return))this : null; }
1695         inout(DeclarationExp) isDeclarationExp() { return op == TOK.declaration ? cast(typeof(return))this : null; }
1696         inout(TypeidExp)    isTypeidExp() { return op == TOK.typeid_ ? cast(typeof(return))this : null; }
1697         inout(TraitsExp)    isTraitsExp() { return op == TOK.traits ? cast(typeof(return))this : null; }
1698         inout(HaltExp)      isHaltExp() { return op == TOK.halt ? cast(typeof(return))this : null; }
1699         inout(IsExp)        isExp() { return op == TOK.is_ ? cast(typeof(return))this : null; }
1700         inout(MixinExp)     isMixinExp() { return op == TOK.mixin_ ? cast(typeof(return))this : null; }
1701         inout(ImportExp)    isImportExp() { return op == TOK.import_ ? cast(typeof(return))this : null; }
1702         inout(AssertExp)    isAssertExp() { return op == TOK.assert_ ? cast(typeof(return))this : null; }
1703         inout(DotIdExp)     isDotIdExp() { return op == TOK.dotIdentifier ? cast(typeof(return))this : null; }
1704         inout(DotTemplateExp) isDotTemplateExp() { return op == TOK.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1705         inout(DotVarExp)    isDotVarExp() { return op == TOK.dotVariable ? cast(typeof(return))this : null; }
1706         inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == TOK.dotTemplateInstance ? cast(typeof(return))this : null; }
1707         inout(DelegateExp)  isDelegateExp() { return op == TOK.delegate_ ? cast(typeof(return))this : null; }
1708         inout(DotTypeExp)   isDotTypeExp() { return op == TOK.dotType ? cast(typeof(return))this : null; }
1709         inout(CallExp)      isCallExp() { return op == TOK.call ? cast(typeof(return))this : null; }
1710         inout(AddrExp)      isAddrExp() { return op == TOK.address ? cast(typeof(return))this : null; }
1711         inout(PtrExp)       isPtrExp() { return op == TOK.star ? cast(typeof(return))this : null; }
1712         inout(NegExp)       isNegExp() { return op == TOK.negate ? cast(typeof(return))this : null; }
1713         inout(UAddExp)      isUAddExp() { return op == TOK.uadd ? cast(typeof(return))this : null; }
1714         inout(ComExp)       isComExp() { return op == TOK.tilde ? cast(typeof(return))this : null; }
1715         inout(NotExp)       isNotExp() { return op == TOK.not ? cast(typeof(return))this : null; }
1716         inout(DeleteExp)    isDeleteExp() { return op == TOK.delete_ ? cast(typeof(return))this : null; }
1717         inout(CastExp)      isCastExp() { return op == TOK.cast_ ? cast(typeof(return))this : null; }
1718         inout(VectorExp)    isVectorExp() { return op == TOK.vector ? cast(typeof(return))this : null; }
1719         inout(VectorArrayExp) isVectorArrayExp() { return op == TOK.vectorArray ? cast(typeof(return))this : null; }
1720         inout(SliceExp)     isSliceExp() { return op == TOK.slice ? cast(typeof(return))this : null; }
1721         inout(ArrayLengthExp) isArrayLengthExp() { return op == TOK.arrayLength ? cast(typeof(return))this : null; }
1722         inout(ArrayExp)     isArrayExp() { return op == TOK.array ? cast(typeof(return))this : null; }
1723         inout(DotExp)       isDotExp() { return op == TOK.dot ? cast(typeof(return))this : null; }
1724         inout(CommaExp)     isCommaExp() { return op == TOK.comma ? cast(typeof(return))this : null; }
1725         inout(IntervalExp)  isIntervalExp() { return op == TOK.interval ? cast(typeof(return))this : null; }
1726         inout(DelegatePtrExp)     isDelegatePtrExp() { return op == TOK.delegatePointer ? cast(typeof(return))this : null; }
1727         inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == TOK.delegateFunctionPointer ? cast(typeof(return))this : null; }
1728         inout(IndexExp)     isIndexExp() { return op == TOK.index ? cast(typeof(return))this : null; }
1729         inout(PostExp)      isPostExp()  { return (op == TOK.plusPlus || op == TOK.minusMinus) ? cast(typeof(return))this : null; }
1730         inout(PreExp)       isPreExp()   { return (op == TOK.prePlusPlus || op == TOK.preMinusMinus) ? cast(typeof(return))this : null; }
1731         inout(AssignExp)    isAssignExp()    { return op == TOK.assign ? cast(typeof(return))this : null; }
1732         inout(ConstructExp) isConstructExp() { return op == TOK.construct ? cast(typeof(return))this : null; }
1733         inout(BlitExp)      isBlitExp()      { return op == TOK.blit ? cast(typeof(return))this : null; }
1734         inout(AddAssignExp) isAddAssignExp() { return op == TOK.addAssign ? cast(typeof(return))this : null; }
1735         inout(MinAssignExp) isMinAssignExp() { return op == TOK.minAssign ? cast(typeof(return))this : null; }
1736         inout(MulAssignExp) isMulAssignExp() { return op == TOK.mulAssign ? cast(typeof(return))this : null; }
1737 
1738         inout(DivAssignExp) isDivAssignExp() { return op == TOK.divAssign ? cast(typeof(return))this : null; }
1739         inout(ModAssignExp) isModAssignExp() { return op == TOK.modAssign ? cast(typeof(return))this : null; }
1740         inout(AndAssignExp) isAndAssignExp() { return op == TOK.andAssign ? cast(typeof(return))this : null; }
1741         inout(OrAssignExp)  isOrAssignExp()  { return op == TOK.orAssign ? cast(typeof(return))this : null; }
1742         inout(XorAssignExp) isXorAssignExp() { return op == TOK.xorAssign ? cast(typeof(return))this : null; }
1743         inout(PowAssignExp) isPowAssignExp() { return op == TOK.powAssign ? cast(typeof(return))this : null; }
1744 
1745         inout(ShlAssignExp)  isShlAssignExp()  { return op == TOK.leftShiftAssign ? cast(typeof(return))this : null; }
1746         inout(ShrAssignExp)  isShrAssignExp()  { return op == TOK.rightShiftAssign ? cast(typeof(return))this : null; }
1747         inout(UshrAssignExp) isUshrAssignExp() { return op == TOK.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1748 
1749         inout(CatAssignExp) isCatAssignExp() { return op == TOK.concatenateAssign
1750                                                 ? cast(typeof(return))this
1751                                                 : null; }
1752 
1753         inout(CatElemAssignExp) isCatElemAssignExp() { return op == TOK.concatenateElemAssign
1754                                                 ? cast(typeof(return))this
1755                                                 : null; }
1756 
1757         inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == TOK.concatenateDcharAssign
1758                                                 ? cast(typeof(return))this
1759                                                 : null; }
1760 
1761         inout(AddExp)      isAddExp() { return op == TOK.add ? cast(typeof(return))this : null; }
1762         inout(MinExp)      isMinExp() { return op == TOK.min ? cast(typeof(return))this : null; }
1763         inout(CatExp)      isCatExp() { return op == TOK.concatenate ? cast(typeof(return))this : null; }
1764         inout(MulExp)      isMulExp() { return op == TOK.mul ? cast(typeof(return))this : null; }
1765         inout(DivExp)      isDivExp() { return op == TOK.div ? cast(typeof(return))this : null; }
1766         inout(ModExp)      isModExp() { return op == TOK.mod ? cast(typeof(return))this : null; }
1767         inout(PowExp)      isPowExp() { return op == TOK.pow ? cast(typeof(return))this : null; }
1768         inout(ShlExp)      isShlExp() { return op == TOK.leftShift ? cast(typeof(return))this : null; }
1769         inout(ShrExp)      isShrExp() { return op == TOK.rightShift ? cast(typeof(return))this : null; }
1770         inout(UshrExp)     isUshrExp() { return op == TOK.unsignedRightShift ? cast(typeof(return))this : null; }
1771         inout(AndExp)      isAndExp() { return op == TOK.and ? cast(typeof(return))this : null; }
1772         inout(OrExp)       isOrExp() { return op == TOK.or ? cast(typeof(return))this : null; }
1773         inout(XorExp)      isXorExp() { return op == TOK.xor ? cast(typeof(return))this : null; }
1774         inout(LogicalExp)  isLogicalExp() { return (op == TOK.andAnd || op == TOK.orOr) ? cast(typeof(return))this : null; }
1775         //inout(CmpExp)    isCmpExp() { return op == TOK. ? cast(typeof(return))this : null; }
1776         inout(InExp)       isInExp() { return op == TOK.in_ ? cast(typeof(return))this : null; }
1777         inout(RemoveExp)   isRemoveExp() { return op == TOK.remove ? cast(typeof(return))this : null; }
1778         inout(EqualExp)    isEqualExp() { return (op == TOK.equal || op == TOK.notEqual) ? cast(typeof(return))this : null; }
1779         inout(IdentityExp) isIdentityExp() { return (op == TOK.identity || op == TOK.notIdentity) ? cast(typeof(return))this : null; }
1780         inout(CondExp)     isCondExp() { return op == TOK.question ? cast(typeof(return))this : null; }
1781         inout(DefaultInitExp)    isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
1782         inout(FileInitExp)       isFileInitExp() { return (op == TOK.file || op == TOK.fileFullPath) ? cast(typeof(return))this : null; }
1783         inout(LineInitExp)       isLineInitExp() { return op == TOK.line ? cast(typeof(return))this : null; }
1784         inout(ModuleInitExp)     isModuleInitExp() { return op == TOK.moduleString ? cast(typeof(return))this : null; }
1785         inout(FuncInitExp)       isFuncInitExp() { return op == TOK.functionString ? cast(typeof(return))this : null; }
1786         inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == TOK.prettyFunction ? cast(typeof(return))this : null; }
1787         inout(ClassReferenceExp) isClassReferenceExp() { return op == TOK.classReference ? cast(typeof(return))this : null; }
1788         inout(ThrownExceptionExp) isThrownExceptionExp() { return op == TOK.thrownException ? cast(typeof(return))this : null; }
1789     }
1790 
1791     inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1792     {
1793         return null;
1794     }
1795 
1796     override void accept(Visitor v)
1797     {
1798         v.visit(this);
1799     }
1800 }
1801 
1802 /***********************************************************
1803  */
1804 extern (C++) final class IntegerExp : Expression
1805 {
1806     private dinteger_t value;
1807 
1808     extern (D) this(const ref Loc loc, dinteger_t value, Type type)
1809     {
1810         super(loc, TOK.int64, __traits(classInstanceSize, IntegerExp));
1811         //printf("IntegerExp(value = %lld, type = '%s')\n", value, type ? type.toChars() : "");
1812         assert(type);
1813         if (!type.isscalar())
1814         {
1815             //printf("%s, loc = %d\n", toChars(), loc.linnum);
1816             if (type.ty != Terror)
1817                 error("integral constant must be scalar type, not `%s`", type.toChars());
1818             type = Type.terror;
1819         }
1820         this.type = type;
1821         this.value = normalize(type.toBasetype().ty, value);
1822     }
1823 
1824     extern (D) this(dinteger_t value)
1825     {
1826         super(Loc.initial, TOK.int64, __traits(classInstanceSize, IntegerExp));
1827         this.type = Type.tint32;
1828         this.value = cast(d_int32)value;
1829     }
1830 
1831     static IntegerExp create(Loc loc, dinteger_t value, Type type)
1832     {
1833         return new IntegerExp(loc, value, type);
1834     }
1835 
1836     // Same as create, but doesn't allocate memory.
1837     static void emplace(UnionExp* pue, Loc loc, dinteger_t value, Type type)
1838     {
1839         emplaceExp!(IntegerExp)(pue, loc, value, type);
1840     }
1841 
1842     override bool equals(const RootObject o) const
1843     {
1844         if (this == o)
1845             return true;
1846         if (auto ne = (cast(Expression)o).isIntegerExp())
1847         {
1848             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && value == ne.value)
1849             {
1850                 return true;
1851             }
1852         }
1853         return false;
1854     }
1855 
1856     override dinteger_t toInteger()
1857     {
1858         // normalize() is necessary until we fix all the paints of 'type'
1859         return value = normalize(type.toBasetype().ty, value);
1860     }
1861 
1862     override real_t toReal()
1863     {
1864         // normalize() is necessary until we fix all the paints of 'type'
1865         const ty = type.toBasetype().ty;
1866         const val = normalize(ty, value);
1867         value = val;
1868         return (ty == Tuns64)
1869             ? real_t(cast(d_uns64)val)
1870             : real_t(cast(d_int64)val);
1871     }
1872 
1873     override real_t toImaginary()
1874     {
1875         return CTFloat.zero;
1876     }
1877 
1878     override complex_t toComplex()
1879     {
1880         return complex_t(toReal());
1881     }
1882 
1883     override bool isBool(bool result)
1884     {
1885         bool r = toInteger() != 0;
1886         return result ? r : !r;
1887     }
1888 
1889     override Expression toLvalue(Scope* sc, Expression e)
1890     {
1891         if (!e)
1892             e = this;
1893         else if (!loc.isValid())
1894             loc = e.loc;
1895         e.error("cannot modify constant `%s`", e.toChars());
1896         return ErrorExp.get();
1897     }
1898 
1899     override void accept(Visitor v)
1900     {
1901         v.visit(this);
1902     }
1903 
1904     dinteger_t getInteger()
1905     {
1906         return value;
1907     }
1908 
1909     void setInteger(dinteger_t value)
1910     {
1911         this.value = normalize(type.toBasetype().ty, value);
1912     }
1913 
1914     extern (D) static dinteger_t normalize(TY ty, dinteger_t value)
1915     {
1916         /* 'Normalize' the value of the integer to be in range of the type
1917          */
1918         dinteger_t result;
1919         switch (ty)
1920         {
1921         case Tbool:
1922             result = (value != 0);
1923             break;
1924 
1925         case Tint8:
1926             result = cast(d_int8)value;
1927             break;
1928 
1929         case Tchar:
1930         case Tuns8:
1931             result = cast(d_uns8)value;
1932             break;
1933 
1934         case Tint16:
1935             result = cast(d_int16)value;
1936             break;
1937 
1938         case Twchar:
1939         case Tuns16:
1940             result = cast(d_uns16)value;
1941             break;
1942 
1943         case Tint32:
1944             result = cast(d_int32)value;
1945             break;
1946 
1947         case Tdchar:
1948         case Tuns32:
1949             result = cast(d_uns32)value;
1950             break;
1951 
1952         case Tint64:
1953             result = cast(d_int64)value;
1954             break;
1955 
1956         case Tuns64:
1957             result = cast(d_uns64)value;
1958             break;
1959 
1960         case Tpointer:
1961             if (target.ptrsize == 8)
1962                 goto case Tuns64;
1963             if (target.ptrsize == 4)
1964                 goto case Tuns32;
1965             if (target.ptrsize == 2)
1966                 goto case Tuns16;
1967             assert(0);
1968 
1969         default:
1970             break;
1971         }
1972         return result;
1973     }
1974 
1975     override IntegerExp syntaxCopy()
1976     {
1977         return this;
1978     }
1979 
1980     /**
1981      * Use this instead of creating new instances for commonly used literals
1982      * such as 0 or 1.
1983      *
1984      * Parameters:
1985      *      v = The value of the expression
1986      * Returns:
1987      *      A static instance of the expression, typed as `Tint32`.
1988      */
1989     static IntegerExp literal(int v)()
1990     {
1991         __gshared IntegerExp theConstant;
1992         if (!theConstant)
1993             theConstant = new IntegerExp(v);
1994         return theConstant;
1995     }
1996 
1997     /**
1998      * Use this instead of creating new instances for commonly used bools.
1999      *
2000      * Parameters:
2001      *      b = The value of the expression
2002      * Returns:
2003      *      A static instance of the expression, typed as `Type.tbool`.
2004      */
2005     static IntegerExp createBool(bool b)
2006     {
2007         __gshared IntegerExp trueExp, falseExp;
2008         if (!trueExp)
2009         {
2010             trueExp = new IntegerExp(Loc.initial, 1, Type.tbool);
2011             falseExp = new IntegerExp(Loc.initial, 0, Type.tbool);
2012         }
2013         return b ? trueExp : falseExp;
2014     }
2015 }
2016 
2017 /***********************************************************
2018  * Use this expression for error recovery.
2019  * It should behave as a 'sink' to prevent further cascaded error messages.
2020  */
2021 extern (C++) final class ErrorExp : Expression
2022 {
2023     private extern (D) this()
2024     {
2025         super(Loc.initial, TOK.error, __traits(classInstanceSize, ErrorExp));
2026         type = Type.terror;
2027     }
2028 
2029     static ErrorExp get ()
2030     {
2031         if (errorexp is null)
2032             errorexp = new ErrorExp();
2033 
2034         if (global.errors == 0 && global.gaggedErrors == 0)
2035         {
2036             /* Unfortunately, errors can still leak out of gagged errors,
2037               * and we need to set the error count to prevent bogus code
2038               * generation. At least give a message.
2039               */
2040             .error(Loc.initial, "unknown, please file report on issues.dlang.org");
2041         }
2042 
2043         return errorexp;
2044     }
2045 
2046     override Expression toLvalue(Scope* sc, Expression e)
2047     {
2048         return this;
2049     }
2050 
2051     override void accept(Visitor v)
2052     {
2053         v.visit(this);
2054     }
2055 
2056     extern (C++) __gshared ErrorExp errorexp; // handy shared value
2057 }
2058 
2059 
2060 /***********************************************************
2061  * An uninitialized value,
2062  * generated from void initializers.
2063  */
2064 extern (C++) final class VoidInitExp : Expression
2065 {
2066     VarDeclaration var; /// the variable from where the void value came from, null if not known
2067                         /// Useful for error messages
2068 
2069     extern (D) this(VarDeclaration var)
2070     {
2071         super(var.loc, TOK.void_, __traits(classInstanceSize, VoidInitExp));
2072         this.var = var;
2073         this.type = var.type;
2074     }
2075 
2076     override const(char)* toChars() const
2077     {
2078         return "void";
2079     }
2080 
2081     override void accept(Visitor v)
2082     {
2083         v.visit(this);
2084     }
2085 }
2086 
2087 
2088 /***********************************************************
2089  */
2090 extern (C++) final class RealExp : Expression
2091 {
2092     real_t value;
2093 
2094     extern (D) this(const ref Loc loc, real_t value, Type type)
2095     {
2096         super(loc, TOK.float64, __traits(classInstanceSize, RealExp));
2097         //printf("RealExp::RealExp(%Lg)\n", value);
2098         this.value = value;
2099         this.type = type;
2100     }
2101 
2102     static RealExp create(Loc loc, real_t value, Type type)
2103     {
2104         return new RealExp(loc, value, type);
2105     }
2106 
2107     // Same as create, but doesn't allocate memory.
2108     static void emplace(UnionExp* pue, Loc loc, real_t value, Type type)
2109     {
2110         emplaceExp!(RealExp)(pue, loc, value, type);
2111     }
2112 
2113     override bool equals(const RootObject o) const
2114     {
2115         if (this == o)
2116             return true;
2117         if (auto ne = (cast(Expression)o).isRealExp())
2118         {
2119             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(value, ne.value))
2120             {
2121                 return true;
2122             }
2123         }
2124         return false;
2125     }
2126 
2127     override dinteger_t toInteger()
2128     {
2129         return cast(sinteger_t)toReal();
2130     }
2131 
2132     override uinteger_t toUInteger()
2133     {
2134         return cast(uinteger_t)toReal();
2135     }
2136 
2137     override real_t toReal()
2138     {
2139         return type.isreal() ? value : CTFloat.zero;
2140     }
2141 
2142     override real_t toImaginary()
2143     {
2144         return type.isreal() ? CTFloat.zero : value;
2145     }
2146 
2147     override complex_t toComplex()
2148     {
2149         return complex_t(toReal(), toImaginary());
2150     }
2151 
2152     override bool isBool(bool result)
2153     {
2154         return result ? cast(bool)value : !cast(bool)value;
2155     }
2156 
2157     override void accept(Visitor v)
2158     {
2159         v.visit(this);
2160     }
2161 }
2162 
2163 /***********************************************************
2164  */
2165 extern (C++) final class ComplexExp : Expression
2166 {
2167     complex_t value;
2168 
2169     extern (D) this(const ref Loc loc, complex_t value, Type type)
2170     {
2171         super(loc, TOK.complex80, __traits(classInstanceSize, ComplexExp));
2172         this.value = value;
2173         this.type = type;
2174         //printf("ComplexExp::ComplexExp(%s)\n", toChars());
2175     }
2176 
2177     static ComplexExp create(Loc loc, complex_t value, Type type)
2178     {
2179         return new ComplexExp(loc, value, type);
2180     }
2181 
2182     // Same as create, but doesn't allocate memory.
2183     static void emplace(UnionExp* pue, Loc loc, complex_t value, Type type)
2184     {
2185         emplaceExp!(ComplexExp)(pue, loc, value, type);
2186     }
2187 
2188     override bool equals(const RootObject o) const
2189     {
2190         if (this == o)
2191             return true;
2192         if (auto ne = (cast(Expression)o).isComplexExp())
2193         {
2194             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && RealIdentical(creall(value), creall(ne.value)) && RealIdentical(cimagl(value), cimagl(ne.value)))
2195             {
2196                 return true;
2197             }
2198         }
2199         return false;
2200     }
2201 
2202     override dinteger_t toInteger()
2203     {
2204         return cast(sinteger_t)toReal();
2205     }
2206 
2207     override uinteger_t toUInteger()
2208     {
2209         return cast(uinteger_t)toReal();
2210     }
2211 
2212     override real_t toReal()
2213     {
2214         return creall(value);
2215     }
2216 
2217     override real_t toImaginary()
2218     {
2219         return cimagl(value);
2220     }
2221 
2222     override complex_t toComplex()
2223     {
2224         return value;
2225     }
2226 
2227     override bool isBool(bool result)
2228     {
2229         if (result)
2230             return cast(bool)value;
2231         else
2232             return !value;
2233     }
2234 
2235     override void accept(Visitor v)
2236     {
2237         v.visit(this);
2238     }
2239 }
2240 
2241 /***********************************************************
2242  */
2243 extern (C++) class IdentifierExp : Expression
2244 {
2245     Identifier ident;
2246 
2247     extern (D) this(const ref Loc loc, Identifier ident)
2248     {
2249         super(loc, TOK.identifier, __traits(classInstanceSize, IdentifierExp));
2250         this.ident = ident;
2251     }
2252 
2253     static IdentifierExp create(Loc loc, Identifier ident)
2254     {
2255         return new IdentifierExp(loc, ident);
2256     }
2257 
2258     override final bool isLvalue()
2259     {
2260         return true;
2261     }
2262 
2263     override final Expression toLvalue(Scope* sc, Expression e)
2264     {
2265         return this;
2266     }
2267 
2268     override void accept(Visitor v)
2269     {
2270         v.visit(this);
2271     }
2272 }
2273 
2274 /***********************************************************
2275  */
2276 extern (C++) final class DollarExp : IdentifierExp
2277 {
2278     extern (D) this(const ref Loc loc)
2279     {
2280         super(loc, Id.dollar);
2281     }
2282 
2283     override void accept(Visitor v)
2284     {
2285         v.visit(this);
2286     }
2287 }
2288 
2289 /***********************************************************
2290  * Won't be generated by parser.
2291  */
2292 extern (C++) final class DsymbolExp : Expression
2293 {
2294     Dsymbol s;
2295     bool hasOverloads;
2296 
2297     extern (D) this(const ref Loc loc, Dsymbol s, bool hasOverloads = true)
2298     {
2299         super(loc, TOK.dSymbol, __traits(classInstanceSize, DsymbolExp));
2300         this.s = s;
2301         this.hasOverloads = hasOverloads;
2302     }
2303 
2304     override bool isLvalue()
2305     {
2306         return true;
2307     }
2308 
2309     override Expression toLvalue(Scope* sc, Expression e)
2310     {
2311         return this;
2312     }
2313 
2314     override void accept(Visitor v)
2315     {
2316         v.visit(this);
2317     }
2318 }
2319 
2320 /***********************************************************
2321  * http://dlang.org/spec/expression.html#this
2322  */
2323 extern (C++) class ThisExp : Expression
2324 {
2325     VarDeclaration var;
2326 
2327     extern (D) this(const ref Loc loc)
2328     {
2329         super(loc, TOK.this_, __traits(classInstanceSize, ThisExp));
2330         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2331     }
2332 
2333     this(const ref Loc loc, const TOK tok)
2334     {
2335         super(loc, tok, __traits(classInstanceSize, ThisExp));
2336         //printf("ThisExp::ThisExp() loc = %d\n", loc.linnum);
2337     }
2338 
2339     override ThisExp syntaxCopy()
2340     {
2341         auto r = cast(ThisExp) super.syntaxCopy();
2342         // require new semantic (possibly new `var` etc.)
2343         r.type = null;
2344         r.var = null;
2345         return r;
2346     }
2347 
2348     override final bool isBool(bool result)
2349     {
2350         return result;
2351     }
2352 
2353     override final bool isLvalue()
2354     {
2355         // Class `this` should be an rvalue; struct `this` should be an lvalue.
2356         return type.toBasetype().ty != Tclass;
2357     }
2358 
2359     override final Expression toLvalue(Scope* sc, Expression e)
2360     {
2361         if (type.toBasetype().ty == Tclass)
2362         {
2363             // Class `this` is an rvalue; struct `this` is an lvalue.
2364             return Expression.toLvalue(sc, e);
2365         }
2366         return this;
2367     }
2368 
2369     override void accept(Visitor v)
2370     {
2371         v.visit(this);
2372     }
2373 }
2374 
2375 /***********************************************************
2376  * http://dlang.org/spec/expression.html#super
2377  */
2378 extern (C++) final class SuperExp : ThisExp
2379 {
2380     extern (D) this(const ref Loc loc)
2381     {
2382         super(loc, TOK.super_);
2383     }
2384 
2385     override void accept(Visitor v)
2386     {
2387         v.visit(this);
2388     }
2389 }
2390 
2391 /***********************************************************
2392  * http://dlang.org/spec/expression.html#null
2393  */
2394 extern (C++) final class NullExp : Expression
2395 {
2396     extern (D) this(const ref Loc loc, Type type = null)
2397     {
2398         super(loc, TOK.null_, __traits(classInstanceSize, NullExp));
2399         this.type = type;
2400     }
2401 
2402     override bool equals(const RootObject o) const
2403     {
2404         if (auto e = o.isExpression())
2405         {
2406             if (e.op == TOK.null_ && type.equals(e.type))
2407             {
2408                 return true;
2409             }
2410         }
2411         return false;
2412     }
2413 
2414     override bool isBool(bool result)
2415     {
2416         return result ? false : true;
2417     }
2418 
2419     override StringExp toStringExp()
2420     {
2421         if (implicitConvTo(Type.tstring))
2422         {
2423             auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
2424             se.type = Type.tstring;
2425             return se;
2426         }
2427         return null;
2428     }
2429 
2430     override void accept(Visitor v)
2431     {
2432         v.visit(this);
2433     }
2434 }
2435 
2436 /***********************************************************
2437  * http://dlang.org/spec/expression.html#string_literals
2438  */
2439 extern (C++) final class StringExp : Expression
2440 {
2441     private union
2442     {
2443         char* string;   // if sz == 1
2444         wchar* wstring; // if sz == 2
2445         dchar* dstring; // if sz == 4
2446     }                   // (const if ownedByCtfe == OwnedBy.code)
2447     size_t len;         // number of code units
2448     ubyte sz = 1;       // 1: char, 2: wchar, 4: dchar
2449     ubyte committed;    // !=0 if type is committed
2450     enum char NoPostfix = 0;
2451     char postfix = NoPostfix;   // 'c', 'w', 'd'
2452     OwnedBy ownedByCtfe = OwnedBy.code;
2453 
2454     extern (D) this(const ref Loc loc, const(void)[] string)
2455     {
2456         super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
2457         this.string = cast(char*)string.ptr; // note that this.string should be const
2458         this.len = string.length;
2459         this.sz = 1;                    // work around LDC bug #1286
2460     }
2461 
2462     extern (D) this(const ref Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix = NoPostfix)
2463     {
2464         super(loc, TOK.string_, __traits(classInstanceSize, StringExp));
2465         this.string = cast(char*)string.ptr; // note that this.string should be const
2466         this.len = len;
2467         this.sz = sz;
2468         this.postfix = postfix;
2469     }
2470 
2471     static StringExp create(Loc loc, char* s)
2472     {
2473         return new StringExp(loc, s.toDString());
2474     }
2475 
2476     static StringExp create(Loc loc, void* string, size_t len)
2477     {
2478         return new StringExp(loc, string[0 .. len]);
2479     }
2480 
2481     // Same as create, but doesn't allocate memory.
2482     static void emplace(UnionExp* pue, Loc loc, char* s)
2483     {
2484         emplaceExp!(StringExp)(pue, loc, s.toDString());
2485     }
2486 
2487     extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string)
2488     {
2489         emplaceExp!(StringExp)(pue, loc, string);
2490     }
2491 
2492     extern (D) static void emplace(UnionExp* pue, Loc loc, const(void)[] string, size_t len, ubyte sz, char postfix)
2493     {
2494         emplaceExp!(StringExp)(pue, loc, string, len, sz, postfix);
2495     }
2496 
2497     override bool equals(const RootObject o) const
2498     {
2499         //printf("StringExp::equals('%s') %s\n", o.toChars(), toChars());
2500         if (auto e = o.isExpression())
2501         {
2502             if (auto se = e.isStringExp())
2503             {
2504                 return compare(se) == 0;
2505             }
2506         }
2507         return false;
2508     }
2509 
2510     /**********************************
2511      * Return the number of code units the string would be if it were re-encoded
2512      * as tynto.
2513      * Params:
2514      *      tynto = code unit type of the target encoding
2515      * Returns:
2516      *      number of code units
2517      */
2518     size_t numberOfCodeUnits(int tynto = 0) const
2519     {
2520         int encSize;
2521         switch (tynto)
2522         {
2523             case 0:      return len;
2524             case Tchar:  encSize = 1; break;
2525             case Twchar: encSize = 2; break;
2526             case Tdchar: encSize = 4; break;
2527             default:
2528                 assert(0);
2529         }
2530         if (sz == encSize)
2531             return len;
2532 
2533         size_t result = 0;
2534         dchar c;
2535 
2536         switch (sz)
2537         {
2538         case 1:
2539             for (size_t u = 0; u < len;)
2540             {
2541                 if (const s = utf_decodeChar(string[0 .. len], u, c))
2542                 {
2543                     error("%.*s", cast(int)s.length, s.ptr);
2544                     return 0;
2545                 }
2546                 result += utf_codeLength(encSize, c);
2547             }
2548             break;
2549 
2550         case 2:
2551             for (size_t u = 0; u < len;)
2552             {
2553                 if (const s = utf_decodeWchar(wstring[0 .. len], u, c))
2554                 {
2555                     error("%.*s", cast(int)s.length, s.ptr);
2556                     return 0;
2557                 }
2558                 result += utf_codeLength(encSize, c);
2559             }
2560             break;
2561 
2562         case 4:
2563             foreach (u; 0 .. len)
2564             {
2565                 result += utf_codeLength(encSize, dstring[u]);
2566             }
2567             break;
2568 
2569         default:
2570             assert(0);
2571         }
2572         return result;
2573     }
2574 
2575     /**********************************************
2576      * Write the contents of the string to dest.
2577      * Use numberOfCodeUnits() to determine size of result.
2578      * Params:
2579      *  dest = destination
2580      *  tyto = encoding type of the result
2581      *  zero = add terminating 0
2582      */
2583     void writeTo(void* dest, bool zero, int tyto = 0) const
2584     {
2585         int encSize;
2586         switch (tyto)
2587         {
2588             case 0:      encSize = sz; break;
2589             case Tchar:  encSize = 1; break;
2590             case Twchar: encSize = 2; break;
2591             case Tdchar: encSize = 4; break;
2592             default:
2593                 assert(0);
2594         }
2595         if (sz == encSize)
2596         {
2597             memcpy(dest, string, len * sz);
2598             if (zero)
2599                 memset(dest + len * sz, 0, sz);
2600         }
2601         else
2602             assert(0);
2603     }
2604 
2605     /*********************************************
2606      * Get the code unit at index i
2607      * Params:
2608      *  i = index
2609      * Returns:
2610      *  code unit at index i
2611      */
2612     dchar getCodeUnit(size_t i) const pure
2613     {
2614         assert(i < len);
2615         final switch (sz)
2616         {
2617         case 1:
2618             return string[i];
2619         case 2:
2620             return wstring[i];
2621         case 4:
2622             return dstring[i];
2623         }
2624     }
2625 
2626     /*********************************************
2627      * Set the code unit at index i to c
2628      * Params:
2629      *  i = index
2630      *  c = code unit to set it to
2631      */
2632     void setCodeUnit(size_t i, dchar c)
2633     {
2634         assert(i < len);
2635         final switch (sz)
2636         {
2637         case 1:
2638             string[i] = cast(char)c;
2639             break;
2640         case 2:
2641             wstring[i] = cast(wchar)c;
2642             break;
2643         case 4:
2644             dstring[i] = c;
2645             break;
2646         }
2647     }
2648 
2649     override StringExp toStringExp()
2650     {
2651         return this;
2652     }
2653 
2654     /****************************************
2655      * Convert string to char[].
2656      */
2657     StringExp toUTF8(Scope* sc)
2658     {
2659         if (sz != 1)
2660         {
2661             // Convert to UTF-8 string
2662             committed = 0;
2663             Expression e = castTo(sc, Type.tchar.arrayOf());
2664             e = e.optimize(WANTvalue);
2665             auto se = e.isStringExp();
2666             assert(se.sz == 1);
2667             return se;
2668         }
2669         return this;
2670     }
2671 
2672     /**
2673      * Compare two `StringExp` by length, then value
2674      *
2675      * The comparison is not the usual C-style comparison as seen with
2676      * `strcmp` or `memcmp`, but instead first compare based on the length.
2677      * This allows both faster lookup and sorting when comparing sparse data.
2678      *
2679      * This ordering scheme is relied on by the string-switching feature.
2680      * Code in Druntime's `core.internal.switch_` relies on this ordering
2681      * when doing a binary search among case statements.
2682      *
2683      * Both `StringExp` should be of the same encoding.
2684      *
2685      * Params:
2686      *   se2 = String expression to compare `this` to
2687      *
2688      * Returns:
2689      *   `0` when `this` is equal to se2, a value greater than `0` if
2690      *   `this` should be considered greater than `se2`,
2691      *   and a value less than `0` if `this` is lesser than `se2`.
2692      */
2693     int compare(const StringExp se2) const nothrow pure @nogc
2694     {
2695         //printf("StringExp::compare()\n");
2696         const len1 = len;
2697         const len2 = se2.len;
2698 
2699         assert(this.sz == se2.sz, "Comparing string expressions of different sizes");
2700         //printf("sz = %d, len1 = %d, len2 = %d\n", sz, (int)len1, (int)len2);
2701         if (len1 == len2)
2702         {
2703             switch (sz)
2704             {
2705             case 1:
2706                 return memcmp(string, se2..string, len1);
2707 
2708             case 2:
2709                 {
2710                     wchar* s1 = cast(wchar*)string;
2711                     wchar* s2 = cast(wchar*)se2..string;
2712                     foreach (u; 0 .. len)
2713                     {
2714                         if (s1[u] != s2[u])
2715                             return s1[u] - s2[u];
2716                     }
2717                 }
2718                 break;
2719             case 4:
2720                 {
2721                     dchar* s1 = cast(dchar*)string;
2722                     dchar* s2 = cast(dchar*)se2..string;
2723                     foreach (u; 0 .. len)
2724                     {
2725                         if (s1[u] != s2[u])
2726                             return s1[u] - s2[u];
2727                     }
2728                 }
2729                 break;
2730             default:
2731                 assert(0);
2732             }
2733         }
2734         return cast(int)(len1 - len2);
2735     }
2736 
2737     override bool isBool(bool result)
2738     {
2739         return result;
2740     }
2741 
2742     override bool isLvalue()
2743     {
2744         /* string literal is rvalue in default, but
2745          * conversion to reference of static array is only allowed.
2746          */
2747         return (type && type.toBasetype().ty == Tsarray);
2748     }
2749 
2750     override Expression toLvalue(Scope* sc, Expression e)
2751     {
2752         //printf("StringExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
2753         return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
2754     }
2755 
2756     override Expression modifiableLvalue(Scope* sc, Expression e)
2757     {
2758         error("cannot modify string literal `%s`", toChars());
2759         return ErrorExp.get();
2760     }
2761 
2762     uint charAt(uinteger_t i) const
2763     {
2764         uint value;
2765         switch (sz)
2766         {
2767         case 1:
2768             value = (cast(char*)string)[cast(size_t)i];
2769             break;
2770 
2771         case 2:
2772             value = (cast(ushort*)string)[cast(size_t)i];
2773             break;
2774 
2775         case 4:
2776             value = (cast(uint*)string)[cast(size_t)i];
2777             break;
2778 
2779         default:
2780             assert(0);
2781         }
2782         return value;
2783     }
2784 
2785     /********************************
2786      * Convert string contents to a 0 terminated string,
2787      * allocated by mem.xmalloc().
2788      */
2789     extern (D) const(char)[] toStringz() const
2790     {
2791         auto nbytes = len * sz;
2792         char* s = cast(char*)mem.xmalloc(nbytes + sz);
2793         writeTo(s, true);
2794         return s[0 .. nbytes];
2795     }
2796 
2797     extern (D) const(char)[] peekString() const
2798     {
2799         assert(sz == 1);
2800         return this.string[0 .. len];
2801     }
2802 
2803     extern (D) const(wchar)[] peekWstring() const
2804     {
2805         assert(sz == 2);
2806         return this.wstring[0 .. len];
2807     }
2808 
2809     extern (D) const(dchar)[] peekDstring() const
2810     {
2811         assert(sz == 4);
2812         return this.dstring[0 .. len];
2813     }
2814 
2815     /*******************
2816      * Get a slice of the data.
2817      */
2818     extern (D) const(ubyte)[] peekData() const
2819     {
2820         return cast(const(ubyte)[])this.string[0 .. len * sz];
2821     }
2822 
2823     /*******************
2824      * Borrow a slice of the data, so the caller can modify
2825      * it in-place (!)
2826      */
2827     extern (D) ubyte[] borrowData()
2828     {
2829         return cast(ubyte[])this.string[0 .. len * sz];
2830     }
2831 
2832     /***********************
2833      * Set new string data.
2834      * `this` becomes the new owner of the data.
2835      */
2836     extern (D) void setData(void* s, size_t len, ubyte sz)
2837     {
2838         this.string = cast(char*)s;
2839         this.len = len;
2840         this.sz = sz;
2841     }
2842 
2843     override void accept(Visitor v)
2844     {
2845         v.visit(this);
2846     }
2847 }
2848 
2849 /***********************************************************
2850  */
2851 extern (C++) final class TupleExp : Expression
2852 {
2853     /* Tuple-field access may need to take out its side effect part.
2854      * For example:
2855      *      foo().tupleof
2856      * is rewritten as:
2857      *      (ref __tup = foo(); tuple(__tup.field0, __tup.field1, ...))
2858      * The declaration of temporary variable __tup will be stored in TupleExp.e0.
2859      */
2860     Expression e0;
2861 
2862     Expressions* exps;
2863 
2864     extern (D) this(const ref Loc loc, Expression e0, Expressions* exps)
2865     {
2866         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2867         //printf("TupleExp(this = %p)\n", this);
2868         this.e0 = e0;
2869         this.exps = exps;
2870     }
2871 
2872     extern (D) this(const ref Loc loc, Expressions* exps)
2873     {
2874         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2875         //printf("TupleExp(this = %p)\n", this);
2876         this.exps = exps;
2877     }
2878 
2879     extern (D) this(const ref Loc loc, TupleDeclaration tup)
2880     {
2881         super(loc, TOK.tuple, __traits(classInstanceSize, TupleExp));
2882         this.exps = new Expressions();
2883 
2884         this.exps.reserve(tup.objects.dim);
2885         foreach (o; *tup.objects)
2886         {
2887             if (Dsymbol s = getDsymbol(o))
2888             {
2889                 /* If tuple element represents a symbol, translate to DsymbolExp
2890                  * to supply implicit 'this' if needed later.
2891                  */
2892                 Expression e = new DsymbolExp(loc, s);
2893                 this.exps.push(e);
2894             }
2895             else if (auto eo = o.isExpression())
2896             {
2897                 auto e = eo.copy();
2898                 e.loc = loc;    // https://issues.dlang.org/show_bug.cgi?id=15669
2899                 this.exps.push(e);
2900             }
2901             else if (auto t = o.isType())
2902             {
2903                 Expression e = new TypeExp(loc, t);
2904                 this.exps.push(e);
2905             }
2906             else
2907             {
2908                 error("`%s` is not an expression", o.toChars());
2909             }
2910         }
2911     }
2912 
2913     static TupleExp create(Loc loc, Expressions* exps)
2914     {
2915         return new TupleExp(loc, exps);
2916     }
2917 
2918     override TupleExp toTupleExp()
2919     {
2920         return this;
2921     }
2922 
2923     override TupleExp syntaxCopy()
2924     {
2925         return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2926     }
2927 
2928     override bool equals(const RootObject o) const
2929     {
2930         if (this == o)
2931             return true;
2932         if (auto e = o.isExpression())
2933             if (auto te = e.isTupleExp())
2934             {
2935                 if (exps.dim != te.exps.dim)
2936                     return false;
2937                 if (e0 && !e0.equals(te.e0) || !e0 && te.e0)
2938                     return false;
2939                 foreach (i, e1; *exps)
2940                 {
2941                     auto e2 = (*te.exps)[i];
2942                     if (!e1.equals(e2))
2943                         return false;
2944                 }
2945                 return true;
2946             }
2947         return false;
2948     }
2949 
2950     override void accept(Visitor v)
2951     {
2952         v.visit(this);
2953     }
2954 }
2955 
2956 /***********************************************************
2957  * [ e1, e2, e3, ... ]
2958  *
2959  * http://dlang.org/spec/expression.html#array_literals
2960  */
2961 extern (C++) final class ArrayLiteralExp : Expression
2962 {
2963     /** If !is null, elements[] can be sparse and basis is used for the
2964      * "default" element value. In other words, non-null elements[i] overrides
2965      * this 'basis' value.
2966      */
2967     Expression basis;
2968 
2969     Expressions* elements;
2970     OwnedBy ownedByCtfe = OwnedBy.code;
2971 
2972 
2973     extern (D) this(const ref Loc loc, Type type, Expressions* elements)
2974     {
2975         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2976         this.type = type;
2977         this.elements = elements;
2978     }
2979 
2980     extern (D) this(const ref Loc loc, Type type, Expression e)
2981     {
2982         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2983         this.type = type;
2984         elements = new Expressions();
2985         elements.push(e);
2986     }
2987 
2988     extern (D) this(const ref Loc loc, Type type, Expression basis, Expressions* elements)
2989     {
2990         super(loc, TOK.arrayLiteral, __traits(classInstanceSize, ArrayLiteralExp));
2991         this.type = type;
2992         this.basis = basis;
2993         this.elements = elements;
2994     }
2995 
2996     static ArrayLiteralExp create(Loc loc, Expressions* elements)
2997     {
2998         return new ArrayLiteralExp(loc, null, elements);
2999     }
3000 
3001     // Same as create, but doesn't allocate memory.
3002     static void emplace(UnionExp* pue, Loc loc, Expressions* elements)
3003     {
3004         emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
3005     }
3006 
3007     override ArrayLiteralExp syntaxCopy()
3008     {
3009         return new ArrayLiteralExp(loc,
3010             null,
3011             basis ? basis.syntaxCopy() : null,
3012             arraySyntaxCopy(elements));
3013     }
3014 
3015     override bool equals(const RootObject o) const
3016     {
3017         if (this == o)
3018             return true;
3019         auto e = o.isExpression();
3020         if (!e)
3021             return false;
3022         if (auto ae = e.isArrayLiteralExp())
3023         {
3024             if (elements.dim != ae.elements.dim)
3025                 return false;
3026             if (elements.dim == 0 && !type.equals(ae.type))
3027             {
3028                 return false;
3029             }
3030 
3031             foreach (i, e1; *elements)
3032             {
3033                 auto e2 = (*ae.elements)[i];
3034                 auto e1x = e1 ? e1 : basis;
3035                 auto e2x = e2 ? e2 : ae.basis;
3036 
3037                 if (e1x != e2x && (!e1x || !e2x || !e1x.equals(e2x)))
3038                     return false;
3039             }
3040             return true;
3041         }
3042         return false;
3043     }
3044 
3045     Expression getElement(size_t i)
3046     {
3047         return this[i];
3048     }
3049 
3050     Expression opIndex(size_t i)
3051     {
3052         auto el = (*elements)[i];
3053         return el ? el : basis;
3054     }
3055 
3056     override bool isBool(bool result)
3057     {
3058         size_t dim = elements ? elements.dim : 0;
3059         return result ? (dim != 0) : (dim == 0);
3060     }
3061 
3062     override StringExp toStringExp()
3063     {
3064         TY telem = type.nextOf().toBasetype().ty;
3065         if (telem.isSomeChar || (telem == Tvoid && (!elements || elements.dim == 0)))
3066         {
3067             ubyte sz = 1;
3068             if (telem == Twchar)
3069                 sz = 2;
3070             else if (telem == Tdchar)
3071                 sz = 4;
3072 
3073             OutBuffer buf;
3074             if (elements)
3075             {
3076                 foreach (i; 0 .. elements.dim)
3077                 {
3078                     auto ch = this[i];
3079                     if (ch.op != TOK.int64)
3080                         return null;
3081                     if (sz == 1)
3082                         buf.writeByte(cast(uint)ch.toInteger());
3083                     else if (sz == 2)
3084                         buf.writeword(cast(uint)ch.toInteger());
3085                     else
3086                         buf.write4(cast(uint)ch.toInteger());
3087                 }
3088             }
3089             char prefix;
3090             if (sz == 1)
3091             {
3092                 prefix = 'c';
3093                 buf.writeByte(0);
3094             }
3095             else if (sz == 2)
3096             {
3097                 prefix = 'w';
3098                 buf.writeword(0);
3099             }
3100             else
3101             {
3102                 prefix = 'd';
3103                 buf.write4(0);
3104             }
3105 
3106             const size_t len = buf.length / sz - 1;
3107             auto se = new StringExp(loc, buf.extractSlice()[0 .. len * sz], len, sz, prefix);
3108             se.sz = sz;
3109             se.type = type;
3110             return se;
3111         }
3112         return null;
3113     }
3114 
3115     override void accept(Visitor v)
3116     {
3117         v.visit(this);
3118     }
3119 }
3120 
3121 /***********************************************************
3122  * [ key0 : value0, key1 : value1, ... ]
3123  *
3124  * http://dlang.org/spec/expression.html#associative_array_literals
3125  */
3126 extern (C++) final class AssocArrayLiteralExp : Expression
3127 {
3128     Expressions* keys;
3129     Expressions* values;
3130 
3131     OwnedBy ownedByCtfe = OwnedBy.code;
3132 
3133     extern (D) this(const ref Loc loc, Expressions* keys, Expressions* values)
3134     {
3135         super(loc, TOK.assocArrayLiteral, __traits(classInstanceSize, AssocArrayLiteralExp));
3136         assert(keys.dim == values.dim);
3137         this.keys = keys;
3138         this.values = values;
3139     }
3140 
3141     override bool equals(const RootObject o) const
3142     {
3143         if (this == o)
3144             return true;
3145         auto e = o.isExpression();
3146         if (!e)
3147             return false;
3148         if (auto ae = e.isAssocArrayLiteralExp())
3149         {
3150             if (keys.dim != ae.keys.dim)
3151                 return false;
3152             size_t count = 0;
3153             foreach (i, key; *keys)
3154             {
3155                 foreach (j, akey; *ae.keys)
3156                 {
3157                     if (key.equals(akey))
3158                     {
3159                         if (!(*values)[i].equals((*ae.values)[j]))
3160                             return false;
3161                         ++count;
3162                     }
3163                 }
3164             }
3165             return count == keys.dim;
3166         }
3167         return false;
3168     }
3169 
3170     override AssocArrayLiteralExp syntaxCopy()
3171     {
3172         return new AssocArrayLiteralExp(loc, arraySyntaxCopy(keys), arraySyntaxCopy(values));
3173     }
3174 
3175     override bool isBool(bool result)
3176     {
3177         size_t dim = keys.dim;
3178         return result ? (dim != 0) : (dim == 0);
3179     }
3180 
3181     override void accept(Visitor v)
3182     {
3183         v.visit(this);
3184     }
3185 }
3186 
3187 enum stageScrub             = 0x1;  /// scrubReturnValue is running
3188 enum stageSearchPointers    = 0x2;  /// hasNonConstPointers is running
3189 enum stageOptimize          = 0x4;  /// optimize is running
3190 enum stageApply             = 0x8;  /// apply is running
3191 enum stageInlineScan        = 0x10; /// inlineScan is running
3192 enum stageToCBuffer         = 0x20; /// toCBuffer is running
3193 
3194 /***********************************************************
3195  * sd( e1, e2, e3, ... )
3196  */
3197 extern (C++) final class StructLiteralExp : Expression
3198 {
3199     StructDeclaration sd;   /// which aggregate this is for
3200     Expressions* elements;  /// parallels sd.fields[] with null entries for fields to skip
3201     Type stype;             /// final type of result (can be different from sd's type)
3202 
3203     Symbol* sym;            /// back end symbol to initialize with literal
3204 
3205     /** pointer to the origin instance of the expression.
3206      * once a new expression is created, origin is set to 'this'.
3207      * anytime when an expression copy is created, 'origin' pointer is set to
3208      * 'origin' pointer value of the original expression.
3209      */
3210     StructLiteralExp origin;
3211 
3212     /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
3213     StructLiteralExp inlinecopy;
3214 
3215     /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
3216      * current stage and unmarks before return from this function.
3217      * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
3218      * (with infinite recursion) of this expression.
3219      */
3220     int stageflags;
3221 
3222     bool useStaticInit;     /// if this is true, use the StructDeclaration's init symbol
3223     bool isOriginal = false; /// used when moving instances to indicate `this is this.origin`
3224     OwnedBy ownedByCtfe = OwnedBy.code;
3225 
3226     extern (D) this(const ref Loc loc, StructDeclaration sd, Expressions* elements, Type stype = null)
3227     {
3228         super(loc, TOK.structLiteral, __traits(classInstanceSize, StructLiteralExp));
3229         this.sd = sd;
3230         if (!elements)
3231             elements = new Expressions();
3232         this.elements = elements;
3233         this.stype = stype;
3234         this.origin = this;
3235         //printf("StructLiteralExp::StructLiteralExp(%s)\n", toChars());
3236     }
3237 
3238     static StructLiteralExp create(Loc loc, StructDeclaration sd, void* elements, Type stype = null)
3239     {
3240         return new StructLiteralExp(loc, sd, cast(Expressions*)elements, stype);
3241     }
3242 
3243     override bool equals(const RootObject o) const
3244     {
3245         if (this == o)
3246             return true;
3247         auto e = o.isExpression();
3248         if (!e)
3249             return false;
3250         if (auto se = e.isStructLiteralExp())
3251         {
3252             if (!type.equals(se.type))
3253                 return false;
3254             if (elements.dim != se.elements.dim)
3255                 return false;
3256             foreach (i, e1; *elements)
3257             {
3258                 auto e2 = (*se.elements)[i];
3259                 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
3260                     return false;
3261             }
3262             return true;
3263         }
3264         return false;
3265     }
3266 
3267     override StructLiteralExp syntaxCopy()
3268     {
3269         auto exp = new StructLiteralExp(loc, sd, arraySyntaxCopy(elements), type ? type : stype);
3270         exp.origin = this;
3271         return exp;
3272     }
3273 
3274     /**************************************
3275      * Gets expression at offset of type.
3276      * Returns NULL if not found.
3277      */
3278     Expression getField(Type type, uint offset)
3279     {
3280         //printf("StructLiteralExp::getField(this = %s, type = %s, offset = %u)\n",
3281         //  /*toChars()*/"", type.toChars(), offset);
3282         Expression e = null;
3283         int i = getFieldIndex(type, offset);
3284 
3285         if (i != -1)
3286         {
3287             //printf("\ti = %d\n", i);
3288             if (i >= sd.nonHiddenFields())
3289                 return null;
3290 
3291             assert(i < elements.dim);
3292             e = (*elements)[i];
3293             if (e)
3294             {
3295                 //printf("e = %s, e.type = %s\n", e.toChars(), e.type.toChars());
3296 
3297                 /* If type is a static array, and e is an initializer for that array,
3298                  * then the field initializer should be an array literal of e.
3299                  */
3300                 auto tsa = type.isTypeSArray();
3301                 if (tsa && e.type.castMod(0) != type.castMod(0))
3302                 {
3303                     const length = cast(size_t)tsa.dim.toInteger();
3304                     auto z = new Expressions(length);
3305                     foreach (ref q; *z)
3306                         q = e.copy();
3307                     e = new ArrayLiteralExp(loc, type, z);
3308                 }
3309                 else
3310                 {
3311                     e = e.copy();
3312                     e.type = type;
3313                 }
3314                 if (useStaticInit && e.type.needsNested())
3315                     if (auto se = e.isStructLiteralExp())
3316                     {
3317                         se.useStaticInit = true;
3318                     }
3319             }
3320         }
3321         return e;
3322     }
3323 
3324     /************************************
3325      * Get index of field.
3326      * Returns -1 if not found.
3327      */
3328     int getFieldIndex(Type type, uint offset)
3329     {
3330         /* Find which field offset is by looking at the field offsets
3331          */
3332         if (elements.dim)
3333         {
3334             foreach (i, v; sd.fields)
3335             {
3336                 if (offset == v.offset && type.size() == v.type.size())
3337                 {
3338                     /* context fields might not be filled. */
3339                     if (i >= sd.nonHiddenFields())
3340                         return cast(int)i;
3341                     if (auto e = (*elements)[i])
3342                     {
3343                         return cast(int)i;
3344                     }
3345                     break;
3346                 }
3347             }
3348         }
3349         return -1;
3350     }
3351 
3352     override Expression addDtorHook(Scope* sc)
3353     {
3354         /* If struct requires a destructor, rewrite as:
3355          *    (S tmp = S()),tmp
3356          * so that the destructor can be hung on tmp.
3357          */
3358         if (sd.dtor && sc.func)
3359         {
3360             /* Make an identifier for the temporary of the form:
3361              *   __sl%s%d, where %s is the struct name
3362              */
3363             char[10] buf = void;
3364             const prefix = "__sl";
3365             const ident = sd.ident.toString;
3366             const fullLen = prefix.length + ident.length;
3367             const len = fullLen < buf.length ? fullLen : buf.length;
3368             buf[0 .. prefix.length] = prefix;
3369             buf[prefix.length .. len] = ident[0 .. len - prefix.length];
3370 
3371             auto tmp = copyToTemp(0, buf[0 .. len], this);
3372             Expression ae = new DeclarationExp(loc, tmp);
3373             Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
3374             e = e.expressionSemantic(sc);
3375             return e;
3376         }
3377         return this;
3378     }
3379 
3380     override void accept(Visitor v)
3381     {
3382         v.visit(this);
3383     }
3384 }
3385 
3386 /***********************************************************
3387  * Mainly just a placeholder
3388  */
3389 extern (C++) final class TypeExp : Expression
3390 {
3391     extern (D) this(const ref Loc loc, Type type)
3392     {
3393         super(loc, TOK.type, __traits(classInstanceSize, TypeExp));
3394         //printf("TypeExp::TypeExp(%s)\n", type.toChars());
3395         this.type = type;
3396     }
3397 
3398     override TypeExp syntaxCopy()
3399     {
3400         return new TypeExp(loc, type.syntaxCopy());
3401     }
3402 
3403     override bool checkType()
3404     {
3405         error("type `%s` is not an expression", toChars());
3406         return true;
3407     }
3408 
3409     override bool checkValue()
3410     {
3411         error("type `%s` has no value", toChars());
3412         return true;
3413     }
3414 
3415     override void accept(Visitor v)
3416     {
3417         v.visit(this);
3418     }
3419 }
3420 
3421 /***********************************************************
3422  * Mainly just a placeholder of
3423  *  Package, Module, Nspace, and TemplateInstance (including TemplateMixin)
3424  *
3425  * A template instance that requires IFTI:
3426  *      foo!tiargs(fargs)       // foo!tiargs
3427  * is left until CallExp::semantic() or resolveProperties()
3428  */
3429 extern (C++) final class ScopeExp : Expression
3430 {
3431     ScopeDsymbol sds;
3432 
3433     extern (D) this(const ref Loc loc, ScopeDsymbol sds)
3434     {
3435         super(loc, TOK.scope_, __traits(classInstanceSize, ScopeExp));
3436         //printf("ScopeExp::ScopeExp(sds = '%s')\n", sds.toChars());
3437         //static int count; if (++count == 38) *(char*)0=0;
3438         this.sds = sds;
3439         assert(!sds.isTemplateDeclaration());   // instead, you should use TemplateExp
3440     }
3441 
3442     override ScopeExp syntaxCopy()
3443     {
3444         return new ScopeExp(loc, sds.syntaxCopy(null));
3445     }
3446 
3447     override bool checkType()
3448     {
3449         if (sds.isPackage())
3450         {
3451             error("%s `%s` has no type", sds.kind(), sds.toChars());
3452             return true;
3453         }
3454         if (auto ti = sds.isTemplateInstance())
3455         {
3456             //assert(ti.needsTypeInference(sc));
3457             if (ti.tempdecl &&
3458                 ti.semantictiargsdone &&
3459                 ti.semanticRun == PASS.init)
3460             {
3461                 error("partial %s `%s` has no type", sds.kind(), toChars());
3462                 return true;
3463             }
3464         }
3465         return false;
3466     }
3467 
3468     override bool checkValue()
3469     {
3470         error("%s `%s` has no value", sds.kind(), sds.toChars());
3471         return true;
3472     }
3473 
3474     override void accept(Visitor v)
3475     {
3476         v.visit(this);
3477     }
3478 }
3479 
3480 /***********************************************************
3481  * Mainly just a placeholder
3482  */
3483 extern (C++) final class TemplateExp : Expression
3484 {
3485     TemplateDeclaration td;
3486     FuncDeclaration fd;
3487 
3488     extern (D) this(const ref Loc loc, TemplateDeclaration td, FuncDeclaration fd = null)
3489     {
3490         super(loc, TOK.template_, __traits(classInstanceSize, TemplateExp));
3491         //printf("TemplateExp(): %s\n", td.toChars());
3492         this.td = td;
3493         this.fd = fd;
3494     }
3495 
3496     override bool isLvalue()
3497     {
3498         return fd !is null;
3499     }
3500 
3501     override Expression toLvalue(Scope* sc, Expression e)
3502     {
3503         if (!fd)
3504             return Expression.toLvalue(sc, e);
3505 
3506         assert(sc);
3507         return symbolToExp(fd, loc, sc, true);
3508     }
3509 
3510     override bool checkType()
3511     {
3512         error("%s `%s` has no type", td.kind(), toChars());
3513         return true;
3514     }
3515 
3516     override bool checkValue()
3517     {
3518         error("%s `%s` has no value", td.kind(), toChars());
3519         return true;
3520     }
3521 
3522     override void accept(Visitor v)
3523     {
3524         v.visit(this);
3525     }
3526 }
3527 
3528 /***********************************************************
3529  * thisexp.new(newargs) newtype(arguments)
3530  */
3531 extern (C++) final class NewExp : Expression
3532 {
3533     Expression thisexp;         // if !=null, 'this' for class being allocated
3534     Expressions* newargs;       // Array of Expression's to call new operator
3535     Type newtype;
3536     Expressions* arguments;     // Array of Expression's
3537 
3538     Expression argprefix;       // expression to be evaluated just before arguments[]
3539     CtorDeclaration member;     // constructor function
3540     NewDeclaration allocator;   // allocator function
3541     bool onstack;               // allocate on stack
3542     bool thrownew;              // this NewExp is the expression of a ThrowStatement
3543 
3544     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
3545     {
3546         super(loc, TOK.new_, __traits(classInstanceSize, NewExp));
3547         this.thisexp = thisexp;
3548         this.newargs = newargs;
3549         this.newtype = newtype;
3550         this.arguments = arguments;
3551     }
3552 
3553     static NewExp create(Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
3554     {
3555         return new NewExp(loc, thisexp, newargs, newtype, arguments);
3556     }
3557 
3558     override NewExp syntaxCopy()
3559     {
3560         return new NewExp(loc,
3561             thisexp ? thisexp.syntaxCopy() : null,
3562             arraySyntaxCopy(newargs),
3563             newtype.syntaxCopy(),
3564             arraySyntaxCopy(arguments));
3565     }
3566 
3567     override void accept(Visitor v)
3568     {
3569         v.visit(this);
3570     }
3571 }
3572 
3573 /***********************************************************
3574  * thisexp.new(newargs) class baseclasses { } (arguments)
3575  */
3576 extern (C++) final class NewAnonClassExp : Expression
3577 {
3578     Expression thisexp;     // if !=null, 'this' for class being allocated
3579     Expressions* newargs;   // Array of Expression's to call new operator
3580     ClassDeclaration cd;    // class being instantiated
3581     Expressions* arguments; // Array of Expression's to call class constructor
3582 
3583     extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
3584     {
3585         super(loc, TOK.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
3586         this.thisexp = thisexp;
3587         this.newargs = newargs;
3588         this.cd = cd;
3589         this.arguments = arguments;
3590     }
3591 
3592     override NewAnonClassExp syntaxCopy()
3593     {
3594         return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3595     }
3596 
3597     override void accept(Visitor v)
3598     {
3599         v.visit(this);
3600     }
3601 }
3602 
3603 /***********************************************************
3604  */
3605 extern (C++) class SymbolExp : Expression
3606 {
3607     Declaration var;
3608     Dsymbol originalScope; // original scope before inlining
3609     bool hasOverloads;
3610 
3611     extern (D) this(const ref Loc loc, TOK op, int size, Declaration var, bool hasOverloads)
3612     {
3613         super(loc, op, size);
3614         assert(var);
3615         this.var = var;
3616         this.hasOverloads = hasOverloads;
3617     }
3618 
3619     override void accept(Visitor v)
3620     {
3621         v.visit(this);
3622     }
3623 }
3624 
3625 /***********************************************************
3626  * Offset from symbol
3627  */
3628 extern (C++) final class SymOffExp : SymbolExp
3629 {
3630     dinteger_t offset;
3631 
3632     extern (D) this(const ref Loc loc, Declaration var, dinteger_t offset, bool hasOverloads = true)
3633     {
3634         if (auto v = var.isVarDeclaration())
3635         {
3636             // FIXME: This error report will never be handled anyone.
3637             // It should be done before the SymOffExp construction.
3638             if (v.needThis())
3639                 .error(loc, "need `this` for address of `%s`", v.toChars());
3640             hasOverloads = false;
3641         }
3642         super(loc, TOK.symbolOffset, __traits(classInstanceSize, SymOffExp), var, hasOverloads);
3643         this.offset = offset;
3644     }
3645 
3646     override bool isBool(bool result)
3647     {
3648         return result ? true : false;
3649     }
3650 
3651     override void accept(Visitor v)
3652     {
3653         v.visit(this);
3654     }
3655 }
3656 
3657 /***********************************************************
3658  * Variable
3659  */
3660 extern (C++) final class VarExp : SymbolExp
3661 {
3662     bool delegateWasExtracted;
3663     extern (D) this(const ref Loc loc, Declaration var, bool hasOverloads = true)
3664     {
3665         if (var.isVarDeclaration())
3666             hasOverloads = false;
3667 
3668         super(loc, TOK.variable, __traits(classInstanceSize, VarExp), var, hasOverloads);
3669         //printf("VarExp(this = %p, '%s', loc = %s)\n", this, var.toChars(), loc.toChars());
3670         //if (strcmp(var.ident.toChars(), "func") == 0) assert(0);
3671         this.type = var.type;
3672     }
3673 
3674     static VarExp create(Loc loc, Declaration var, bool hasOverloads = true)
3675     {
3676         return new VarExp(loc, var, hasOverloads);
3677     }
3678 
3679     override bool equals(const RootObject o) const
3680     {
3681         if (this == o)
3682             return true;
3683         if (auto ne = o.isExpression().isVarExp())
3684         {
3685             if (type.toHeadMutable().equals(ne.type.toHeadMutable()) && var == ne.var)
3686             {
3687                 return true;
3688             }
3689         }
3690         return false;
3691     }
3692 
3693     override Modifiable checkModifiable(Scope* sc, int flag)
3694     {
3695         //printf("VarExp::checkModifiable %s", toChars());
3696         assert(type);
3697         return var.checkModify(loc, sc, null, flag);
3698     }
3699 
3700     override bool isLvalue()
3701     {
3702         if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3703             return false;
3704         return true;
3705     }
3706 
3707     override Expression toLvalue(Scope* sc, Expression e)
3708     {
3709         if (var.storage_class & STC.manifest)
3710         {
3711             error("manifest constant `%s` cannot be modified", var.toChars());
3712             return ErrorExp.get();
3713         }
3714         if (var.storage_class & STC.lazy_ && !delegateWasExtracted)
3715         {
3716             error("lazy variable `%s` cannot be modified", var.toChars());
3717             return ErrorExp.get();
3718         }
3719         if (var.ident == Id.ctfe)
3720         {
3721             error("cannot modify compiler-generated variable `__ctfe`");
3722             return ErrorExp.get();
3723         }
3724         if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
3725         {
3726             error("cannot modify operator `$`");
3727             return ErrorExp.get();
3728         }
3729         return this;
3730     }
3731 
3732     override Expression modifiableLvalue(Scope* sc, Expression e)
3733     {
3734         //printf("VarExp::modifiableLvalue('%s')\n", var.toChars());
3735         if (var.storage_class & STC.manifest)
3736         {
3737             error("cannot modify manifest constant `%s`", toChars());
3738             return ErrorExp.get();
3739         }
3740         // See if this expression is a modifiable lvalue (i.e. not const)
3741         return Expression.modifiableLvalue(sc, e);
3742     }
3743 
3744     override void accept(Visitor v)
3745     {
3746         v.visit(this);
3747     }
3748 }
3749 
3750 /***********************************************************
3751  * Overload Set
3752  */
3753 extern (C++) final class OverExp : Expression
3754 {
3755     OverloadSet vars;
3756 
3757     extern (D) this(const ref Loc loc, OverloadSet s)
3758     {
3759         super(loc, TOK.overloadSet, __traits(classInstanceSize, OverExp));
3760         //printf("OverExp(this = %p, '%s')\n", this, var.toChars());
3761         vars = s;
3762         type = Type.tvoid;
3763     }
3764 
3765     override bool isLvalue()
3766     {
3767         return true;
3768     }
3769 
3770     override Expression toLvalue(Scope* sc, Expression e)
3771     {
3772         return this;
3773     }
3774 
3775     override void accept(Visitor v)
3776     {
3777         v.visit(this);
3778     }
3779 }
3780 
3781 /***********************************************************
3782  * Function/Delegate literal
3783  */
3784 
3785 extern (C++) final class FuncExp : Expression
3786 {
3787     FuncLiteralDeclaration fd;
3788     TemplateDeclaration td;
3789     TOK tok;
3790 
3791     extern (D) this(const ref Loc loc, Dsymbol s)
3792     {
3793         super(loc, TOK.function_, __traits(classInstanceSize, FuncExp));
3794         this.td = s.isTemplateDeclaration();
3795         this.fd = s.isFuncLiteralDeclaration();
3796         if (td)
3797         {
3798             assert(td.literal);
3799             assert(td.members && td.members.dim == 1);
3800             fd = (*td.members)[0].isFuncLiteralDeclaration();
3801         }
3802         tok = fd.tok; // save original kind of function/delegate/(infer)
3803         assert(fd.fbody);
3804     }
3805 
3806     override bool equals(const RootObject o) const
3807     {
3808         if (this == o)
3809             return true;
3810         auto e = o.isExpression();
3811         if (!e)
3812             return false;
3813         if (auto fe = e.isFuncExp())
3814         {
3815             return fd == fe.fd;
3816         }
3817         return false;
3818     }
3819 
3820     extern (D) void genIdent(Scope* sc)
3821     {
3822         if (fd.ident == Id.empty)
3823         {
3824             const(char)[] s;
3825             if (fd.fes)
3826                 s = "__foreachbody";
3827             else if (fd.tok == TOK.reserved)
3828                 s = "__lambda";
3829             else if (fd.tok == TOK.delegate_)
3830                 s = "__dgliteral";
3831             else
3832                 s = "__funcliteral";
3833 
3834             DsymbolTable symtab;
3835             if (FuncDeclaration func = sc.parent.isFuncDeclaration())
3836             {
3837                 if (func.localsymtab is null)
3838                 {
3839                     // Inside template constraint, symtab is not set yet.
3840                     // Initialize it lazily.
3841                     func.localsymtab = new DsymbolTable();
3842                 }
3843                 symtab = func.localsymtab;
3844             }
3845             else
3846             {
3847                 ScopeDsymbol sds = sc.parent.isScopeDsymbol();
3848                 if (!sds.symtab)
3849                 {
3850                     // Inside template constraint, symtab may not be set yet.
3851                     // Initialize it lazily.
3852                     assert(sds.isTemplateInstance());
3853                     sds.symtab = new DsymbolTable();
3854                 }
3855                 symtab = sds.symtab;
3856             }
3857             assert(symtab);
3858             Identifier id = Identifier.generateId(s, symtab.length() + 1);
3859             fd.ident = id;
3860             if (td)
3861                 td.ident = id;
3862             symtab.insert(td ? cast(Dsymbol)td : cast(Dsymbol)fd);
3863         }
3864     }
3865 
3866     override FuncExp syntaxCopy()
3867     {
3868         if (td)
3869             return new FuncExp(loc, td.syntaxCopy(null));
3870         else if (fd.semanticRun == PASS.init)
3871             return new FuncExp(loc, fd.syntaxCopy(null));
3872         else // https://issues.dlang.org/show_bug.cgi?id=13481
3873              // Prevent multiple semantic analysis of lambda body.
3874             return new FuncExp(loc, fd);
3875     }
3876 
3877     extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, int flag = 0)
3878     {
3879 
3880         static MATCH cannotInfer(Expression e, Type to, int flag)
3881         {
3882             if (!flag)
3883                 e.error("cannot infer parameter types from `%s`", to.toChars());
3884             return MATCH.nomatch;
3885         }
3886 
3887         //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
3888         if (presult)
3889             *presult = null;
3890 
3891         TypeFunction tof = null;
3892         if (to.ty == Tdelegate)
3893         {
3894             if (tok == TOK.function_)
3895             {
3896                 if (!flag)
3897                     error("cannot match function literal to delegate type `%s`", to.toChars());
3898                 return MATCH.nomatch;
3899             }
3900             tof = cast(TypeFunction)to.nextOf();
3901         }
3902         else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
3903         {
3904             if (tok == TOK.delegate_)
3905             {
3906                 if (!flag)
3907                     error("cannot match delegate literal to function pointer type `%s`", to.toChars());
3908                 return MATCH.nomatch;
3909             }
3910         }
3911 
3912         if (td)
3913         {
3914             if (!tof)
3915             {
3916                 return cannotInfer(this, to, flag);
3917             }
3918 
3919             // Parameter types inference from 'tof'
3920             assert(td._scope);
3921             TypeFunction tf = fd.type.isTypeFunction();
3922             //printf("\ttof = %s\n", tof.toChars());
3923             //printf("\ttf  = %s\n", tf.toChars());
3924             const dim = tf.parameterList.length;
3925 
3926             if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
3927                 return cannotInfer(this, to, flag);
3928 
3929             auto tiargs = new Objects();
3930             tiargs.reserve(td.parameters.dim);
3931 
3932             foreach (tp; *td.parameters)
3933             {
3934                 size_t u = 0;
3935                 foreach (i, p; tf.parameterList)
3936                 {
3937                     if (auto ti = p.type.isTypeIdentifier())
3938                         if (ti && ti.ident == tp.ident)
3939                             break;
3940 
3941                     ++u;
3942                 }
3943                 assert(u < dim);
3944                 Parameter pto = tof.parameterList[u];
3945                 Type t = pto.type;
3946                 if (t.ty == Terror)
3947                     return cannotInfer(this, to, flag);
3948                 tiargs.push(t);
3949             }
3950 
3951             // Set target of return type inference
3952             if (!tf.next && tof.next)
3953                 fd.treq = to;
3954 
3955             auto ti = new TemplateInstance(loc, td, tiargs);
3956             Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
3957 
3958             // Reset inference target for the later re-semantic
3959             fd.treq = null;
3960 
3961             if (ex.op == TOK.error)
3962                 return MATCH.nomatch;
3963             if (auto ef = ex.isFuncExp())
3964                 return ef.matchType(to, sc, presult, flag);
3965             else
3966                 return cannotInfer(this, to, flag);
3967         }
3968 
3969         if (!tof || !tof.next)
3970             return MATCH.nomatch;
3971 
3972         assert(type && type != Type.tvoid);
3973         if (fd.type.ty == Terror)
3974             return MATCH.nomatch;
3975         auto tfx = fd.type.isTypeFunction();
3976         bool convertMatch = (type.ty != to.ty);
3977 
3978         if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
3979         {
3980             /* If return type is inferred and covariant return,
3981              * tweak return statements to required return type.
3982              *
3983              * interface I {}
3984              * class C : Object, I{}
3985              *
3986              * I delegate() dg = delegate() { return new class C(); }
3987              */
3988             convertMatch = true;
3989 
3990             auto tfy = new TypeFunction(tfx.parameterList, tof.next,
3991                         tfx.linkage, STC.undefined_);
3992             tfy.mod = tfx.mod;
3993             tfy.isnothrow = tfx.isnothrow;
3994             tfy.isnogc = tfx.isnogc;
3995             tfy.purity = tfx.purity;
3996             tfy.isproperty = tfx.isproperty;
3997             tfy.isref = tfx.isref;
3998             tfy.isInOutParam = tfx.isInOutParam;
3999             tfy.isInOutQual = tfx.isInOutQual;
4000             tfy.deco = tfy.merge().deco;
4001 
4002             tfx = tfy;
4003         }
4004         Type tx;
4005         if (tok == TOK.delegate_ ||
4006             tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
4007         {
4008             // Allow conversion from implicit function pointer to delegate
4009             tx = new TypeDelegate(tfx);
4010             tx.deco = tx.merge().deco;
4011         }
4012         else
4013         {
4014             assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer);
4015             tx = tfx.pointerTo();
4016         }
4017         //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
4018 
4019         MATCH m = tx.implicitConvTo(to);
4020         if (m > MATCH.nomatch)
4021         {
4022             // MATCH.exact:      exact type match
4023             // MATCH.constant:      covairiant type match (eg. attributes difference)
4024             // MATCH.convert:    context conversion
4025             m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
4026 
4027             if (presult)
4028             {
4029                 (*presult) = cast(FuncExp)copy();
4030                 (*presult).type = to;
4031 
4032                 // https://issues.dlang.org/show_bug.cgi?id=12508
4033                 // Tweak function body for covariant returns.
4034                 (*presult).fd.modifyReturns(sc, tof.next);
4035             }
4036         }
4037         else if (!flag)
4038         {
4039             auto ts = toAutoQualChars(tx, to);
4040             error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
4041                 toChars(), ts[0], ts[1]);
4042         }
4043         return m;
4044     }
4045 
4046     override const(char)* toChars() const
4047     {
4048         return fd.toChars();
4049     }
4050 
4051     override bool checkType()
4052     {
4053         if (td)
4054         {
4055             error("template lambda has no type");
4056             return true;
4057         }
4058         return false;
4059     }
4060 
4061     override bool checkValue()
4062     {
4063         if (td)
4064         {
4065             error("template lambda has no value");
4066             return true;
4067         }
4068         return false;
4069     }
4070 
4071     override void accept(Visitor v)
4072     {
4073         v.visit(this);
4074     }
4075 }
4076 
4077 /***********************************************************
4078  * Declaration of a symbol
4079  *
4080  * D grammar allows declarations only as statements. However in AST representation
4081  * it can be part of any expression. This is used, for example, during internal
4082  * syntax re-writes to inject hidden symbols.
4083  */
4084 extern (C++) final class DeclarationExp : Expression
4085 {
4086     Dsymbol declaration;
4087 
4088     extern (D) this(const ref Loc loc, Dsymbol declaration)
4089     {
4090         super(loc, TOK.declaration, __traits(classInstanceSize, DeclarationExp));
4091         this.declaration = declaration;
4092     }
4093 
4094     override DeclarationExp syntaxCopy()
4095     {
4096         return new DeclarationExp(loc, declaration.syntaxCopy(null));
4097     }
4098 
4099     override bool hasCode()
4100     {
4101         if (auto vd = declaration.isVarDeclaration())
4102         {
4103             return !(vd.storage_class & (STC.manifest | STC.static_));
4104         }
4105         return false;
4106     }
4107 
4108     override void accept(Visitor v)
4109     {
4110         v.visit(this);
4111     }
4112 }
4113 
4114 /***********************************************************
4115  * typeid(int)
4116  */
4117 extern (C++) final class TypeidExp : Expression
4118 {
4119     RootObject obj;
4120 
4121     extern (D) this(const ref Loc loc, RootObject o)
4122     {
4123         super(loc, TOK.typeid_, __traits(classInstanceSize, TypeidExp));
4124         this.obj = o;
4125     }
4126 
4127     override TypeidExp syntaxCopy()
4128     {
4129         return new TypeidExp(loc, objectSyntaxCopy(obj));
4130     }
4131 
4132     override void accept(Visitor v)
4133     {
4134         v.visit(this);
4135     }
4136 }
4137 
4138 /***********************************************************
4139  * __traits(identifier, args...)
4140  */
4141 extern (C++) final class TraitsExp : Expression
4142 {
4143     Identifier ident;
4144     Objects* args;
4145 
4146     extern (D) this(const ref Loc loc, Identifier ident, Objects* args)
4147     {
4148         super(loc, TOK.traits, __traits(classInstanceSize, TraitsExp));
4149         this.ident = ident;
4150         this.args = args;
4151     }
4152 
4153     override TraitsExp syntaxCopy()
4154     {
4155         return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4156     }
4157 
4158     override void accept(Visitor v)
4159     {
4160         v.visit(this);
4161     }
4162 }
4163 
4164 /***********************************************************
4165  */
4166 extern (C++) final class HaltExp : Expression
4167 {
4168     extern (D) this(const ref Loc loc)
4169     {
4170         super(loc, TOK.halt, __traits(classInstanceSize, HaltExp));
4171     }
4172 
4173     override void accept(Visitor v)
4174     {
4175         v.visit(this);
4176     }
4177 }
4178 
4179 /***********************************************************
4180  * is(targ id tok tspec)
4181  * is(targ id == tok2)
4182  */
4183 extern (C++) final class IsExp : Expression
4184 {
4185     Type targ;
4186     Identifier id;      // can be null
4187     Type tspec;         // can be null
4188     TemplateParameters* parameters;
4189     TOK tok;            // ':' or '=='
4190     TOK tok2;           // 'struct', 'union', etc.
4191 
4192     extern (D) this(const ref Loc loc, Type targ, Identifier id, TOK tok, Type tspec, TOK tok2, TemplateParameters* parameters)
4193     {
4194         super(loc, TOK.is_, __traits(classInstanceSize, IsExp));
4195         this.targ = targ;
4196         this.id = id;
4197         this.tok = tok;
4198         this.tspec = tspec;
4199         this.tok2 = tok2;
4200         this.parameters = parameters;
4201     }
4202 
4203     override IsExp syntaxCopy()
4204     {
4205         // This section is identical to that in TemplateDeclaration::syntaxCopy()
4206         TemplateParameters* p = null;
4207         if (parameters)
4208         {
4209             p = new TemplateParameters(parameters.dim);
4210             foreach (i, el; *parameters)
4211                 (*p)[i] = el.syntaxCopy();
4212         }
4213         return new IsExp(loc, targ.syntaxCopy(), id, tok, tspec ? tspec.syntaxCopy() : null, tok2, p);
4214     }
4215 
4216     override void accept(Visitor v)
4217     {
4218         v.visit(this);
4219     }
4220 }
4221 
4222 /***********************************************************
4223  */
4224 extern (C++) abstract class UnaExp : Expression
4225 {
4226     Expression e1;
4227     Type att1;      // Save alias this type to detect recursion
4228 
4229     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1)
4230     {
4231         super(loc, op, size);
4232         this.e1 = e1;
4233     }
4234 
4235     override UnaExp syntaxCopy()
4236     {
4237         UnaExp e = cast(UnaExp)copy();
4238         e.type = null;
4239         e.e1 = e.e1.syntaxCopy();
4240         return e;
4241     }
4242 
4243     /********************************
4244      * The type for a unary expression is incompatible.
4245      * Print error message.
4246      * Returns:
4247      *  ErrorExp
4248      */
4249     final Expression incompatibleTypes()
4250     {
4251         if (e1.type.toBasetype() == Type.terror)
4252             return e1;
4253 
4254         if (e1.op == TOK.type)
4255         {
4256             error("incompatible type for `%s(%s)`: cannot use `%s` with types", Token.toChars(op), e1.toChars(), Token.toChars(op));
4257         }
4258         else
4259         {
4260             error("incompatible type for `%s(%s)`: `%s`", Token.toChars(op), e1.toChars(), e1.type.toChars());
4261         }
4262         return ErrorExp.get();
4263     }
4264 
4265     /*********************
4266      * Mark the operand as will never be dereferenced,
4267      * which is useful info for @safe checks.
4268      * Do before semantic() on operands rewrites them.
4269      */
4270     final void setNoderefOperand()
4271     {
4272         if (auto edi = e1.isDotIdExp())
4273             edi.noderef = true;
4274 
4275     }
4276 
4277     override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4278     {
4279         e1 = e1.resolveLoc(loc, sc);
4280         return this;
4281     }
4282 
4283     override void accept(Visitor v)
4284     {
4285         v.visit(this);
4286     }
4287 }
4288 
4289 alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4290 alias fp2_t = bool function(const ref Loc loc, TOK, Expression, Expression);
4291 
4292 /***********************************************************
4293  */
4294 extern (C++) abstract class BinExp : Expression
4295 {
4296     Expression e1;
4297     Expression e2;
4298     Type att1;      // Save alias this type to detect recursion
4299     Type att2;      // Save alias this type to detect recursion
4300 
4301     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
4302     {
4303         super(loc, op, size);
4304         this.e1 = e1;
4305         this.e2 = e2;
4306     }
4307 
4308     override BinExp syntaxCopy()
4309     {
4310         BinExp e = cast(BinExp)copy();
4311         e.type = null;
4312         e.e1 = e.e1.syntaxCopy();
4313         e.e2 = e.e2.syntaxCopy();
4314         return e;
4315     }
4316 
4317     /********************************
4318      * The types for a binary expression are incompatible.
4319      * Print error message.
4320      * Returns:
4321      *  ErrorExp
4322      */
4323     final Expression incompatibleTypes()
4324     {
4325         if (e1.type.toBasetype() == Type.terror)
4326             return e1;
4327         if (e2.type.toBasetype() == Type.terror)
4328             return e2;
4329 
4330         // CondExp uses 'a ? b : c' but we're comparing 'b : c'
4331         TOK thisOp = (op == TOK.question) ? TOK.colon : op;
4332         if (e1.op == TOK.type || e2.op == TOK.type)
4333         {
4334             error("incompatible types for `(%s) %s (%s)`: cannot use `%s` with types",
4335                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), Token.toChars(op));
4336         }
4337         else if (e1.type.equals(e2.type))
4338         {
4339             error("incompatible types for `(%s) %s (%s)`: both operands are of type `%s`",
4340                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), e1.type.toChars());
4341         }
4342         else
4343         {
4344             auto ts = toAutoQualChars(e1.type, e2.type);
4345             error("incompatible types for `(%s) %s (%s)`: `%s` and `%s`",
4346                 e1.toChars(), Token.toChars(thisOp), e2.toChars(), ts[0], ts[1]);
4347         }
4348         return ErrorExp.get();
4349     }
4350 
4351     extern (D) final Expression checkOpAssignTypes(Scope* sc)
4352     {
4353         // At that point t1 and t2 are the merged types. type is the original type of the lhs.
4354         Type t1 = e1.type;
4355         Type t2 = e2.type;
4356 
4357         // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
4358         // See issue 3841.
4359         // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
4360         if (op == TOK.addAssign || op == TOK.minAssign ||
4361             op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign ||
4362             op == TOK.powAssign)
4363         {
4364             if ((type.isintegral() && t2.isfloating()))
4365             {
4366                 warning("`%s %s %s` is performing truncating conversion", type.toChars(), Token.toChars(op), t2.toChars());
4367             }
4368         }
4369 
4370         // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
4371         if (op == TOK.mulAssign || op == TOK.divAssign || op == TOK.modAssign)
4372         {
4373             // Any multiplication by an imaginary or complex number yields a complex result.
4374             // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
4375             const(char)* opstr = Token.toChars(op);
4376             if (t1.isreal() && t2.iscomplex())
4377             {
4378                 error("`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4379                 return ErrorExp.get();
4380             }
4381             else if (t1.isimaginary() && t2.iscomplex())
4382             {
4383                 error("`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
4384                 return ErrorExp.get();
4385             }
4386             else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
4387             {
4388                 error("`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
4389                 return ErrorExp.get();
4390             }
4391         }
4392 
4393         // generate an error if this is a nonsensical += or -=, eg real += imaginary
4394         if (op == TOK.addAssign || op == TOK.minAssign)
4395         {
4396             // Addition or subtraction of a real and an imaginary is a complex result.
4397             // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
4398             if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
4399             {
4400                 error("`%s %s %s` is undefined (result is complex)", t1.toChars(), Token.toChars(op), t2.toChars());
4401                 return ErrorExp.get();
4402             }
4403             if (type.isreal() || type.isimaginary())
4404             {
4405                 assert(global.errors || t2.isfloating());
4406                 e2 = e2.castTo(sc, t1);
4407             }
4408         }
4409         if (op == TOK.mulAssign)
4410         {
4411             if (t2.isfloating())
4412             {
4413                 if (t1.isreal())
4414                 {
4415                     if (t2.isimaginary() || t2.iscomplex())
4416                     {
4417                         e2 = e2.castTo(sc, t1);
4418                     }
4419                 }
4420                 else if (t1.isimaginary())
4421                 {
4422                     if (t2.isimaginary() || t2.iscomplex())
4423                     {
4424                         switch (t1.ty)
4425                         {
4426                         case Timaginary32:
4427                             t2 = Type.tfloat32;
4428                             break;
4429 
4430                         case Timaginary64:
4431                             t2 = Type.tfloat64;
4432                             break;
4433 
4434                         case Timaginary80:
4435                             t2 = Type.tfloat80;
4436                             break;
4437 
4438                         default:
4439                             assert(0);
4440                         }
4441                         e2 = e2.castTo(sc, t2);
4442                     }
4443                 }
4444             }
4445         }
4446         else if (op == TOK.divAssign)
4447         {
4448             if (t2.isimaginary())
4449             {
4450                 if (t1.isreal())
4451                 {
4452                     // x/iv = i(-x/v)
4453                     // Therefore, the result is 0
4454                     e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
4455                     e2.type = t1;
4456                     Expression e = new AssignExp(loc, e1, e2);
4457                     e.type = t1;
4458                     return e;
4459                 }
4460                 else if (t1.isimaginary())
4461                 {
4462                     Type t3;
4463                     switch (t1.ty)
4464                     {
4465                     case Timaginary32:
4466                         t3 = Type.tfloat32;
4467                         break;
4468 
4469                     case Timaginary64:
4470                         t3 = Type.tfloat64;
4471                         break;
4472 
4473                     case Timaginary80:
4474                         t3 = Type.tfloat80;
4475                         break;
4476 
4477                     default:
4478                         assert(0);
4479                     }
4480                     e2 = e2.castTo(sc, t3);
4481                     Expression e = new AssignExp(loc, e1, e2);
4482                     e.type = t1;
4483                     return e;
4484                 }
4485             }
4486         }
4487         else if (op == TOK.modAssign)
4488         {
4489             if (t2.iscomplex())
4490             {
4491                 error("cannot perform modulo complex arithmetic");
4492                 return ErrorExp.get();
4493             }
4494         }
4495         return this;
4496     }
4497 
4498     extern (D) final bool checkIntegralBin()
4499     {
4500         bool r1 = e1.checkIntegral();
4501         bool r2 = e2.checkIntegral();
4502         return (r1 || r2);
4503     }
4504 
4505     extern (D) final bool checkArithmeticBin()
4506     {
4507         bool r1 = e1.checkArithmetic();
4508         bool r2 = e2.checkArithmetic();
4509         return (r1 || r2);
4510     }
4511 
4512     extern (D) final bool checkSharedAccessBin(Scope* sc)
4513     {
4514         const r1 = e1.checkSharedAccess(sc);
4515         const r2 = e2.checkSharedAccess(sc);
4516         return (r1 || r2);
4517     }
4518 
4519     /*********************
4520      * Mark the operands as will never be dereferenced,
4521      * which is useful info for @safe checks.
4522      * Do before semantic() on operands rewrites them.
4523      */
4524     final void setNoderefOperands()
4525     {
4526         if (auto edi = e1.isDotIdExp())
4527             edi.noderef = true;
4528         if (auto edi = e2.isDotIdExp())
4529             edi.noderef = true;
4530 
4531     }
4532 
4533     final Expression reorderSettingAAElem(Scope* sc)
4534     {
4535         BinExp be = this;
4536 
4537         auto ie = be.e1.isIndexExp();
4538         if (!ie)
4539             return be;
4540         if (ie.e1.type.toBasetype().ty != Taarray)
4541             return be;
4542 
4543         /* Fix evaluation order of setting AA element
4544          * https://issues.dlang.org/show_bug.cgi?id=3825
4545          * Rewrite:
4546          *     aa[k1][k2][k3] op= val;
4547          * as:
4548          *     auto ref __aatmp = aa;
4549          *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
4550          *     auto ref __aaval = val;
4551          *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
4552          */
4553 
4554         Expression e0;
4555         while (1)
4556         {
4557             Expression de;
4558             ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
4559             e0 = Expression.combine(de, e0);
4560 
4561             auto ie1 = ie.e1.isIndexExp();
4562             if (!ie1 ||
4563                 ie1.e1.type.toBasetype().ty != Taarray)
4564             {
4565                 break;
4566             }
4567             ie = ie1;
4568         }
4569         assert(ie.e1.type.toBasetype().ty == Taarray);
4570 
4571         Expression de;
4572         ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
4573         e0 = Expression.combine(de, e0);
4574 
4575         be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
4576 
4577         //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
4578         return Expression.combine(e0, be);
4579     }
4580 
4581     override void accept(Visitor v)
4582     {
4583         v.visit(this);
4584     }
4585 }
4586 
4587 /***********************************************************
4588  */
4589 extern (C++) class BinAssignExp : BinExp
4590 {
4591     extern (D) this(const ref Loc loc, TOK op, int size, Expression e1, Expression e2)
4592     {
4593         super(loc, op, size, e1, e2);
4594     }
4595 
4596     override final bool isLvalue()
4597     {
4598         return true;
4599     }
4600 
4601     override final Expression toLvalue(Scope* sc, Expression ex)
4602     {
4603         // Lvalue-ness will be handled in glue layer.
4604         return this;
4605     }
4606 
4607     override final Expression modifiableLvalue(Scope* sc, Expression e)
4608     {
4609         // should check e1.checkModifiable() ?
4610         return toLvalue(sc, this);
4611     }
4612 
4613     override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
4614     {
4615         return this;
4616     }
4617 
4618     override void accept(Visitor v)
4619     {
4620         v.visit(this);
4621     }
4622 }
4623 
4624 /***********************************************************
4625  * https://dlang.org/spec/expression.html#mixin_expressions
4626  */
4627 extern (C++) final class MixinExp : Expression
4628 {
4629     Expressions* exps;
4630 
4631     extern (D) this(const ref Loc loc, Expressions* exps)
4632     {
4633         super(loc, TOK.mixin_, __traits(classInstanceSize, MixinExp));
4634         this.exps = exps;
4635     }
4636 
4637     override MixinExp syntaxCopy()
4638     {
4639         return new MixinExp(loc, arraySyntaxCopy(exps));
4640     }
4641 
4642     override bool equals(const RootObject o) const
4643     {
4644         if (this == o)
4645             return true;
4646         auto e = o.isExpression();
4647         if (!e)
4648             return false;
4649         if (auto ce = e.isMixinExp())
4650         {
4651             if (exps.dim != ce.exps.dim)
4652                 return false;
4653             foreach (i, e1; *exps)
4654             {
4655                 auto e2 = (*ce.exps)[i];
4656                 if (e1 != e2 && (!e1 || !e2 || !e1.equals(e2)))
4657                     return false;
4658             }
4659             return true;
4660         }
4661         return false;
4662     }
4663 
4664     override void accept(Visitor v)
4665     {
4666         v.visit(this);
4667     }
4668 }
4669 
4670 /***********************************************************
4671  */
4672 extern (C++) final class ImportExp : UnaExp
4673 {
4674     extern (D) this(const ref Loc loc, Expression e)
4675     {
4676         super(loc, TOK.import_, __traits(classInstanceSize, ImportExp), e);
4677     }
4678 
4679     override void accept(Visitor v)
4680     {
4681         v.visit(this);
4682     }
4683 }
4684 
4685 /***********************************************************
4686  * https://dlang.org/spec/expression.html#assert_expressions
4687  */
4688 extern (C++) final class AssertExp : UnaExp
4689 {
4690     Expression msg;
4691 
4692     extern (D) this(const ref Loc loc, Expression e, Expression msg = null)
4693     {
4694         super(loc, TOK.assert_, __traits(classInstanceSize, AssertExp), e);
4695         this.msg = msg;
4696     }
4697 
4698     override AssertExp syntaxCopy()
4699     {
4700         return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4701     }
4702 
4703     override void accept(Visitor v)
4704     {
4705         v.visit(this);
4706     }
4707 }
4708 
4709 /***********************************************************
4710  */
4711 extern (C++) final class DotIdExp : UnaExp
4712 {
4713     Identifier ident;
4714     bool noderef;       // true if the result of the expression will never be dereferenced
4715     bool wantsym;       // do not replace Symbol with its initializer during semantic()
4716 
4717     extern (D) this(const ref Loc loc, Expression e, Identifier ident)
4718     {
4719         super(loc, TOK.dotIdentifier, __traits(classInstanceSize, DotIdExp), e);
4720         this.ident = ident;
4721     }
4722 
4723     static DotIdExp create(Loc loc, Expression e, Identifier ident)
4724     {
4725         return new DotIdExp(loc, e, ident);
4726     }
4727 
4728     override void accept(Visitor v)
4729     {
4730         v.visit(this);
4731     }
4732 }
4733 
4734 /***********************************************************
4735  * Mainly just a placeholder
4736  */
4737 extern (C++) final class DotTemplateExp : UnaExp
4738 {
4739     TemplateDeclaration td;
4740 
4741     extern (D) this(const ref Loc loc, Expression e, TemplateDeclaration td)
4742     {
4743         super(loc, TOK.dotTemplateDeclaration, __traits(classInstanceSize, DotTemplateExp), e);
4744         this.td = td;
4745     }
4746 
4747     override void accept(Visitor v)
4748     {
4749         v.visit(this);
4750     }
4751 }
4752 
4753 /***********************************************************
4754  */
4755 extern (C++) final class DotVarExp : UnaExp
4756 {
4757     Declaration var;
4758     bool hasOverloads;
4759 
4760     extern (D) this(const ref Loc loc, Expression e, Declaration var, bool hasOverloads = true)
4761     {
4762         if (var.isVarDeclaration())
4763             hasOverloads = false;
4764 
4765         super(loc, TOK.dotVariable, __traits(classInstanceSize, DotVarExp), e);
4766         //printf("DotVarExp()\n");
4767         this.var = var;
4768         this.hasOverloads = hasOverloads;
4769     }
4770 
4771     override Modifiable checkModifiable(Scope* sc, int flag)
4772     {
4773         //printf("DotVarExp::checkModifiable %s %s\n", toChars(), type.toChars());
4774         if (checkUnsafeAccess(sc, this, false, !flag))
4775             return Modifiable.initialization;
4776 
4777         if (e1.op == TOK.this_)
4778             return var.checkModify(loc, sc, e1, flag);
4779 
4780         /* https://issues.dlang.org/show_bug.cgi?id=12764
4781          * If inside a constructor and an expression of type `this.field.var`
4782          * is encountered, where `field` is a struct declaration with
4783          * default construction disabled, we must make sure that
4784          * assigning to `var` does not imply that `field` was initialized
4785          */
4786         if (sc.func && sc.func.isCtorDeclaration())
4787         {
4788             // if inside a constructor scope and e1 of this DotVarExp
4789             // is a DotVarExp, then check if e1.e1 is a `this` identifier
4790             if (auto dve = e1.isDotVarExp())
4791             {
4792                 if (dve.e1.op == TOK.this_)
4793                 {
4794                     scope v = dve.var.isVarDeclaration();
4795                     /* if v is a struct member field with no initializer, no default construction
4796                      * and v wasn't intialized before
4797                      */
4798                     if (v && v.isField() && !v._init && !v.ctorinit)
4799                     {
4800                         if (auto ts = v.type.isTypeStruct())
4801                         {
4802                             if (ts.sym.noDefaultCtor)
4803                             {
4804                                 /* checkModify will consider that this is an initialization
4805                                  * of v while it is actually an assignment of a field of v
4806                                  */
4807                                 scope modifyLevel = v.checkModify(loc, sc, dve.e1, flag);
4808                                 // reflect that assigning a field of v is not initialization of v
4809                                 v.ctorinit = false;
4810                                 if (modifyLevel == Modifiable.initialization)
4811                                     return Modifiable.yes;
4812                                 return modifyLevel;
4813                             }
4814                         }
4815                     }
4816                 }
4817             }
4818         }
4819 
4820         //printf("\te1 = %s\n", e1.toChars());
4821         return e1.checkModifiable(sc, flag);
4822     }
4823 
4824     override bool isLvalue()
4825     {
4826         if (e1.op != TOK.structLiteral)
4827             return true;
4828         auto vd = var.isVarDeclaration();
4829         return !(vd && vd.isField());
4830     }
4831 
4832     override Expression toLvalue(Scope* sc, Expression e)
4833     {
4834         //printf("DotVarExp::toLvalue(%s)\n", toChars());
4835         if (!isLvalue())
4836             return Expression.toLvalue(sc, e);
4837         if (e1.op == TOK.this_ && sc.ctorflow.fieldinit.length && !(sc.ctorflow.callSuper & CSX.any_ctor))
4838         {
4839             if (VarDeclaration vd = var.isVarDeclaration())
4840             {
4841                 auto ad = vd.isMember2();
4842                 if (ad && ad.fields.dim == sc.ctorflow.fieldinit.length)
4843                 {
4844                     foreach (i, f; ad.fields)
4845                     {
4846                         if (f == vd)
4847                         {
4848                             if (!(sc.ctorflow.fieldinit[i].csx & CSX.this_ctor))
4849                             {
4850                                 /* If the address of vd is taken, assume it is thereby initialized
4851                                  * https://issues.dlang.org/show_bug.cgi?id=15869
4852                                  */
4853                                 modifyFieldVar(loc, sc, vd, e1);
4854                             }
4855                             break;
4856                         }
4857                     }
4858                 }
4859             }
4860         }
4861         return this;
4862     }
4863 
4864     override Expression modifiableLvalue(Scope* sc, Expression e)
4865     {
4866         version (none)
4867         {
4868             printf("DotVarExp::modifiableLvalue(%s)\n", toChars());
4869             printf("e1.type = %s\n", e1.type.toChars());
4870             printf("var.type = %s\n", var.type.toChars());
4871         }
4872 
4873         return Expression.modifiableLvalue(sc, e);
4874     }
4875 
4876     override void accept(Visitor v)
4877     {
4878         v.visit(this);
4879     }
4880 }
4881 
4882 /***********************************************************
4883  * foo.bar!(args)
4884  */
4885 extern (C++) final class DotTemplateInstanceExp : UnaExp
4886 {
4887     TemplateInstance ti;
4888 
4889     extern (D) this(const ref Loc loc, Expression e, Identifier name, Objects* tiargs)
4890     {
4891         super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4892         //printf("DotTemplateInstanceExp()\n");
4893         this.ti = new TemplateInstance(loc, name, tiargs);
4894     }
4895 
4896     extern (D) this(const ref Loc loc, Expression e, TemplateInstance ti)
4897     {
4898         super(loc, TOK.dotTemplateInstance, __traits(classInstanceSize, DotTemplateInstanceExp), e);
4899         this.ti = ti;
4900     }
4901 
4902     override DotTemplateInstanceExp syntaxCopy()
4903     {
4904         return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4905     }
4906 
4907     bool findTempDecl(Scope* sc)
4908     {
4909         static if (LOGSEMANTIC)
4910         {
4911             printf("DotTemplateInstanceExp::findTempDecl('%s')\n", toChars());
4912         }
4913         if (ti.tempdecl)
4914             return true;
4915 
4916         Expression e = new DotIdExp(loc, e1, ti.name);
4917         e = e.expressionSemantic(sc);
4918         if (e.op == TOK.dot)
4919             e = (cast(DotExp)e).e2;
4920 
4921         Dsymbol s = null;
4922         switch (e.op)
4923         {
4924         case TOK.overloadSet:
4925             s = (cast(OverExp)e).vars;
4926             break;
4927 
4928         case TOK.dotTemplateDeclaration:
4929             s = (cast(DotTemplateExp)e).td;
4930             break;
4931 
4932         case TOK.scope_:
4933             s = (cast(ScopeExp)e).sds;
4934             break;
4935 
4936         case TOK.dotVariable:
4937             s = (cast(DotVarExp)e).var;
4938             break;
4939 
4940         case TOK.variable:
4941             s = (cast(VarExp)e).var;
4942             break;
4943 
4944         default:
4945             return false;
4946         }
4947         return ti.updateTempDecl(sc, s);
4948     }
4949 
4950     override void accept(Visitor v)
4951     {
4952         v.visit(this);
4953     }
4954 }
4955 
4956 /***********************************************************
4957  */
4958 extern (C++) final class DelegateExp : UnaExp
4959 {
4960     FuncDeclaration func;
4961     bool hasOverloads;
4962     VarDeclaration vthis2;  // container for multi-context
4963 
4964     extern (D) this(const ref Loc loc, Expression e, FuncDeclaration f, bool hasOverloads = true, VarDeclaration vthis2 = null)
4965     {
4966         super(loc, TOK.delegate_, __traits(classInstanceSize, DelegateExp), e);
4967         this.func = f;
4968         this.hasOverloads = hasOverloads;
4969         this.vthis2 = vthis2;
4970     }
4971 
4972     override void accept(Visitor v)
4973     {
4974         v.visit(this);
4975     }
4976 }
4977 
4978 /***********************************************************
4979  */
4980 extern (C++) final class DotTypeExp : UnaExp
4981 {
4982     Dsymbol sym;        // symbol that represents a type
4983 
4984     extern (D) this(const ref Loc loc, Expression e, Dsymbol s)
4985     {
4986         super(loc, TOK.dotType, __traits(classInstanceSize, DotTypeExp), e);
4987         this.sym = s;
4988     }
4989 
4990     override void accept(Visitor v)
4991     {
4992         v.visit(this);
4993     }
4994 }
4995 
4996 /***********************************************************
4997  */
4998 extern (C++) final class CallExp : UnaExp
4999 {
5000     Expressions* arguments; // function arguments
5001     FuncDeclaration f;      // symbol to call
5002     bool directcall;        // true if a virtual call is devirtualized
5003     bool inDebugStatement;  /// true if this was in a debug statement
5004     bool ignoreAttributes;  /// don't enforce attributes (e.g. call @gc function in @nogc code)
5005     VarDeclaration vthis2;  // container for multi-context
5006 
5007     extern (D) this(const ref Loc loc, Expression e, Expressions* exps)
5008     {
5009         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
5010         this.arguments = exps;
5011     }
5012 
5013     extern (D) this(const ref Loc loc, Expression e)
5014     {
5015         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
5016     }
5017 
5018     extern (D) this(const ref Loc loc, Expression e, Expression earg1)
5019     {
5020         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
5021         this.arguments = new Expressions();
5022         if (earg1)
5023             this.arguments.push(earg1);
5024     }
5025 
5026     extern (D) this(const ref Loc loc, Expression e, Expression earg1, Expression earg2)
5027     {
5028         super(loc, TOK.call, __traits(classInstanceSize, CallExp), e);
5029         auto arguments = new Expressions(2);
5030         (*arguments)[0] = earg1;
5031         (*arguments)[1] = earg2;
5032         this.arguments = arguments;
5033     }
5034 
5035     /***********************************************************
5036     * Instatiates a new function call expression
5037     * Params:
5038     *       loc   = location
5039     *       fd    = the declaration of the function to call
5040     *       earg1 = the function argument
5041     */
5042     extern(D) this(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5043     {
5044         this(loc, new VarExp(loc, fd, false), earg1);
5045         this.f = fd;
5046     }
5047 
5048     static CallExp create(Loc loc, Expression e, Expressions* exps)
5049     {
5050         return new CallExp(loc, e, exps);
5051     }
5052 
5053     static CallExp create(Loc loc, Expression e)
5054     {
5055         return new CallExp(loc, e);
5056     }
5057 
5058     static CallExp create(Loc loc, Expression e, Expression earg1)
5059     {
5060         return new CallExp(loc, e, earg1);
5061     }
5062 
5063     /***********************************************************
5064     * Creates a new function call expression
5065     * Params:
5066     *       loc   = location
5067     *       fd    = the declaration of the function to call
5068     *       earg1 = the function argument
5069     */
5070     static CallExp create(Loc loc, FuncDeclaration fd, Expression earg1)
5071     {
5072         return new CallExp(loc, fd, earg1);
5073     }
5074 
5075     override CallExp syntaxCopy()
5076     {
5077         return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5078     }
5079 
5080     override bool isLvalue()
5081     {
5082         Type tb = e1.type.toBasetype();
5083         if (tb.ty == Tdelegate || tb.ty == Tpointer)
5084             tb = tb.nextOf();
5085         auto tf = tb.isTypeFunction();
5086         if (tf && tf.isref)
5087         {
5088             if (auto dve = e1.isDotVarExp())
5089                 if (dve.var.isCtorDeclaration())
5090                     return false;
5091             return true; // function returns a reference
5092         }
5093         return false;
5094     }
5095 
5096     override Expression toLvalue(Scope* sc, Expression e)
5097     {
5098         if (isLvalue())
5099             return this;
5100         return Expression.toLvalue(sc, e);
5101     }
5102 
5103     override Expression addDtorHook(Scope* sc)
5104     {
5105         /* Only need to add dtor hook if it's a type that needs destruction.
5106          * Use same logic as VarDeclaration::callScopeDtor()
5107          */
5108 
5109         if (auto tf = e1.type.isTypeFunction())
5110         {
5111             if (tf.isref)
5112                 return this;
5113         }
5114 
5115         Type tv = type.baseElemOf();
5116         if (auto ts = tv.isTypeStruct())
5117         {
5118             StructDeclaration sd = ts.sym;
5119             if (sd.dtor)
5120             {
5121                 /* Type needs destruction, so declare a tmp
5122                  * which the back end will recognize and call dtor on
5123                  */
5124                 auto tmp = copyToTemp(0, "__tmpfordtor", this);
5125                 auto de = new DeclarationExp(loc, tmp);
5126                 auto ve = new VarExp(loc, tmp);
5127                 Expression e = new CommaExp(loc, de, ve);
5128                 e = e.expressionSemantic(sc);
5129                 return e;
5130             }
5131         }
5132         return this;
5133     }
5134 
5135     override void accept(Visitor v)
5136     {
5137         v.visit(this);
5138     }
5139 }
5140 
5141 FuncDeclaration isFuncAddress(Expression e, bool* hasOverloads = null)
5142 {
5143     if (auto ae = e.isAddrExp())
5144     {
5145         auto ae1 = ae.e1;
5146         if (auto ve = ae1.isVarExp())
5147         {
5148             if (hasOverloads)
5149                 *hasOverloads = ve.hasOverloads;
5150             return ve.var.isFuncDeclaration();
5151         }
5152         if (auto dve = ae1.isDotVarExp())
5153         {
5154             if (hasOverloads)
5155                 *hasOverloads = dve.hasOverloads;
5156             return dve.var.isFuncDeclaration();
5157         }
5158     }
5159     else
5160     {
5161         if (auto soe = e.isSymOffExp())
5162         {
5163             if (hasOverloads)
5164                 *hasOverloads = soe.hasOverloads;
5165             return soe.var.isFuncDeclaration();
5166         }
5167         if (auto dge = e.isDelegateExp())
5168         {
5169             if (hasOverloads)
5170                 *hasOverloads = dge.hasOverloads;
5171             return dge.func.isFuncDeclaration();
5172         }
5173     }
5174     return null;
5175 }
5176 
5177 /***********************************************************
5178  */
5179 extern (C++) final class AddrExp : UnaExp
5180 {
5181     extern (D) this(const ref Loc loc, Expression e)
5182     {
5183         super(loc, TOK.address, __traits(classInstanceSize, AddrExp), e);
5184     }
5185 
5186     extern (D) this(const ref Loc loc, Expression e, Type t)
5187     {
5188         this(loc, e);
5189         type = t;
5190     }
5191 
5192     override void accept(Visitor v)
5193     {
5194         v.visit(this);
5195     }
5196 }
5197 
5198 /***********************************************************
5199  */
5200 extern (C++) final class PtrExp : UnaExp
5201 {
5202     extern (D) this(const ref Loc loc, Expression e)
5203     {
5204         super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
5205         //if (e.type)
5206         //  type = ((TypePointer *)e.type).next;
5207     }
5208 
5209     extern (D) this(const ref Loc loc, Expression e, Type t)
5210     {
5211         super(loc, TOK.star, __traits(classInstanceSize, PtrExp), e);
5212         type = t;
5213     }
5214 
5215     override Modifiable checkModifiable(Scope* sc, int flag)
5216     {
5217         if (auto se = e1.isSymOffExp())
5218         {
5219             return se.var.checkModify(loc, sc, null, flag);
5220         }
5221         else if (auto ae = e1.isAddrExp())
5222         {
5223             return ae.e1.checkModifiable(sc, flag);
5224         }
5225         return Modifiable.yes;
5226     }
5227 
5228     override bool isLvalue()
5229     {
5230         return true;
5231     }
5232 
5233     override Expression toLvalue(Scope* sc, Expression e)
5234     {
5235         return this;
5236     }
5237 
5238     override Expression modifiableLvalue(Scope* sc, Expression e)
5239     {
5240         //printf("PtrExp::modifiableLvalue() %s, type %s\n", toChars(), type.toChars());
5241         return Expression.modifiableLvalue(sc, e);
5242     }
5243 
5244     override void accept(Visitor v)
5245     {
5246         v.visit(this);
5247     }
5248 }
5249 
5250 /***********************************************************
5251  */
5252 extern (C++) final class NegExp : UnaExp
5253 {
5254     extern (D) this(const ref Loc loc, Expression e)
5255     {
5256         super(loc, TOK.negate, __traits(classInstanceSize, NegExp), e);
5257     }
5258 
5259     override void accept(Visitor v)
5260     {
5261         v.visit(this);
5262     }
5263 }
5264 
5265 /***********************************************************
5266  */
5267 extern (C++) final class UAddExp : UnaExp
5268 {
5269     extern (D) this(const ref Loc loc, Expression e)
5270     {
5271         super(loc, TOK.uadd, __traits(classInstanceSize, UAddExp), e);
5272     }
5273 
5274     override void accept(Visitor v)
5275     {
5276         v.visit(this);
5277     }
5278 }
5279 
5280 /***********************************************************
5281  */
5282 extern (C++) final class ComExp : UnaExp
5283 {
5284     extern (D) this(const ref Loc loc, Expression e)
5285     {
5286         super(loc, TOK.tilde, __traits(classInstanceSize, ComExp), e);
5287     }
5288 
5289     override void accept(Visitor v)
5290     {
5291         v.visit(this);
5292     }
5293 }
5294 
5295 /***********************************************************
5296  */
5297 extern (C++) final class NotExp : UnaExp
5298 {
5299     extern (D) this(const ref Loc loc, Expression e)
5300     {
5301         super(loc, TOK.not, __traits(classInstanceSize, NotExp), e);
5302     }
5303 
5304     override void accept(Visitor v)
5305     {
5306         v.visit(this);
5307     }
5308 }
5309 
5310 /***********************************************************
5311  */
5312 extern (C++) final class DeleteExp : UnaExp
5313 {
5314     bool isRAII;        // true if called automatically as a result of scoped destruction
5315 
5316     extern (D) this(const ref Loc loc, Expression e, bool isRAII)
5317     {
5318         super(loc, TOK.delete_, __traits(classInstanceSize, DeleteExp), e);
5319         this.isRAII = isRAII;
5320     }
5321 
5322     override Expression toBoolean(Scope* sc)
5323     {
5324         error("`delete` does not give a boolean result");
5325         return ErrorExp.get();
5326     }
5327 
5328     override void accept(Visitor v)
5329     {
5330         v.visit(this);
5331     }
5332 }
5333 
5334 /***********************************************************
5335  * Possible to cast to one type while painting to another type
5336  */
5337 extern (C++) final class CastExp : UnaExp
5338 {
5339     Type to;                    // type to cast to
5340     ubyte mod = cast(ubyte)~0;  // MODxxxxx
5341 
5342     extern (D) this(const ref Loc loc, Expression e, Type t)
5343     {
5344         super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
5345         this.to = t;
5346     }
5347 
5348     /* For cast(const) and cast(immutable)
5349      */
5350     extern (D) this(const ref Loc loc, Expression e, ubyte mod)
5351     {
5352         super(loc, TOK.cast_, __traits(classInstanceSize, CastExp), e);
5353         this.mod = mod;
5354     }
5355 
5356     override CastExp syntaxCopy()
5357     {
5358         return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5359     }
5360 
5361     override bool isLvalue()
5362     {
5363         //printf("e1.type = %s, to.type = %s\n", e1.type.toChars(), to.toChars());
5364         if (!e1.isLvalue())
5365             return false;
5366         return (to.ty == Tsarray && (e1.type.ty == Tvector || e1.type.ty == Tsarray)) ||
5367             e1.type.mutableOf().unSharedOf().equals(to.mutableOf().unSharedOf());
5368     }
5369 
5370     override Expression toLvalue(Scope* sc, Expression e)
5371     {
5372         if (isLvalue())
5373             return this;
5374         return Expression.toLvalue(sc, e);
5375     }
5376 
5377     override Expression addDtorHook(Scope* sc)
5378     {
5379         if (to.toBasetype().ty == Tvoid)        // look past the cast(void)
5380             e1 = e1.addDtorHook(sc);
5381         return this;
5382     }
5383 
5384     override void accept(Visitor v)
5385     {
5386         v.visit(this);
5387     }
5388 }
5389 
5390 /***********************************************************
5391  */
5392 extern (C++) final class VectorExp : UnaExp
5393 {
5394     TypeVector to;      // the target vector type before semantic()
5395     uint dim = ~0;      // number of elements in the vector
5396     OwnedBy ownedByCtfe = OwnedBy.code;
5397 
5398     extern (D) this(const ref Loc loc, Expression e, Type t)
5399     {
5400         super(loc, TOK.vector, __traits(classInstanceSize, VectorExp), e);
5401         assert(t.ty == Tvector);
5402         to = cast(TypeVector)t;
5403     }
5404 
5405     static VectorExp create(Loc loc, Expression e, Type t)
5406     {
5407         return new VectorExp(loc, e, t);
5408     }
5409 
5410     // Same as create, but doesn't allocate memory.
5411     static void emplace(UnionExp* pue, Loc loc, Expression e, Type type)
5412     {
5413         emplaceExp!(VectorExp)(pue, loc, e, type);
5414     }
5415 
5416     override VectorExp syntaxCopy()
5417     {
5418         return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5419     }
5420 
5421     override void accept(Visitor v)
5422     {
5423         v.visit(this);
5424     }
5425 }
5426 
5427 /***********************************************************
5428  * e1.array property for vectors.
5429  *
5430  * https://dlang.org/spec/simd.html#properties
5431  */
5432 extern (C++) final class VectorArrayExp : UnaExp
5433 {
5434     extern (D) this(const ref Loc loc, Expression e1)
5435     {
5436         super(loc, TOK.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
5437     }
5438 
5439     override bool isLvalue()
5440     {
5441         return e1.isLvalue();
5442     }
5443 
5444     override Expression toLvalue(Scope* sc, Expression e)
5445     {
5446         e1 = e1.toLvalue(sc, e);
5447         return this;
5448     }
5449 
5450     override void accept(Visitor v)
5451     {
5452         v.visit(this);
5453     }
5454 }
5455 
5456 /***********************************************************
5457  * e1 [lwr .. upr]
5458  *
5459  * http://dlang.org/spec/expression.html#slice_expressions
5460  */
5461 extern (C++) final class SliceExp : UnaExp
5462 {
5463     Expression upr;             // null if implicit 0
5464     Expression lwr;             // null if implicit [length - 1]
5465 
5466     VarDeclaration lengthVar;
5467     bool upperIsInBounds;       // true if upr <= e1.length
5468     bool lowerIsLessThanUpper;  // true if lwr <= upr
5469     bool arrayop;               // an array operation, rather than a slice
5470 
5471     /************************************************************/
5472     extern (D) this(const ref Loc loc, Expression e1, IntervalExp ie)
5473     {
5474         super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
5475         this.upr = ie ? ie.upr : null;
5476         this.lwr = ie ? ie.lwr : null;
5477     }
5478 
5479     extern (D) this(const ref Loc loc, Expression e1, Expression lwr, Expression upr)
5480     {
5481         super(loc, TOK.slice, __traits(classInstanceSize, SliceExp), e1);
5482         this.upr = upr;
5483         this.lwr = lwr;
5484     }
5485 
5486     override SliceExp syntaxCopy()
5487     {
5488         auto se = new SliceExp(loc, e1.syntaxCopy(), lwr ? lwr.syntaxCopy() : null, upr ? upr.syntaxCopy() : null);
5489         se.lengthVar = this.lengthVar; // bug7871
5490         return se;
5491     }
5492 
5493     override Modifiable checkModifiable(Scope* sc, int flag)
5494     {
5495         //printf("SliceExp::checkModifiable %s\n", toChars());
5496         if (e1.type.ty == Tsarray || (e1.op == TOK.index && e1.type.ty != Tarray) || e1.op == TOK.slice)
5497         {
5498             return e1.checkModifiable(sc, flag);
5499         }
5500         return Modifiable.yes;
5501     }
5502 
5503     override bool isLvalue()
5504     {
5505         /* slice expression is rvalue in default, but
5506          * conversion to reference of static array is only allowed.
5507          */
5508         return (type && type.toBasetype().ty == Tsarray);
5509     }
5510 
5511     override Expression toLvalue(Scope* sc, Expression e)
5512     {
5513         //printf("SliceExp::toLvalue(%s) type = %s\n", toChars(), type ? type.toChars() : NULL);
5514         return (type && type.toBasetype().ty == Tsarray) ? this : Expression.toLvalue(sc, e);
5515     }
5516 
5517     override Expression modifiableLvalue(Scope* sc, Expression e)
5518     {
5519         error("slice expression `%s` is not a modifiable lvalue", toChars());
5520         return this;
5521     }
5522 
5523     override bool isBool(bool result)
5524     {
5525         return e1.isBool(result);
5526     }
5527 
5528     override void accept(Visitor v)
5529     {
5530         v.visit(this);
5531     }
5532 }
5533 
5534 /***********************************************************
5535  */
5536 extern (C++) final class ArrayLengthExp : UnaExp
5537 {
5538     extern (D) this(const ref Loc loc, Expression e1)
5539     {
5540         super(loc, TOK.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
5541     }
5542 
5543     override void accept(Visitor v)
5544     {
5545         v.visit(this);
5546     }
5547 }
5548 
5549 /***********************************************************
5550  * e1 [ a0, a1, a2, a3 ,... ]
5551  *
5552  * http://dlang.org/spec/expression.html#index_expressions
5553  */
5554 extern (C++) final class ArrayExp : UnaExp
5555 {
5556     Expressions* arguments;     // Array of Expression's a0..an
5557 
5558     size_t currentDimension;    // for opDollar
5559     VarDeclaration lengthVar;
5560 
5561     extern (D) this(const ref Loc loc, Expression e1, Expression index = null)
5562     {
5563         super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
5564         arguments = new Expressions();
5565         if (index)
5566             arguments.push(index);
5567     }
5568 
5569     extern (D) this(const ref Loc loc, Expression e1, Expressions* args)
5570     {
5571         super(loc, TOK.array, __traits(classInstanceSize, ArrayExp), e1);
5572         arguments = args;
5573     }
5574 
5575     override ArrayExp syntaxCopy()
5576     {
5577         auto ae = new ArrayExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5578         ae.lengthVar = this.lengthVar; // bug7871
5579         return ae;
5580     }
5581 
5582     override bool isLvalue()
5583     {
5584         if (type && type.toBasetype().ty == Tvoid)
5585             return false;
5586         return true;
5587     }
5588 
5589     override Expression toLvalue(Scope* sc, Expression e)
5590     {
5591         if (type && type.toBasetype().ty == Tvoid)
5592             error("`void`s have no value");
5593         return this;
5594     }
5595 
5596     override void accept(Visitor v)
5597     {
5598         v.visit(this);
5599     }
5600 }
5601 
5602 /***********************************************************
5603  */
5604 extern (C++) final class DotExp : BinExp
5605 {
5606     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5607     {
5608         super(loc, TOK.dot, __traits(classInstanceSize, DotExp), e1, e2);
5609     }
5610 
5611     override void accept(Visitor v)
5612     {
5613         v.visit(this);
5614     }
5615 }
5616 
5617 /***********************************************************
5618  */
5619 extern (C++) final class CommaExp : BinExp
5620 {
5621     /// This is needed because AssignExp rewrites CommaExp, hence it needs
5622     /// to trigger the deprecation.
5623     const bool isGenerated;
5624 
5625     /// Temporary variable to enable / disable deprecation of comma expression
5626     /// depending on the context.
5627     /// Since most constructor calls are rewritting, the only place where
5628     /// false will be passed will be from the parser.
5629     bool allowCommaExp;
5630 
5631 
5632     extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool generated = true)
5633     {
5634         super(loc, TOK.comma, __traits(classInstanceSize, CommaExp), e1, e2);
5635         allowCommaExp = isGenerated = generated;
5636     }
5637 
5638     override Modifiable checkModifiable(Scope* sc, int flag)
5639     {
5640         return e2.checkModifiable(sc, flag);
5641     }
5642 
5643     override bool isLvalue()
5644     {
5645         return e2.isLvalue();
5646     }
5647 
5648     override Expression toLvalue(Scope* sc, Expression e)
5649     {
5650         e2 = e2.toLvalue(sc, null);
5651         return this;
5652     }
5653 
5654     override Expression modifiableLvalue(Scope* sc, Expression e)
5655     {
5656         e2 = e2.modifiableLvalue(sc, e);
5657         return this;
5658     }
5659 
5660     override bool isBool(bool result)
5661     {
5662         return e2.isBool(result);
5663     }
5664 
5665     override Expression toBoolean(Scope* sc)
5666     {
5667         auto ex2 = e2.toBoolean(sc);
5668         if (ex2.op == TOK.error)
5669             return ex2;
5670         e2 = ex2;
5671         type = e2.type;
5672         return this;
5673     }
5674 
5675     override Expression addDtorHook(Scope* sc)
5676     {
5677         e2 = e2.addDtorHook(sc);
5678         return this;
5679     }
5680 
5681     override void accept(Visitor v)
5682     {
5683         v.visit(this);
5684     }
5685 
5686     /**
5687      * If the argument is a CommaExp, set a flag to prevent deprecation messages
5688      *
5689      * It's impossible to know from CommaExp.semantic if the result will
5690      * be used, hence when there is a result (type != void), a deprecation
5691      * message is always emitted.
5692      * However, some construct can produce a result but won't use it
5693      * (ExpStatement and for loop increment).  Those should call this function
5694      * to prevent unwanted deprecations to be emitted.
5695      *
5696      * Params:
5697      *   exp = An expression that discards its result.
5698      *         If the argument is null or not a CommaExp, nothing happens.
5699      */
5700     static void allow(Expression exp)
5701     {
5702         if (exp)
5703             if (auto ce = exp.isCommaExp())
5704                 ce.allowCommaExp = true;
5705     }
5706 }
5707 
5708 /***********************************************************
5709  * Mainly just a placeholder
5710  */
5711 extern (C++) final class IntervalExp : Expression
5712 {
5713     Expression lwr;
5714     Expression upr;
5715 
5716     extern (D) this(const ref Loc loc, Expression lwr, Expression upr)
5717     {
5718         super(loc, TOK.interval, __traits(classInstanceSize, IntervalExp));
5719         this.lwr = lwr;
5720         this.upr = upr;
5721     }
5722 
5723     override Expression syntaxCopy()
5724     {
5725         return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5726     }
5727 
5728     override void accept(Visitor v)
5729     {
5730         v.visit(this);
5731     }
5732 }
5733 
5734 extern (C++) final class DelegatePtrExp : UnaExp
5735 {
5736     extern (D) this(const ref Loc loc, Expression e1)
5737     {
5738         super(loc, TOK.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
5739     }
5740 
5741     override bool isLvalue()
5742     {
5743         return e1.isLvalue();
5744     }
5745 
5746     override Expression toLvalue(Scope* sc, Expression e)
5747     {
5748         e1 = e1.toLvalue(sc, e);
5749         return this;
5750     }
5751 
5752     override Expression modifiableLvalue(Scope* sc, Expression e)
5753     {
5754         if (sc.func.setUnsafe())
5755         {
5756             error("cannot modify delegate pointer in `@safe` code `%s`", toChars());
5757             return ErrorExp.get();
5758         }
5759         return Expression.modifiableLvalue(sc, e);
5760     }
5761 
5762     override void accept(Visitor v)
5763     {
5764         v.visit(this);
5765     }
5766 }
5767 
5768 /***********************************************************
5769  */
5770 extern (C++) final class DelegateFuncptrExp : UnaExp
5771 {
5772     extern (D) this(const ref Loc loc, Expression e1)
5773     {
5774         super(loc, TOK.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
5775     }
5776 
5777     override bool isLvalue()
5778     {
5779         return e1.isLvalue();
5780     }
5781 
5782     override Expression toLvalue(Scope* sc, Expression e)
5783     {
5784         e1 = e1.toLvalue(sc, e);
5785         return this;
5786     }
5787 
5788     override Expression modifiableLvalue(Scope* sc, Expression e)
5789     {
5790         if (sc.func.setUnsafe())
5791         {
5792             error("cannot modify delegate function pointer in `@safe` code `%s`", toChars());
5793             return ErrorExp.get();
5794         }
5795         return Expression.modifiableLvalue(sc, e);
5796     }
5797 
5798     override void accept(Visitor v)
5799     {
5800         v.visit(this);
5801     }
5802 }
5803 
5804 /***********************************************************
5805  * e1 [ e2 ]
5806  */
5807 extern (C++) final class IndexExp : BinExp
5808 {
5809     VarDeclaration lengthVar;
5810     bool modifiable = false;    // assume it is an rvalue
5811     bool indexIsInBounds;       // true if 0 <= e2 && e2 <= e1.length - 1
5812 
5813     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5814     {
5815         super(loc, TOK.index, __traits(classInstanceSize, IndexExp), e1, e2);
5816         //printf("IndexExp::IndexExp('%s')\n", toChars());
5817     }
5818 
5819     override IndexExp syntaxCopy()
5820     {
5821         auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
5822         ie.lengthVar = this.lengthVar; // bug7871
5823         return ie;
5824     }
5825 
5826     override Modifiable checkModifiable(Scope* sc, int flag)
5827     {
5828         if (e1.type.ty == Tsarray ||
5829             e1.type.ty == Taarray ||
5830             (e1.op == TOK.index && e1.type.ty != Tarray) ||
5831             e1.op == TOK.slice)
5832         {
5833             return e1.checkModifiable(sc, flag);
5834         }
5835         return Modifiable.yes;
5836     }
5837 
5838     override bool isLvalue()
5839     {
5840         if (e1.op == TOK.assocArrayLiteral)
5841             return false;
5842         if (e1.type.ty == Tsarray ||
5843             (e1.op == TOK.index && e1.type.ty != Tarray))
5844         {
5845             return e1.isLvalue();
5846         }
5847         return true;
5848     }
5849 
5850     override Expression toLvalue(Scope* sc, Expression e)
5851     {
5852         if (isLvalue())
5853             return this;
5854         return Expression.toLvalue(sc, e);
5855     }
5856 
5857     override Expression modifiableLvalue(Scope* sc, Expression e)
5858     {
5859         //printf("IndexExp::modifiableLvalue(%s)\n", toChars());
5860         Expression ex = markSettingAAElem();
5861         if (ex.op == TOK.error)
5862             return ex;
5863 
5864         return Expression.modifiableLvalue(sc, e);
5865     }
5866 
5867     extern (D) Expression markSettingAAElem()
5868     {
5869         if (e1.type.toBasetype().ty == Taarray)
5870         {
5871             Type t2b = e2.type.toBasetype();
5872             if (t2b.ty == Tarray && t2b.nextOf().isMutable())
5873             {
5874                 error("associative arrays can only be assigned values with immutable keys, not `%s`", e2.type.toChars());
5875                 return ErrorExp.get();
5876             }
5877             modifiable = true;
5878 
5879             if (auto ie = e1.isIndexExp())
5880             {
5881                 Expression ex = ie.markSettingAAElem();
5882                 if (ex.op == TOK.error)
5883                     return ex;
5884                 assert(ex == e1);
5885             }
5886         }
5887         return this;
5888     }
5889 
5890     override void accept(Visitor v)
5891     {
5892         v.visit(this);
5893     }
5894 }
5895 
5896 /***********************************************************
5897  * For both i++ and i--
5898  */
5899 extern (C++) final class PostExp : BinExp
5900 {
5901     extern (D) this(TOK op, const ref Loc loc, Expression e)
5902     {
5903         super(loc, op, __traits(classInstanceSize, PostExp), e, IntegerExp.literal!1);
5904         assert(op == TOK.minusMinus || op == TOK.plusPlus);
5905     }
5906 
5907     override void accept(Visitor v)
5908     {
5909         v.visit(this);
5910     }
5911 }
5912 
5913 /***********************************************************
5914  * For both ++i and --i
5915  */
5916 extern (C++) final class PreExp : UnaExp
5917 {
5918     extern (D) this(TOK op, const ref Loc loc, Expression e)
5919     {
5920         super(loc, op, __traits(classInstanceSize, PreExp), e);
5921         assert(op == TOK.preMinusMinus || op == TOK.prePlusPlus);
5922     }
5923 
5924     override void accept(Visitor v)
5925     {
5926         v.visit(this);
5927     }
5928 }
5929 
5930 enum MemorySet
5931 {
5932     none            = 0,    // simple assignment
5933     blockAssign     = 1,    // setting the contents of an array
5934     referenceInit   = 2,    // setting the reference of STC.ref_ variable
5935 }
5936 
5937 /***********************************************************
5938  */
5939 extern (C++) class AssignExp : BinExp
5940 {
5941     MemorySet memset;
5942 
5943     /************************************************************/
5944     /* op can be TOK.assign, TOK.construct, or TOK.blit */
5945     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
5946     {
5947         super(loc, TOK.assign, __traits(classInstanceSize, AssignExp), e1, e2);
5948     }
5949 
5950     this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
5951     {
5952         super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
5953     }
5954 
5955     override final bool isLvalue()
5956     {
5957         // Array-op 'x[] = y[]' should make an rvalue.
5958         // Setting array length 'x.length = v' should make an rvalue.
5959         if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
5960         {
5961             return false;
5962         }
5963         return true;
5964     }
5965 
5966     override final Expression toLvalue(Scope* sc, Expression ex)
5967     {
5968         if (e1.op == TOK.slice || e1.op == TOK.arrayLength)
5969         {
5970             return Expression.toLvalue(sc, ex);
5971         }
5972 
5973         /* In front-end level, AssignExp should make an lvalue of e1.
5974          * Taking the address of e1 will be handled in low level layer,
5975          * so this function does nothing.
5976          */
5977         return this;
5978     }
5979 
5980     override final Expression toBoolean(Scope* sc)
5981     {
5982         // Things like:
5983         //  if (a = b) ...
5984         // are usually mistakes.
5985 
5986         error("assignment cannot be used as a condition, perhaps `==` was meant?");
5987         return ErrorExp.get();
5988     }
5989 
5990     override void accept(Visitor v)
5991     {
5992         v.visit(this);
5993     }
5994 }
5995 
5996 /***********************************************************
5997  */
5998 extern (C++) final class ConstructExp : AssignExp
5999 {
6000     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6001     {
6002         super(loc, TOK.construct, e1, e2);
6003     }
6004 
6005     // Internal use only. If `v` is a reference variable, the assignment
6006     // will become a reference initialization automatically.
6007     extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6008     {
6009         auto ve = new VarExp(loc, v);
6010         assert(v.type && ve.type);
6011 
6012         super(loc, TOK.construct, ve, e2);
6013 
6014         if (v.storage_class & (STC.ref_ | STC.out_))
6015             memset = MemorySet.referenceInit;
6016     }
6017 
6018     override void accept(Visitor v)
6019     {
6020         v.visit(this);
6021     }
6022 }
6023 
6024 /***********************************************************
6025  */
6026 extern (C++) final class BlitExp : AssignExp
6027 {
6028     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6029     {
6030         super(loc, TOK.blit, e1, e2);
6031     }
6032 
6033     // Internal use only. If `v` is a reference variable, the assinment
6034     // will become a reference rebinding automatically.
6035     extern (D) this(const ref Loc loc, VarDeclaration v, Expression e2)
6036     {
6037         auto ve = new VarExp(loc, v);
6038         assert(v.type && ve.type);
6039 
6040         super(loc, TOK.blit, ve, e2);
6041 
6042         if (v.storage_class & (STC.ref_ | STC.out_))
6043             memset = MemorySet.referenceInit;
6044     }
6045 
6046     override void accept(Visitor v)
6047     {
6048         v.visit(this);
6049     }
6050 }
6051 
6052 /***********************************************************
6053  */
6054 extern (C++) final class AddAssignExp : BinAssignExp
6055 {
6056     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6057     {
6058         super(loc, TOK.addAssign, __traits(classInstanceSize, AddAssignExp), e1, e2);
6059     }
6060 
6061     override void accept(Visitor v)
6062     {
6063         v.visit(this);
6064     }
6065 }
6066 
6067 /***********************************************************
6068  */
6069 extern (C++) final class MinAssignExp : BinAssignExp
6070 {
6071     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6072     {
6073         super(loc, TOK.minAssign, __traits(classInstanceSize, MinAssignExp), e1, e2);
6074     }
6075 
6076     override void accept(Visitor v)
6077     {
6078         v.visit(this);
6079     }
6080 }
6081 
6082 /***********************************************************
6083  */
6084 extern (C++) final class MulAssignExp : BinAssignExp
6085 {
6086     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6087     {
6088         super(loc, TOK.mulAssign, __traits(classInstanceSize, MulAssignExp), e1, e2);
6089     }
6090 
6091     override void accept(Visitor v)
6092     {
6093         v.visit(this);
6094     }
6095 }
6096 
6097 /***********************************************************
6098  */
6099 extern (C++) final class DivAssignExp : BinAssignExp
6100 {
6101     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6102     {
6103         super(loc, TOK.divAssign, __traits(classInstanceSize, DivAssignExp), e1, e2);
6104     }
6105 
6106     override void accept(Visitor v)
6107     {
6108         v.visit(this);
6109     }
6110 }
6111 
6112 /***********************************************************
6113  */
6114 extern (C++) final class ModAssignExp : BinAssignExp
6115 {
6116     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6117     {
6118         super(loc, TOK.modAssign, __traits(classInstanceSize, ModAssignExp), e1, e2);
6119     }
6120 
6121     override void accept(Visitor v)
6122     {
6123         v.visit(this);
6124     }
6125 }
6126 
6127 /***********************************************************
6128  */
6129 extern (C++) final class AndAssignExp : BinAssignExp
6130 {
6131     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6132     {
6133         super(loc, TOK.andAssign, __traits(classInstanceSize, AndAssignExp), e1, e2);
6134     }
6135 
6136     override void accept(Visitor v)
6137     {
6138         v.visit(this);
6139     }
6140 }
6141 
6142 /***********************************************************
6143  */
6144 extern (C++) final class OrAssignExp : BinAssignExp
6145 {
6146     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6147     {
6148         super(loc, TOK.orAssign, __traits(classInstanceSize, OrAssignExp), e1, e2);
6149     }
6150 
6151     override void accept(Visitor v)
6152     {
6153         v.visit(this);
6154     }
6155 }
6156 
6157 /***********************************************************
6158  */
6159 extern (C++) final class XorAssignExp : BinAssignExp
6160 {
6161     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6162     {
6163         super(loc, TOK.xorAssign, __traits(classInstanceSize, XorAssignExp), e1, e2);
6164     }
6165 
6166     override void accept(Visitor v)
6167     {
6168         v.visit(this);
6169     }
6170 }
6171 
6172 /***********************************************************
6173  */
6174 extern (C++) final class PowAssignExp : BinAssignExp
6175 {
6176     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6177     {
6178         super(loc, TOK.powAssign, __traits(classInstanceSize, PowAssignExp), e1, e2);
6179     }
6180 
6181     override void accept(Visitor v)
6182     {
6183         v.visit(this);
6184     }
6185 }
6186 
6187 /***********************************************************
6188  */
6189 extern (C++) final class ShlAssignExp : BinAssignExp
6190 {
6191     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6192     {
6193         super(loc, TOK.leftShiftAssign, __traits(classInstanceSize, ShlAssignExp), e1, e2);
6194     }
6195 
6196     override void accept(Visitor v)
6197     {
6198         v.visit(this);
6199     }
6200 }
6201 
6202 /***********************************************************
6203  */
6204 extern (C++) final class ShrAssignExp : BinAssignExp
6205 {
6206     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6207     {
6208         super(loc, TOK.rightShiftAssign, __traits(classInstanceSize, ShrAssignExp), e1, e2);
6209     }
6210 
6211     override void accept(Visitor v)
6212     {
6213         v.visit(this);
6214     }
6215 }
6216 
6217 /***********************************************************
6218  */
6219 extern (C++) final class UshrAssignExp : BinAssignExp
6220 {
6221     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6222     {
6223         super(loc, TOK.unsignedRightShiftAssign, __traits(classInstanceSize, UshrAssignExp), e1, e2);
6224     }
6225 
6226     override void accept(Visitor v)
6227     {
6228         v.visit(this);
6229     }
6230 }
6231 
6232 /***********************************************************
6233  * The ~= operator. It can have one of the following operators:
6234  *
6235  * TOK.concatenateAssign      - appending T[] to T[]
6236  * TOK.concatenateElemAssign  - appending T to T[]
6237  * TOK.concatenateDcharAssign - appending dchar to T[]
6238  *
6239  * The parser initially sets it to TOK.concatenateAssign, and semantic() later decides which
6240  * of the three it will be set to.
6241  */
6242 extern (C++) class CatAssignExp : BinAssignExp
6243 {
6244     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6245     {
6246         super(loc, TOK.concatenateAssign, __traits(classInstanceSize, CatAssignExp), e1, e2);
6247     }
6248 
6249     extern (D) this(const ref Loc loc, TOK tok, Expression e1, Expression e2)
6250     {
6251         super(loc, tok, __traits(classInstanceSize, CatAssignExp), e1, e2);
6252     }
6253 
6254     override void accept(Visitor v)
6255     {
6256         v.visit(this);
6257     }
6258 }
6259 
6260 ///
6261 extern (C++) final class CatElemAssignExp : CatAssignExp
6262 {
6263     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6264     {
6265         super(loc, TOK.concatenateElemAssign, e1, e2);
6266         this.type = type;
6267     }
6268 
6269     override void accept(Visitor v)
6270     {
6271         v.visit(this);
6272     }
6273 }
6274 
6275 ///
6276 extern (C++) final class CatDcharAssignExp : CatAssignExp
6277 {
6278     extern (D) this(const ref Loc loc, Type type, Expression e1, Expression e2)
6279     {
6280         super(loc, TOK.concatenateDcharAssign, e1, e2);
6281         this.type = type;
6282     }
6283 
6284     override void accept(Visitor v)
6285     {
6286         v.visit(this);
6287     }
6288 }
6289 
6290 /***********************************************************
6291  * http://dlang.org/spec/expression.html#add_expressions
6292  */
6293 extern (C++) final class AddExp : BinExp
6294 {
6295     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6296     {
6297         super(loc, TOK.add, __traits(classInstanceSize, AddExp), e1, e2);
6298     }
6299 
6300     override void accept(Visitor v)
6301     {
6302         v.visit(this);
6303     }
6304 }
6305 
6306 /***********************************************************
6307  */
6308 extern (C++) final class MinExp : BinExp
6309 {
6310     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6311     {
6312         super(loc, TOK.min, __traits(classInstanceSize, MinExp), e1, e2);
6313     }
6314 
6315     override void accept(Visitor v)
6316     {
6317         v.visit(this);
6318     }
6319 }
6320 
6321 /***********************************************************
6322  * http://dlang.org/spec/expression.html#cat_expressions
6323  */
6324 extern (C++) final class CatExp : BinExp
6325 {
6326     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6327     {
6328         super(loc, TOK.concatenate, __traits(classInstanceSize, CatExp), e1, e2);
6329     }
6330 
6331     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6332     {
6333         e1 = e1.resolveLoc(loc, sc);
6334         e2 = e2.resolveLoc(loc, sc);
6335         return this;
6336     }
6337 
6338     override void accept(Visitor v)
6339     {
6340         v.visit(this);
6341     }
6342 }
6343 
6344 /***********************************************************
6345  * http://dlang.org/spec/expression.html#mul_expressions
6346  */
6347 extern (C++) final class MulExp : BinExp
6348 {
6349     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6350     {
6351         super(loc, TOK.mul, __traits(classInstanceSize, MulExp), e1, e2);
6352     }
6353 
6354     override void accept(Visitor v)
6355     {
6356         v.visit(this);
6357     }
6358 }
6359 
6360 /***********************************************************
6361  * http://dlang.org/spec/expression.html#mul_expressions
6362  */
6363 extern (C++) final class DivExp : BinExp
6364 {
6365     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6366     {
6367         super(loc, TOK.div, __traits(classInstanceSize, DivExp), e1, e2);
6368     }
6369 
6370     override void accept(Visitor v)
6371     {
6372         v.visit(this);
6373     }
6374 }
6375 
6376 /***********************************************************
6377  * http://dlang.org/spec/expression.html#mul_expressions
6378  */
6379 extern (C++) final class ModExp : BinExp
6380 {
6381     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6382     {
6383         super(loc, TOK.mod, __traits(classInstanceSize, ModExp), e1, e2);
6384     }
6385 
6386     override void accept(Visitor v)
6387     {
6388         v.visit(this);
6389     }
6390 }
6391 
6392 /***********************************************************
6393  * http://dlang.org/spec/expression.html#pow_expressions
6394  */
6395 extern (C++) final class PowExp : BinExp
6396 {
6397     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6398     {
6399         super(loc, TOK.pow, __traits(classInstanceSize, PowExp), e1, e2);
6400     }
6401 
6402     override void accept(Visitor v)
6403     {
6404         v.visit(this);
6405     }
6406 }
6407 
6408 /***********************************************************
6409  */
6410 extern (C++) final class ShlExp : BinExp
6411 {
6412     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6413     {
6414         super(loc, TOK.leftShift, __traits(classInstanceSize, ShlExp), e1, e2);
6415     }
6416 
6417     override void accept(Visitor v)
6418     {
6419         v.visit(this);
6420     }
6421 }
6422 
6423 /***********************************************************
6424  */
6425 extern (C++) final class ShrExp : BinExp
6426 {
6427     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6428     {
6429         super(loc, TOK.rightShift, __traits(classInstanceSize, ShrExp), e1, e2);
6430     }
6431 
6432     override void accept(Visitor v)
6433     {
6434         v.visit(this);
6435     }
6436 }
6437 
6438 /***********************************************************
6439  */
6440 extern (C++) final class UshrExp : BinExp
6441 {
6442     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6443     {
6444         super(loc, TOK.unsignedRightShift, __traits(classInstanceSize, UshrExp), e1, e2);
6445     }
6446 
6447     override void accept(Visitor v)
6448     {
6449         v.visit(this);
6450     }
6451 }
6452 
6453 /***********************************************************
6454  */
6455 extern (C++) final class AndExp : BinExp
6456 {
6457     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6458     {
6459         super(loc, TOK.and, __traits(classInstanceSize, AndExp), e1, e2);
6460     }
6461 
6462     override void accept(Visitor v)
6463     {
6464         v.visit(this);
6465     }
6466 }
6467 
6468 /***********************************************************
6469  */
6470 extern (C++) final class OrExp : BinExp
6471 {
6472     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6473     {
6474         super(loc, TOK.or, __traits(classInstanceSize, OrExp), e1, e2);
6475     }
6476 
6477     override void accept(Visitor v)
6478     {
6479         v.visit(this);
6480     }
6481 }
6482 
6483 /***********************************************************
6484  */
6485 extern (C++) final class XorExp : BinExp
6486 {
6487     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6488     {
6489         super(loc, TOK.xor, __traits(classInstanceSize, XorExp), e1, e2);
6490     }
6491 
6492     override void accept(Visitor v)
6493     {
6494         v.visit(this);
6495     }
6496 }
6497 
6498 /***********************************************************
6499  * http://dlang.org/spec/expression.html#andand_expressions
6500  * http://dlang.org/spec/expression.html#oror_expressions
6501  */
6502 extern (C++) final class LogicalExp : BinExp
6503 {
6504     extern (D) this(const ref Loc loc, TOK op, Expression e1, Expression e2)
6505     {
6506         super(loc, op, __traits(classInstanceSize, LogicalExp), e1, e2);
6507         assert(op == TOK.andAnd || op == TOK.orOr);
6508     }
6509 
6510     override Expression toBoolean(Scope* sc)
6511     {
6512         auto ex2 = e2.toBoolean(sc);
6513         if (ex2.op == TOK.error)
6514             return ex2;
6515         e2 = ex2;
6516         return this;
6517     }
6518 
6519     override void accept(Visitor v)
6520     {
6521         v.visit(this);
6522     }
6523 }
6524 
6525 /***********************************************************
6526  * `op` is one of:
6527  *      TOK.lessThan, TOK.lessOrEqual, TOK.greaterThan, TOK.greaterOrEqual
6528  *
6529  * http://dlang.org/spec/expression.html#relation_expressions
6530  */
6531 extern (C++) final class CmpExp : BinExp
6532 {
6533     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6534     {
6535         super(loc, op, __traits(classInstanceSize, CmpExp), e1, e2);
6536         assert(op == TOK.lessThan || op == TOK.lessOrEqual || op == TOK.greaterThan || op == TOK.greaterOrEqual);
6537     }
6538 
6539     override void accept(Visitor v)
6540     {
6541         v.visit(this);
6542     }
6543 }
6544 
6545 /***********************************************************
6546  */
6547 extern (C++) final class InExp : BinExp
6548 {
6549     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6550     {
6551         super(loc, TOK.in_, __traits(classInstanceSize, InExp), e1, e2);
6552     }
6553 
6554     override void accept(Visitor v)
6555     {
6556         v.visit(this);
6557     }
6558 }
6559 
6560 /***********************************************************
6561  * This deletes the key e1 from the associative array e2
6562  */
6563 extern (C++) final class RemoveExp : BinExp
6564 {
6565     extern (D) this(const ref Loc loc, Expression e1, Expression e2)
6566     {
6567         super(loc, TOK.remove, __traits(classInstanceSize, RemoveExp), e1, e2);
6568         type = Type.tbool;
6569     }
6570 
6571     override void accept(Visitor v)
6572     {
6573         v.visit(this);
6574     }
6575 }
6576 
6577 /***********************************************************
6578  * `==` and `!=`
6579  *
6580  * TOK.equal and TOK.notEqual
6581  *
6582  * http://dlang.org/spec/expression.html#equality_expressions
6583  */
6584 extern (C++) final class EqualExp : BinExp
6585 {
6586     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6587     {
6588         super(loc, op, __traits(classInstanceSize, EqualExp), e1, e2);
6589         assert(op == TOK.equal || op == TOK.notEqual);
6590     }
6591 
6592     override void accept(Visitor v)
6593     {
6594         v.visit(this);
6595     }
6596 }
6597 
6598 /***********************************************************
6599  * `is` and `!is`
6600  *
6601  * TOK.identity and TOK.notIdentity
6602  *
6603  *  http://dlang.org/spec/expression.html#identity_expressions
6604  */
6605 extern (C++) final class IdentityExp : BinExp
6606 {
6607     extern (D) this(TOK op, const ref Loc loc, Expression e1, Expression e2)
6608     {
6609         super(loc, op, __traits(classInstanceSize, IdentityExp), e1, e2);
6610         assert(op == TOK.identity || op == TOK.notIdentity);
6611     }
6612 
6613     override void accept(Visitor v)
6614     {
6615         v.visit(this);
6616     }
6617 }
6618 
6619 /***********************************************************
6620  * `econd ? e1 : e2`
6621  *
6622  * http://dlang.org/spec/expression.html#conditional_expressions
6623  */
6624 extern (C++) final class CondExp : BinExp
6625 {
6626     Expression econd;
6627 
6628     extern (D) this(const ref Loc loc, Expression econd, Expression e1, Expression e2)
6629     {
6630         super(loc, TOK.question, __traits(classInstanceSize, CondExp), e1, e2);
6631         this.econd = econd;
6632     }
6633 
6634     override CondExp syntaxCopy()
6635     {
6636         return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6637     }
6638 
6639     override Modifiable checkModifiable(Scope* sc, int flag)
6640     {
6641         if (e1.checkModifiable(sc, flag) != Modifiable.no
6642             && e2.checkModifiable(sc, flag) != Modifiable.no)
6643             return Modifiable.yes;
6644         return Modifiable.no;
6645     }
6646 
6647     override bool isLvalue()
6648     {
6649         return e1.isLvalue() && e2.isLvalue();
6650     }
6651 
6652     override Expression toLvalue(Scope* sc, Expression ex)
6653     {
6654         // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
6655         CondExp e = cast(CondExp)copy();
6656         e.e1 = e1.toLvalue(sc, null).addressOf();
6657         e.e2 = e2.toLvalue(sc, null).addressOf();
6658         e.type = type.pointerTo();
6659         return new PtrExp(loc, e, type);
6660     }
6661 
6662     override Expression modifiableLvalue(Scope* sc, Expression e)
6663     {
6664         //error("conditional expression %s is not a modifiable lvalue", toChars());
6665         e1 = e1.modifiableLvalue(sc, e1);
6666         e2 = e2.modifiableLvalue(sc, e2);
6667         return toLvalue(sc, this);
6668     }
6669 
6670     override Expression toBoolean(Scope* sc)
6671     {
6672         auto ex1 = e1.toBoolean(sc);
6673         auto ex2 = e2.toBoolean(sc);
6674         if (ex1.op == TOK.error)
6675             return ex1;
6676         if (ex2.op == TOK.error)
6677             return ex2;
6678         e1 = ex1;
6679         e2 = ex2;
6680         return this;
6681     }
6682 
6683     void hookDtors(Scope* sc)
6684     {
6685         extern (C++) final class DtorVisitor : StoppableVisitor
6686         {
6687             alias visit = typeof(super).visit;
6688         public:
6689             Scope* sc;
6690             CondExp ce;
6691             VarDeclaration vcond;
6692             bool isThen;
6693 
6694             extern (D) this(Scope* sc, CondExp ce)
6695             {
6696                 this.sc = sc;
6697                 this.ce = ce;
6698             }
6699 
6700             override void visit(Expression e)
6701             {
6702                 //printf("(e = %s)\n", e.toChars());
6703             }
6704 
6705             override void visit(DeclarationExp e)
6706             {
6707                 auto v = e.declaration.isVarDeclaration();
6708                 if (v && !v.isDataseg())
6709                 {
6710                     if (v._init)
6711                     {
6712                         if (auto ei = v._init.isExpInitializer())
6713                             walkPostorder(ei.exp, this);
6714                     }
6715 
6716                     if (v.edtor)
6717                         walkPostorder(v.edtor, this);
6718 
6719                     if (v.needsScopeDtor())
6720                     {
6721                         if (!vcond)
6722                         {
6723                             vcond = copyToTemp(STC.volatile_ | STC.const_, "__cond", ce.econd);
6724                             vcond.dsymbolSemantic(sc);
6725 
6726                             Expression de = new DeclarationExp(ce.econd.loc, vcond);
6727                             de = de.expressionSemantic(sc);
6728 
6729                             Expression ve = new VarExp(ce.econd.loc, vcond);
6730                             ce.econd = Expression.combine(de, ve);
6731                         }
6732 
6733                         //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6734                         Expression ve = new VarExp(vcond.loc, vcond);
6735                         if (isThen)
6736                             v.edtor = new LogicalExp(v.edtor.loc, TOK.andAnd, ve, v.edtor);
6737                         else
6738                             v.edtor = new LogicalExp(v.edtor.loc, TOK.orOr, ve, v.edtor);
6739                         v.edtor = v.edtor.expressionSemantic(sc);
6740                         //printf("\t--v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars());
6741                     }
6742                 }
6743             }
6744         }
6745 
6746         scope DtorVisitor v = new DtorVisitor(sc, this);
6747         //printf("+%s\n", toChars());
6748         v.isThen = true;
6749         walkPostorder(e1, v);
6750         v.isThen = false;
6751         walkPostorder(e2, v);
6752         //printf("-%s\n", toChars());
6753     }
6754 
6755     override void accept(Visitor v)
6756     {
6757         v.visit(this);
6758     }
6759 }
6760 
6761 /// Returns: if this token is the `op` for a derived `DefaultInitExp` class.
6762 bool isDefaultInitOp(TOK op) pure nothrow @safe @nogc
6763 {
6764     return  op == TOK.prettyFunction    || op == TOK.functionString ||
6765             op == TOK.line              || op == TOK.moduleString   ||
6766             op == TOK.file              || op == TOK.fileFullPath   ;
6767 }
6768 
6769 /***********************************************************
6770  */
6771 extern (C++) class DefaultInitExp : Expression
6772 {
6773     extern (D) this(const ref Loc loc, TOK op, int size)
6774     {
6775         super(loc, op, size);
6776     }
6777 
6778     override void accept(Visitor v)
6779     {
6780         v.visit(this);
6781     }
6782 }
6783 
6784 /***********************************************************
6785  */
6786 extern (C++) final class FileInitExp : DefaultInitExp
6787 {
6788     extern (D) this(const ref Loc loc, TOK tok)
6789     {
6790         super(loc, tok, __traits(classInstanceSize, FileInitExp));
6791     }
6792 
6793     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6794     {
6795         //printf("FileInitExp::resolve() %s\n", toChars());
6796         const(char)* s;
6797         if (op == TOK.fileFullPath)
6798             s = FileName.toAbsolute(loc.isValid() ? loc.filename : sc._module.srcfile.toChars());
6799         else
6800             s = loc.isValid() ? loc.filename : sc._module.ident.toChars();
6801 
6802         Expression e = new StringExp(loc, s.toDString());
6803         e = e.expressionSemantic(sc);
6804         e = e.castTo(sc, type);
6805         return e;
6806     }
6807 
6808     override void accept(Visitor v)
6809     {
6810         v.visit(this);
6811     }
6812 }
6813 
6814 /***********************************************************
6815  */
6816 extern (C++) final class LineInitExp : DefaultInitExp
6817 {
6818     extern (D) this(const ref Loc loc)
6819     {
6820         super(loc, TOK.line, __traits(classInstanceSize, LineInitExp));
6821     }
6822 
6823     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6824     {
6825         Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
6826         e = e.castTo(sc, type);
6827         return e;
6828     }
6829 
6830     override void accept(Visitor v)
6831     {
6832         v.visit(this);
6833     }
6834 }
6835 
6836 /***********************************************************
6837  */
6838 extern (C++) final class ModuleInitExp : DefaultInitExp
6839 {
6840     extern (D) this(const ref Loc loc)
6841     {
6842         super(loc, TOK.moduleString, __traits(classInstanceSize, ModuleInitExp));
6843     }
6844 
6845     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6846     {
6847         const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
6848         Expression e = new StringExp(loc, s);
6849         e = e.expressionSemantic(sc);
6850         e = e.castTo(sc, type);
6851         return e;
6852     }
6853 
6854     override void accept(Visitor v)
6855     {
6856         v.visit(this);
6857     }
6858 }
6859 
6860 /***********************************************************
6861  */
6862 extern (C++) final class FuncInitExp : DefaultInitExp
6863 {
6864     extern (D) this(const ref Loc loc)
6865     {
6866         super(loc, TOK.functionString, __traits(classInstanceSize, FuncInitExp));
6867     }
6868 
6869     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6870     {
6871         const(char)* s;
6872         if (sc.callsc && sc.callsc.func)
6873             s = sc.callsc.func.Dsymbol.toPrettyChars();
6874         else if (sc.func)
6875             s = sc.func.Dsymbol.toPrettyChars();
6876         else
6877             s = "";
6878         Expression e = new StringExp(loc, s.toDString());
6879         e = e.expressionSemantic(sc);
6880         e.type = Type.tstring;
6881         return e;
6882     }
6883 
6884     override void accept(Visitor v)
6885     {
6886         v.visit(this);
6887     }
6888 }
6889 
6890 /***********************************************************
6891  */
6892 extern (C++) final class PrettyFuncInitExp : DefaultInitExp
6893 {
6894     extern (D) this(const ref Loc loc)
6895     {
6896         super(loc, TOK.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
6897     }
6898 
6899     override Expression resolveLoc(const ref Loc loc, Scope* sc)
6900     {
6901         FuncDeclaration fd = (sc.callsc && sc.callsc.func)
6902                         ? sc.callsc.func
6903                         : sc.func;
6904 
6905         const(char)* s;
6906         if (fd)
6907         {
6908             const funcStr = fd.Dsymbol.toPrettyChars();
6909             OutBuffer buf;
6910             functionToBufferWithIdent(fd.type.isTypeFunction(), &buf, funcStr, fd.isStatic);
6911             s = buf.extractChars();
6912         }
6913         else
6914         {
6915             s = "";
6916         }
6917 
6918         Expression e = new StringExp(loc, s.toDString());
6919         e = e.expressionSemantic(sc);
6920         e.type = Type.tstring;
6921         return e;
6922     }
6923 
6924     override void accept(Visitor v)
6925     {
6926         v.visit(this);
6927     }
6928 }
6929 
6930 /**
6931  * Objective-C class reference expression.
6932  *
6933  * Used to get the metaclass of an Objective-C class, `NSObject.Class`.
6934  */
6935 extern (C++) final class ObjcClassReferenceExp : Expression
6936 {
6937     ClassDeclaration classDeclaration;
6938 
6939     extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
6940     {
6941         super(loc, TOK.objcClassReference,
6942             __traits(classInstanceSize, ObjcClassReferenceExp));
6943         this.classDeclaration = classDeclaration;
6944         type = objc.getRuntimeMetaclass(classDeclaration).getType();
6945     }
6946 
6947     override void accept(Visitor v)
6948     {
6949         v.visit(this);
6950     }
6951 }