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