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