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