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