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