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
14module dmd.expression;
15
16import core.stdc.stdarg;
17import core.stdc.stdio;
18import core.stdc.string;
19
20import dmd.aggregate;
21import dmd.aliasthis;
22import dmd.apply;
23import dmd.arrayop;
24import dmd.arraytypes;
25import dmd.astenums;
26import dmd.ast_node;
27import dmd.gluelayer;
28import dmd.constfold;
29import dmd.ctfeexpr;
30import dmd.ctorflow;
31import dmd.dcast;
32import dmd.dclass;
33import dmd.declaration;
34import dmd.delegatize;
35import dmd.dimport;
36import dmd.dinterpret;
37import dmd.dmodule;
38import dmd.dscope;
39import dmd.dstruct;
40import dmd.dsymbol;
41import dmd.dsymbolsem;
42import dmd.dtemplate;
43import dmd.errors;
44import dmd.escape;
45import dmd.expressionsem;
46import dmd.func;
47import dmd.globals;
48import dmd.hdrgen;
49import dmd.id;
50import dmd.identifier;
51import dmd.init;
52import dmd.inline;
53import dmd.mtype;
54import dmd.nspace;
55import dmd.objc;
56import dmd.opover;
57import dmd.optimize;
58import dmd.root.complex;
59import dmd.root.ctfloat;
60import dmd.root.filename;
61import dmd.common.outbuffer;
62import dmd.root.optional;
63import dmd.root.rmem;
64import dmd.root.rootobject;
65import dmd.root.string;
66import dmd.root.utf;
67import dmd.safe;
68import dmd.sideeffect;
69import dmd.target;
70import dmd.tokens;
71import dmd.typesem;
72import dmd.visitor;
73
74enum LOGSEMANTIC = false;
75
76void 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
86void emplaceExp(T : UnionExp)(T* p, Expression e)
87{
88    memcpy(p, cast(void*)e, e.size);
89}
90
91/// Return value for `checkModifiable`
92enum 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 */
104enum 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 */
121inout(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
138inout(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 */
156FuncDeclaration 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 */
208bool 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 */
243bool 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 */
257extern (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 */
310TupleDeclaration 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
340int 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            }
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 */
381TemplateDeclaration 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 */
405Expression 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 */
458private 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 */
507extern (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 */
526extern (C++) struct UnionExp
527{
528    // yes, default constructor does nothing
529    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
559private:
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 */
596bool 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 */
608DotIdExp 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 */
622VarDeclaration 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
665enum 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
672enum WANTvalue  = 0;    // default
673enum WANTexpand = 1;    // expand const/immutable variables if possible
674
675/***********************************************************
676 * https://dlang.org/spec/expression.html#expression
677 */
678extern (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
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
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     */
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     */
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
742    Expression syntaxCopy()
743    {
744        //printf("Expression::syntaxCopy()\n");
745        //print();
746        return copy();
747    }
748
749    // kludge for template.isExpression()
750    override final DYNCAST dyncast() const
751    {
752        return DYNCAST.expression;
753    }
754
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    {
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
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
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
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    {
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
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
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
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     */
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
874    extern (D) static Expression combine(Expression e1, Expression e2, Expression e3)
875    {
876        return combine(combine(e1, e2), e3);
877    }
878
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     */
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
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
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
941    uinteger_t toUInteger()
942    {
943        //printf("Expression %s\n", EXPtoString(op).ptr);
944        return cast(uinteger_t)toInteger();
945    }
946
947    real_t toReal()
948    {
949        error("floating point constant expression expected instead of `%s`", toChars());
950        return CTFloat.zero;
951    }
952
953    real_t toImaginary()
954    {
955        error("floating point constant expression expected instead of `%s`", toChars());
956        return CTFloat.zero;
957    }
958
959    complex_t toComplex()
960    {
961        error("floating point constant expression expected instead of `%s`", toChars());
962        return complex_t(CTFloat.zero);
963    }
964
965    StringExp toStringExp()
966    {
967        return null;
968    }
969
970    /***************************************
971     * Return !=0 if expression is an lvalue.
972     */
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     */
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
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
1034    final Expression implicitCastTo(Scope* sc, Type t)
1035    {
1036        return .implicitCastTo(this, sc, t);
1037    }
1038
1039    final MATCH implicitConvTo(Type t)
1040    {
1041        return .implicitConvTo(this, t);
1042    }
1043
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     */
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     */
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     */
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
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
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
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
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
1146    final bool checkDeprecated(Scope* sc, Dsymbol s)
1147    {
1148        return s.checkDeprecated(loc, sc);
1149    }
1150
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     */
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     */
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     */
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    */
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     */
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     */
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     */
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
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     */
1558    Expression addDtorHook(Scope* sc)
1559    {
1560        return this;
1561    }
1562
1563    /******************************
1564     * Take address of expression.
1565     */
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     */
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
1600    final Expression ctfeInterpret()
1601    {
1602        return .ctfeInterpret(this);
1603    }
1604
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
1617    bool hasCode()
1618    {
1619        return true;
1620    }
1621
1622    final pure inout nothrow @nogc @safe
1623    {
1624        inout(IntegerExp)   isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
1625        inout(ErrorExp)     isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
1626        inout(VoidInitExp)  isVoidInitExp() { return op == EXP.void_ ? cast(typeof(return))this : null; }
1627        inout(RealExp)      isRealExp() { return op == EXP.float64 ? cast(typeof(return))this : null; }
1628        inout(ComplexExp)   isComplexExp() { return op == EXP.complex80 ? cast(typeof(return))this : null; }
1629        inout(IdentifierExp) isIdentifierExp() { return op == EXP.identifier ? cast(typeof(return))this : null; }
1630        inout(DollarExp)    isDollarExp() { return op == EXP.dollar ? cast(typeof(return))this : null; }
1631        inout(DsymbolExp)   isDsymbolExp() { return op == EXP.dSymbol ? cast(typeof(return))this : null; }
1632        inout(ThisExp)      isThisExp() { return op == EXP.this_ ? cast(typeof(return))this : null; }
1633        inout(SuperExp)     isSuperExp() { return op == EXP.super_ ? cast(typeof(return))this : null; }
1634        inout(NullExp)      isNullExp() { return op == EXP.null_ ? cast(typeof(return))this : null; }
1635        inout(StringExp)    isStringExp() { return op == EXP.string_ ? cast(typeof(return))this : null; }
1636        inout(TupleExp)     isTupleExp() { return op == EXP.tuple ? cast(typeof(return))this : null; }
1637        inout(ArrayLiteralExp) isArrayLiteralExp() { return op == EXP.arrayLiteral ? cast(typeof(return))this : null; }
1638        inout(AssocArrayLiteralExp) isAssocArrayLiteralExp() { return op == EXP.assocArrayLiteral ? cast(typeof(return))this : null; }
1639        inout(StructLiteralExp) isStructLiteralExp() { return op == EXP.structLiteral ? cast(typeof(return))this : null; }
1640        inout(CompoundLiteralExp) isCompoundLiteralExp() { return op == EXP.compoundLiteral ? cast(typeof(return))this : null; }
1641        inout(TypeExp)      isTypeExp() { return op == EXP.type ? cast(typeof(return))this : null; }
1642        inout(ScopeExp)     isScopeExp() { return op == EXP.scope_ ? cast(typeof(return))this : null; }
1643        inout(TemplateExp)  isTemplateExp() { return op == EXP.template_ ? cast(typeof(return))this : null; }
1644        inout(NewExp) isNewExp() { return op == EXP.new_ ? cast(typeof(return))this : null; }
1645        inout(NewAnonClassExp) isNewAnonClassExp() { return op == EXP.newAnonymousClass ? cast(typeof(return))this : null; }
1646        inout(SymOffExp)    isSymOffExp() { return op == EXP.symbolOffset ? cast(typeof(return))this : null; }
1647        inout(VarExp)       isVarExp() { return op == EXP.variable ? cast(typeof(return))this : null; }
1648        inout(OverExp)      isOverExp() { return op == EXP.overloadSet ? cast(typeof(return))this : null; }
1649        inout(FuncExp)      isFuncExp() { return op == EXP.function_ ? cast(typeof(return))this : null; }
1650        inout(DeclarationExp) isDeclarationExp() { return op == EXP.declaration ? cast(typeof(return))this : null; }
1651        inout(TypeidExp)    isTypeidExp() { return op == EXP.typeid_ ? cast(typeof(return))this : null; }
1652        inout(TraitsExp)    isTraitsExp() { return op == EXP.traits ? cast(typeof(return))this : null; }
1653        inout(HaltExp)      isHaltExp() { return op == EXP.halt ? cast(typeof(return))this : null; }
1654        inout(IsExp)        isExp() { return op == EXP.is_ ? cast(typeof(return))this : null; }
1655        inout(MixinExp)     isMixinExp() { return op == EXP.mixin_ ? cast(typeof(return))this : null; }
1656        inout(ImportExp)    isImportExp() { return op == EXP.import_ ? cast(typeof(return))this : null; }
1657        inout(AssertExp)    isAssertExp() { return op == EXP.assert_ ? cast(typeof(return))this : null; }
1658        inout(ThrowExp)     isThrowExp() { return op == EXP.throw_ ? cast(typeof(return))this : null; }
1659        inout(DotIdExp)     isDotIdExp() { return op == EXP.dotIdentifier ? cast(typeof(return))this : null; }
1660        inout(DotTemplateExp) isDotTemplateExp() { return op == EXP.dotTemplateDeclaration ? cast(typeof(return))this : null; }
1661        inout(DotVarExp)    isDotVarExp() { return op == EXP.dotVariable ? cast(typeof(return))this : null; }
1662        inout(DotTemplateInstanceExp) isDotTemplateInstanceExp() { return op == EXP.dotTemplateInstance ? cast(typeof(return))this : null; }
1663        inout(DelegateExp)  isDelegateExp() { return op == EXP.delegate_ ? cast(typeof(return))this : null; }
1664        inout(DotTypeExp)   isDotTypeExp() { return op == EXP.dotType ? cast(typeof(return))this : null; }
1665        inout(CallExp)      isCallExp() { return op == EXP.call ? cast(typeof(return))this : null; }
1666        inout(AddrExp)      isAddrExp() { return op == EXP.address ? cast(typeof(return))this : null; }
1667        inout(PtrExp)       isPtrExp() { return op == EXP.star ? cast(typeof(return))this : null; }
1668        inout(NegExp)       isNegExp() { return op == EXP.negate ? cast(typeof(return))this : null; }
1669        inout(UAddExp)      isUAddExp() { return op == EXP.uadd ? cast(typeof(return))this : null; }
1670        inout(ComExp)       isComExp() { return op == EXP.tilde ? cast(typeof(return))this : null; }
1671        inout(NotExp)       isNotExp() { return op == EXP.not ? cast(typeof(return))this : null; }
1672        inout(DeleteExp)    isDeleteExp() { return op == EXP.delete_ ? cast(typeof(return))this : null; }
1673        inout(CastExp)      isCastExp() { return op == EXP.cast_ ? cast(typeof(return))this : null; }
1674        inout(VectorExp)    isVectorExp() { return op == EXP.vector ? cast(typeof(return))this : null; }
1675        inout(VectorArrayExp) isVectorArrayExp() { return op == EXP.vectorArray ? cast(typeof(return))this : null; }
1676        inout(SliceExp)     isSliceExp() { return op == EXP.slice ? cast(typeof(return))this : null; }
1677        inout(ArrayLengthExp) isArrayLengthExp() { return op == EXP.arrayLength ? cast(typeof(return))this : null; }
1678        inout(ArrayExp)     isArrayExp() { return op == EXP.array ? cast(typeof(return))this : null; }
1679        inout(DotExp)       isDotExp() { return op == EXP.dot ? cast(typeof(return))this : null; }
1680        inout(CommaExp)     isCommaExp() { return op == EXP.comma ? cast(typeof(return))this : null; }
1681        inout(IntervalExp)  isIntervalExp() { return op == EXP.interval ? cast(typeof(return))this : null; }
1682        inout(DelegatePtrExp)     isDelegatePtrExp() { return op == EXP.delegatePointer ? cast(typeof(return))this : null; }
1683        inout(DelegateFuncptrExp) isDelegateFuncptrExp() { return op == EXP.delegateFunctionPointer ? cast(typeof(return))this : null; }
1684        inout(IndexExp)     isIndexExp() { return op == EXP.index ? cast(typeof(return))this : null; }
1685        inout(PostExp)      isPostExp()  { return (op == EXP.plusPlus || op == EXP.minusMinus) ? cast(typeof(return))this : null; }
1686        inout(PreExp)       isPreExp()   { return (op == EXP.prePlusPlus || op == EXP.preMinusMinus) ? cast(typeof(return))this : null; }
1687        inout(AssignExp)    isAssignExp()    { return op == EXP.assign ? cast(typeof(return))this : null; }
1688        inout(ConstructExp) isConstructExp() { return op == EXP.construct ? cast(typeof(return))this : null; }
1689        inout(BlitExp)      isBlitExp()      { return op == EXP.blit ? cast(typeof(return))this : null; }
1690        inout(AddAssignExp) isAddAssignExp() { return op == EXP.addAssign ? cast(typeof(return))this : null; }
1691        inout(MinAssignExp) isMinAssignExp() { return op == EXP.minAssign ? cast(typeof(return))this : null; }
1692        inout(MulAssignExp) isMulAssignExp() { return op == EXP.mulAssign ? cast(typeof(return))this : null; }
1693
1694        inout(DivAssignExp) isDivAssignExp() { return op == EXP.divAssign ? cast(typeof(return))this : null; }
1695        inout(ModAssignExp) isModAssignExp() { return op == EXP.modAssign ? cast(typeof(return))this : null; }
1696        inout(AndAssignExp) isAndAssignExp() { return op == EXP.andAssign ? cast(typeof(return))this : null; }
1697        inout(OrAssignExp)  isOrAssignExp()  { return op == EXP.orAssign ? cast(typeof(return))this : null; }
1698        inout(XorAssignExp) isXorAssignExp() { return op == EXP.xorAssign ? cast(typeof(return))this : null; }
1699        inout(PowAssignExp) isPowAssignExp() { return op == EXP.powAssign ? cast(typeof(return))this : null; }
1700
1701        inout(ShlAssignExp)  isShlAssignExp()  { return op == EXP.leftShiftAssign ? cast(typeof(return))this : null; }
1702        inout(ShrAssignExp)  isShrAssignExp()  { return op == EXP.rightShiftAssign ? cast(typeof(return))this : null; }
1703        inout(UshrAssignExp) isUshrAssignExp() { return op == EXP.unsignedRightShiftAssign ? cast(typeof(return))this : null; }
1704
1705        inout(CatAssignExp) isCatAssignExp() { return op == EXP.concatenateAssign
1706                                                ? cast(typeof(return))this
1707                                                : null; }
1708
1709        inout(CatElemAssignExp) isCatElemAssignExp() { return op == EXP.concatenateElemAssign
1710                                                ? cast(typeof(return))this
1711                                                : null; }
1712
1713        inout(CatDcharAssignExp) isCatDcharAssignExp() { return op == EXP.concatenateDcharAssign
1714                                                ? cast(typeof(return))this
1715                                                : null; }
1716
1717        inout(AddExp)      isAddExp() { return op == EXP.add ? cast(typeof(return))this : null; }
1718        inout(MinExp)      isMinExp() { return op == EXP.min ? cast(typeof(return))this : null; }
1719        inout(CatExp)      isCatExp() { return op == EXP.concatenate ? cast(typeof(return))this : null; }
1720        inout(MulExp)      isMulExp() { return op == EXP.mul ? cast(typeof(return))this : null; }
1721        inout(DivExp)      isDivExp() { return op == EXP.div ? cast(typeof(return))this : null; }
1722        inout(ModExp)      isModExp() { return op == EXP.mod ? cast(typeof(return))this : null; }
1723        inout(PowExp)      isPowExp() { return op == EXP.pow ? cast(typeof(return))this : null; }
1724        inout(ShlExp)      isShlExp() { return op == EXP.leftShift ? cast(typeof(return))this : null; }
1725        inout(ShrExp)      isShrExp() { return op == EXP.rightShift ? cast(typeof(return))this : null; }
1726        inout(UshrExp)     isUshrExp() { return op == EXP.unsignedRightShift ? cast(typeof(return))this : null; }
1727        inout(AndExp)      isAndExp() { return op == EXP.and ? cast(typeof(return))this : null; }
1728        inout(OrExp)       isOrExp() { return op == EXP.or ? cast(typeof(return))this : null; }
1729        inout(XorExp)      isXorExp() { return op == EXP.xor ? cast(typeof(return))this : null; }
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; }
1732        inout(InExp)       isInExp() { return op == EXP.in_ ? cast(typeof(return))this : null; }
1733        inout(RemoveExp)   isRemoveExp() { return op == EXP.remove ? cast(typeof(return))this : null; }
1734        inout(EqualExp)    isEqualExp() { return (op == EXP.equal || op == EXP.notEqual) ? cast(typeof(return))this : null; }
1735        inout(IdentityExp) isIdentityExp() { return (op == EXP.identity || op == EXP.notIdentity) ? cast(typeof(return))this : null; }
1736        inout(CondExp)     isCondExp() { return op == EXP.question ? cast(typeof(return))this : null; }
1737        inout(GenericExp)  isGenericExp() { return op == EXP._Generic ? cast(typeof(return))this : null; }
1738        inout(DefaultInitExp)    isDefaultInitExp() { return isDefaultInitOp(op) ? cast(typeof(return))this: null; }
1739        inout(FileInitExp)       isFileInitExp() { return (op == EXP.file || op == EXP.fileFullPath) ? cast(typeof(return))this : null; }
1740        inout(LineInitExp)       isLineInitExp() { return op == EXP.line ? cast(typeof(return))this : null; }
1741        inout(ModuleInitExp)     isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
1742        inout(FuncInitExp)       isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
1743        inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
1744        inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
1745        inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
1746        inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
1747
1748        inout(UnaExp) isUnaExp() pure inout nothrow @nogc
1749        {
1750            return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
1751        }
1752
1753        inout(BinExp) isBinExp() pure inout nothrow @nogc
1754        {
1755            return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
1756        }
1757
1758        inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
1759        {
1760            return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
1761        }
1762    }
1763
1764    override void accept(Visitor v)
1765    {
1766        v.visit(this);
1767    }
1768}
1769
1770/***********************************************************
1771 * A compile-time known integer value
1772 */
1773extern (C++) final class IntegerExp : Expression
1774{
1775    private dinteger_t value;
1776
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
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
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.
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
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
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
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
1842    override real_t toImaginary()
1843    {
1844        return CTFloat.zero;
1845    }
1846
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
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
1868    override void accept(Visitor v)
1869    {
1870        v.visit(this);
1871    }
1872
1873    dinteger_t getInteger()
1874    {
1875        return value;
1876    }
1877
1878    void setInteger(dinteger_t value)
1879    {
1880        this.value = normalize(type.toBasetype().ty, value);
1881    }
1882
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
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     */
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     */
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 */
1991extern (C++) final class ErrorExp : Expression
1992{
1993    private extern (D) this()
1994    {
1995        super(Loc.initial, EXP.error, __traits(classInstanceSize, ErrorExp));
1996        type = Type.terror;
1997    }
1998
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
2016    override Expression toLvalue(Scope* sc, Expression e)
2017    {
2018        return this;
2019    }
2020
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 */
2036extern (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
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
2048    override const(char)* toChars() const
2049    {
2050        return "void";
2051    }
2052
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 */
2063extern (C++) final class RealExp : Expression
2064{
2065    real_t value;
2066
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
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.
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
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
2100    override dinteger_t toInteger()
2101    {
2102        return cast(sinteger_t)toReal();
2103    }
2104
2105    override uinteger_t toUInteger()
2106    {
2107        return cast(uinteger_t)toReal();
2108    }
2109
2110    override real_t toReal()
2111    {
2112        return type.isreal() ? value : CTFloat.zero;
2113    }
2114
2115    override real_t toImaginary()
2116    {
2117        return type.isreal() ? CTFloat.zero : value;
2118    }
2119
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
2130    override void accept(Visitor v)
2131    {
2132        v.visit(this);
2133    }
2134}
2135
2136/***********************************************************
2137 * A compile-time complex number (deprecated)
2138 */
2139extern (C++) final class ComplexExp : Expression
2140{
2141    complex_t value;
2142
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
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.
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
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
2176    override dinteger_t toInteger()
2177    {
2178        return cast(sinteger_t)toReal();
2179    }
2180
2181    override uinteger_t toUInteger()
2182    {
2183        return cast(uinteger_t)toReal();
2184    }
2185
2186    override real_t toReal()
2187    {
2188        return creall(value);
2189    }
2190
2191    override real_t toImaginary()
2192    {
2193        return cimagl(value);
2194    }
2195
2196    override complex_t toComplex()
2197    {
2198        return value;
2199    }
2200
2201    override Optional!bool toBool()
2202    {
2203        return typeof(return)(!!value);
2204    }
2205
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 */
2220extern (C++) class IdentifierExp : Expression
2221{
2222    Identifier ident;
2223
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
2230    static IdentifierExp create(const ref Loc loc, Identifier ident)
2231    {
2232        return new IdentifierExp(loc, ident);
2233    }
2234
2235    override final bool isLvalue()
2236    {
2237        return true;
2238    }
2239
2240    override final Expression toLvalue(Scope* sc, Expression e)
2241    {
2242        return this;
2243    }
2244
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 */
2256extern (C++) final class DollarExp : IdentifierExp
2257{
2258    extern (D) this(const ref Loc loc)
2259    {
2260        super(loc, Id.dollar);
2261    }
2262
2263    override void accept(Visitor v)
2264    {
2265        v.visit(this);
2266    }
2267}
2268
2269/***********************************************************
2270 * Won't be generated by parser.
2271 */
2272extern (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
2284    override bool isLvalue()
2285    {
2286        return true;
2287    }
2288
2289    override Expression toLvalue(Scope* sc, Expression e)
2290    {
2291        return this;
2292    }
2293
2294    override void accept(Visitor v)
2295    {
2296        v.visit(this);
2297    }
2298}
2299
2300/***********************************************************
2301 * https://dlang.org/spec/expression.html#this
2302 */
2303extern (C++) class ThisExp : Expression
2304{
2305    VarDeclaration var;
2306
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
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
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
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
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
2350    override void accept(Visitor v)
2351    {
2352        v.visit(this);
2353    }
2354}
2355
2356/***********************************************************
2357 * https://dlang.org/spec/expression.html#super
2358 */
2359extern (C++) final class SuperExp : ThisExp
2360{
2361    extern (D) this(const ref Loc loc)
2362    {
2363        super(loc, EXP.super_);
2364    }
2365
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 */
2377extern (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
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
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
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 */
2423extern (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
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
2455    static StringExp create(const ref Loc loc, const(char)* s)
2456    {
2457        return new StringExp(loc, s.toDString());
2458    }
2459
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.
2466    static void emplace(UnionExp* pue, const ref Loc loc, const(char)* s)
2467    {
2468        emplaceExp!(StringExp)(pue, loc, s.toDString());
2469    }
2470
2471    extern (D) static void emplace(UnionExp* pue, const ref Loc loc, const(void)[] string)
2472    {
2473        emplaceExp!(StringExp)(pue, loc, string);
2474    }
2475
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
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     */
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     */
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
2633    override StringExp toStringExp()
2634    {
2635        return this;
2636    }
2637
2638    /****************************************
2639     * Convert string to char[].
2640     */
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     */
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
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
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
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     */
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
2760    extern (D) const(char)[] peekString() const
2761    {
2762        assert(sz == 1);
2763        return this.string[0 .. len];
2764    }
2765
2766    extern (D) const(wchar)[] peekWstring() const
2767    {
2768        assert(sz == 2);
2769        return this.wstring[0 .. len];
2770    }
2771
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     */
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     */
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     */
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
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 */
2820extern (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
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
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
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
2882    static TupleExp create(const ref Loc loc, Expressions* exps)
2883    {
2884        return new TupleExp(loc, exps);
2885    }
2886
2887    override TupleExp syntaxCopy()
2888    {
2889        return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
2890    }
2891
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
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 */
2925extern (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
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
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
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
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.
2966    static void emplace(UnionExp* pue, const ref Loc loc, Expressions* elements)
2967    {
2968        emplaceExp!(ArrayLiteralExp)(pue, loc, null, elements);
2969    }
2970
2971    override ArrayLiteralExp syntaxCopy()
2972    {
2973        return new ArrayLiteralExp(loc,
2974            null,
2975            basis ? basis.syntaxCopy() : null,
2976            arraySyntaxCopy(elements));
2977    }
2978
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
3009    Expression getElement(size_t i)
3010    {
3011        return this[i];
3012    }
3013
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
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
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 */
3090extern (C++) final class AssocArrayLiteralExp : Expression
3091{
3092    Expressions* keys;
3093    Expressions* values;
3094
3095    OwnedBy ownedByCtfe = OwnedBy.code;
3096
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
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
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
3145    override void accept(Visitor v)
3146    {
3147        v.visit(this);
3148    }
3149}
3150
3151enum stageScrub             = 0x1;  /// scrubReturnValue is running
3152enum stageSearchPointers    = 0x2;  /// hasNonConstPointers is running
3153enum stageOptimize          = 0x4;  /// optimize is running
3154enum stageApply             = 0x8;  /// apply is running
3155enum stageInlineScan        = 0x10; /// inlineScan is running
3156enum stageToCBuffer         = 0x20; /// toCBuffer is running
3157
3158/***********************************************************
3159 * sd( e1, e2, e3, ... )
3160 */
3161extern (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
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
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     */
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     */
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
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
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
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 */
3365extern (C++) final class CompoundLiteralExp : Expression
3366{
3367    Initializer initializer; /// initializer-list
3368
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
3377    override void accept(Visitor v)
3378    {
3379        v.visit(this);
3380    }
3381}
3382
3383/***********************************************************
3384 * Mainly just a placeholder
3385 */
3386extern (C++) final class TypeExp : Expression
3387{
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
3395    override TypeExp syntaxCopy()
3396    {
3397        return new TypeExp(loc, type.syntaxCopy());
3398    }
3399
3400    override bool checkType()
3401    {
3402        error("type `%s` is not an expression", toChars());
3403        return true;
3404    }
3405
3406    override bool checkValue()
3407    {
3408        error("type `%s` has no value", toChars());
3409        return true;
3410    }
3411
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 */
3426extern (C++) final class ScopeExp : Expression
3427{
3428    ScopeDsymbol sds;
3429
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
3439    override ScopeExp syntaxCopy()
3440    {
3441        return new ScopeExp(loc, sds.syntaxCopy(null));
3442    }
3443
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
3465    override bool checkValue()
3466    {
3467        error("%s `%s` has no value", sds.kind(), sds.toChars());
3468        return true;
3469    }
3470
3471    override void accept(Visitor v)
3472    {
3473        v.visit(this);
3474    }
3475}
3476
3477/***********************************************************
3478 * Mainly just a placeholder
3479 */
3480extern (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
3493    override bool isLvalue()
3494    {
3495        return fd !is null;
3496    }
3497
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
3507    override bool checkType()
3508    {
3509        error("%s `%s` has no type", td.kind(), toChars());
3510        return true;
3511    }
3512
3513    override bool checkValue()
3514    {
3515        error("%s `%s` has no value", td.kind(), toChars());
3516        return true;
3517    }
3518
3519    override void accept(Visitor v)
3520    {
3521        v.visit(this);
3522    }
3523}
3524
3525/***********************************************************
3526 * newtype(arguments)
3527 */
3528extern (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
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
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
3552    override NewExp syntaxCopy()
3553    {
3554        return new NewExp(loc,
3555            thisexp ? thisexp.syntaxCopy() : null,
3556            newtype.syntaxCopy(),
3557            arraySyntaxCopy(arguments));
3558    }
3559
3560    override void accept(Visitor v)
3561    {
3562        v.visit(this);
3563    }
3564}
3565
3566/***********************************************************
3567 * class baseclasses { } (arguments)
3568 */
3569extern (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
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
3583    override NewAnonClassExp syntaxCopy()
3584    {
3585        return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
3586    }
3587
3588    override void accept(Visitor v)
3589    {
3590        v.visit(this);
3591    }
3592}
3593
3594/***********************************************************
3595 */
3596extern (C++) class SymbolExp : Expression
3597{
3598    Declaration var;
3599    Dsymbol originalScope; // original scope before inlining
3600    bool hasOverloads;
3601
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
3610    override void accept(Visitor v)
3611    {
3612        v.visit(this);
3613    }
3614}
3615
3616/***********************************************************
3617 * Offset from symbol
3618 */
3619extern (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
3642    override void accept(Visitor v)
3643    {
3644        v.visit(this);
3645    }
3646}
3647
3648/***********************************************************
3649 * Variable
3650 */
3651extern (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
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
3684    override bool isLvalue()
3685    {
3686        if (var.storage_class & (STC.lazy_ | STC.rvalue | STC.manifest))
3687            return false;
3688        return true;
3689    }
3690
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
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
3728    override void accept(Visitor v)
3729    {
3730        v.visit(this);
3731    }
3732}
3733
3734/***********************************************************
3735 * Overload Set
3736 */
3737extern (C++) final class OverExp : Expression
3738{
3739    OverloadSet vars;
3740
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
3749    override bool isLvalue()
3750    {
3751        return true;
3752    }
3753
3754    override Expression toLvalue(Scope* sc, Expression e)
3755    {
3756        return this;
3757    }
3758
3759    override void accept(Visitor v)
3760    {
3761        v.visit(this);
3762    }
3763}
3764
3765/***********************************************************
3766 * Function/Delegate literal
3767 */
3768
3769extern (C++) final class FuncExp : Expression
3770{
3771    FuncLiteralDeclaration fd;
3772    TemplateDeclaration td;
3773    TOK tok;  // TOK.reserved, TOK.delegate_, TOK.function_
3774
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
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
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
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
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
4031    override const(char)* toChars() const
4032    {
4033        return fd.toChars();
4034    }
4035
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
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
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 */
4069extern (C++) final class DeclarationExp : Expression
4070{
4071    Dsymbol declaration;
4072
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
4079    override DeclarationExp syntaxCopy()
4080    {
4081        return new DeclarationExp(loc, declaration.syntaxCopy(null));
4082    }
4083
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
4093    override void accept(Visitor v)
4094    {
4095        v.visit(this);
4096    }
4097}
4098
4099/***********************************************************
4100 * typeid(int)
4101 */
4102extern (C++) final class TypeidExp : Expression
4103{
4104    RootObject obj;
4105
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
4112    override TypeidExp syntaxCopy()
4113    {
4114        return new TypeidExp(loc, objectSyntaxCopy(obj));
4115    }
4116
4117    override void accept(Visitor v)
4118    {
4119        v.visit(this);
4120    }
4121}
4122
4123/***********************************************************
4124 * __traits(identifier, args...)
4125 */
4126extern (C++) final class TraitsExp : Expression
4127{
4128    Identifier ident;
4129    Objects* args;
4130
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
4138    override TraitsExp syntaxCopy()
4139    {
4140        return new TraitsExp(loc, ident, TemplateInstance.arraySyntaxCopy(args));
4141    }
4142
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 */
4154extern (C++) final class HaltExp : Expression
4155{
4156    extern (D) this(const ref Loc loc)
4157    {
4158        super(loc, EXP.halt, __traits(classInstanceSize, HaltExp));
4159    }
4160
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 */
4171extern (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
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
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
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 */
4215extern (C++) abstract class UnaExp : Expression
4216{
4217    Expression e1;
4218    Type att1;      // Save alias this type to detect recursion
4219
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
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     */
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     */
4261    final void setNoderefOperand()
4262    {
4263        if (auto edi = e1.isDotIdExp())
4264            edi.noderef = true;
4265
4266    }
4267
4268    override final Expression resolveLoc(const ref Loc loc, Scope* sc)
4269    {
4270        e1 = e1.resolveLoc(loc, sc);
4271        return this;
4272    }
4273
4274    override void accept(Visitor v)
4275    {
4276        v.visit(this);
4277    }
4278}
4279
4280alias fp_t = UnionExp function(const ref Loc loc, Type, Expression, Expression);
4281alias fp2_t = bool function(const ref Loc loc, EXP, Expression, Expression);
4282
4283/***********************************************************
4284 * Base class for binary operators
4285 */
4286extern (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
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
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     */
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
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
4490    extern (D) final bool checkIntegralBin()
4491    {
4492        bool r1 = e1.checkIntegral();
4493        bool r2 = e2.checkIntegral();
4494        return (r1 || r2);
4495    }
4496
4497    extern (D) final bool checkArithmeticBin()
4498    {
4499        bool r1 = e1.checkArithmetic();
4500        bool r2 = e2.checkArithmetic();
4501        return (r1 || r2);
4502    }
4503
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     */
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
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
4573    override void accept(Visitor v)
4574    {
4575        v.visit(this);
4576    }
4577}
4578
4579/***********************************************************
4580 * Binary operator assignment, `+=` `-=` `*=` etc.
4581 */
4582extern (C++) class BinAssignExp : BinExp
4583{
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
4589    override final bool isLvalue()
4590    {
4591        return true;
4592    }
4593
4594    override final Expression toLvalue(Scope* sc, Expression ex)
4595    {
4596        // Lvalue-ness will be handled in glue layer.
4597        return this;
4598    }
4599
4600    override final Expression modifiableLvalue(Scope* sc, Expression e)
4601    {
4602        // should check e1.checkModifiable() ?
4603        return toLvalue(sc, this);
4604    }
4605
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 */
4617extern (C++) final class MixinExp : Expression
4618{
4619    Expressions* exps;
4620
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
4627    override MixinExp syntaxCopy()
4628    {
4629        return new MixinExp(loc, arraySyntaxCopy(exps));
4630    }
4631
4632    override bool equals(const RootObject o) const
4633    {
4634        if (this == o)
4635            return true;
4636        auto e = o.isExpression();
4637        if (!e)
4638            return false;
4639        if (auto ce = e.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
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 */
4667extern (C++) final class ImportExp : UnaExp
4668{
4669    extern (D) this(const ref Loc loc, Expression e)
4670    {
4671        super(loc, EXP.import_, __traits(classInstanceSize, ImportExp), e);
4672    }
4673
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 */
4685extern (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
4695    override AssertExp syntaxCopy()
4696    {
4697        return new AssertExp(loc, e1.syntaxCopy(), msg ? msg.syntaxCopy() : null);
4698    }
4699
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 */
4712extern (C++) final class ThrowExp : UnaExp
4713{
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
4720    override ThrowExp syntaxCopy()
4721    {
4722        return new ThrowExp(loc, e1.syntaxCopy());
4723    }
4724
4725    override void accept(Visitor v)
4726    {
4727        v.visit(this);
4728    }
4729}
4730
4731/***********************************************************
4732 */
4733extern (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
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
4746    static DotIdExp create(const ref Loc loc, Expression e, Identifier ident)
4747    {
4748        return new DotIdExp(loc, e, ident);
4749    }
4750
4751    override void accept(Visitor v)
4752    {
4753        v.visit(this);
4754    }
4755}
4756
4757/***********************************************************
4758 * Mainly just a placeholder
4759 */
4760extern (C++) final class DotTemplateExp : UnaExp
4761{
4762    TemplateDeclaration td;
4763
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
4770    override bool checkType()
4771    {
4772        error("%s `%s` has no type", td.kind(), toChars());
4773        return true;
4774    }
4775
4776    override bool checkValue()
4777    {
4778        error("%s `%s` has no value", td.kind(), toChars());
4779        return true;
4780    }
4781
4782    override void accept(Visitor v)
4783    {
4784        v.visit(this);
4785    }
4786}
4787
4788/***********************************************************
4789 */
4790extern (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
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
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
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
4866    override void accept(Visitor v)
4867    {
4868        v.visit(this);
4869    }
4870}
4871
4872/***********************************************************
4873 * foo.bar!(args)
4874 */
4875extern (C++) final class DotTemplateInstanceExp : UnaExp
4876{
4877    TemplateInstance ti;
4878
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
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
4892    override DotTemplateInstanceExp syntaxCopy()
4893    {
4894        return new DotTemplateInstanceExp(loc, e1.syntaxCopy(), ti.name, TemplateInstance.arraySyntaxCopy(ti.tiargs));
4895    }
4896
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
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
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
4965    override void accept(Visitor v)
4966    {
4967        v.visit(this);
4968    }
4969}
4970
4971/***********************************************************
4972 */
4973extern (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
4987    override void accept(Visitor v)
4988    {
4989        v.visit(this);
4990    }
4991}
4992
4993/***********************************************************
4994 */
4995extern (C++) final class DotTypeExp : UnaExp
4996{
4997    Dsymbol sym;        // symbol that represents a type
4998
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
5005    override void accept(Visitor v)
5006    {
5007        v.visit(this);
5008    }
5009}
5010
5011/***********************************************************
5012 */
5013extern (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
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
5028    extern (D) this(const ref Loc loc, Expression e)
5029    {
5030        super(loc, EXP.call, __traits(classInstanceSize, CallExp), e);
5031    }
5032
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
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    */
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
5063    static CallExp create(const ref Loc loc, Expression e, Expressions* exps)
5064    {
5065        return new CallExp(loc, e, exps);
5066    }
5067
5068    static CallExp create(const ref Loc loc, Expression e)
5069    {
5070        return new CallExp(loc, e);
5071    }
5072
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    */
5085    static CallExp create(const ref Loc loc, FuncDeclaration fd, Expression earg1)
5086    {
5087        return new CallExp(loc, fd, earg1);
5088    }
5089
5090    override CallExp syntaxCopy()
5091    {
5092        return new CallExp(loc, e1.syntaxCopy(), arraySyntaxCopy(arguments));
5093    }
5094
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
5111    override Expression toLvalue(Scope* sc, Expression e)
5112    {
5113        if (isLvalue())
5114            return this;
5115        return Expression.toLvalue(sc, e);
5116    }
5117
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
5150    override void accept(Visitor v)
5151    {
5152        v.visit(this);
5153    }
5154}
5155
5156FuncDeclaration 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 */
5195extern (C++) final class AddrExp : UnaExp
5196{
5197    extern (D) this(const ref Loc loc, Expression e)
5198    {
5199        super(loc, EXP.address, __traits(classInstanceSize, AddrExp), e);
5200    }
5201
5202    extern (D) this(const ref Loc loc, Expression e, Type t)
5203    {
5204        this(loc, e);
5205        type = t;
5206    }
5207
5208    override void accept(Visitor v)
5209    {
5210        v.visit(this);
5211    }
5212}
5213
5214/***********************************************************
5215 * The pointer dereference operator, `*p`
5216 */
5217extern (C++) final class PtrExp : UnaExp
5218{
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
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
5232    override bool isLvalue()
5233    {
5234        return true;
5235    }
5236
5237    override Expression toLvalue(Scope* sc, Expression e)
5238    {
5239        return this;
5240    }
5241
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
5261    override void accept(Visitor v)
5262    {
5263        v.visit(this);
5264    }
5265}
5266
5267/***********************************************************
5268 * The negation operator, `-x`
5269 */
5270extern (C++) final class NegExp : UnaExp
5271{
5272    extern (D) this(const ref Loc loc, Expression e)
5273    {
5274        super(loc, EXP.negate, __traits(classInstanceSize, NegExp), e);
5275    }
5276
5277    override void accept(Visitor v)
5278    {
5279        v.visit(this);
5280    }
5281}
5282
5283/***********************************************************
5284 * The unary add operator, `+x`
5285 */
5286extern (C++) final class UAddExp : UnaExp
5287{
5288    extern (D) this(const ref Loc loc, Expression e)
5289    {
5290        super(loc, EXP.uadd, __traits(classInstanceSize, UAddExp), e);
5291    }
5292
5293    override void accept(Visitor v)
5294    {
5295        v.visit(this);
5296    }
5297}
5298
5299/***********************************************************
5300 * The bitwise complement operator, `~x`
5301 */
5302extern (C++) final class ComExp : UnaExp
5303{
5304    extern (D) this(const ref Loc loc, Expression e)
5305    {
5306        super(loc, EXP.tilde, __traits(classInstanceSize, ComExp), e);
5307    }
5308
5309    override void accept(Visitor v)
5310    {
5311        v.visit(this);
5312    }
5313}
5314
5315/***********************************************************
5316 * The logical not operator, `!x`
5317 */
5318extern (C++) final class NotExp : UnaExp
5319{
5320    extern (D) this(const ref Loc loc, Expression e)
5321    {
5322        super(loc, EXP.not, __traits(classInstanceSize, NotExp), e);
5323    }
5324
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 */
5336extern (C++) final class DeleteExp : UnaExp
5337{
5338    bool isRAII;        // true if called automatically as a result of scoped destruction
5339
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
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 */
5359extern (C++) final class CastExp : UnaExp
5360{
5361    Type to;                    // type to cast to
5362    ubyte mod = cast(ubyte)~0;  // MODxxxxx
5363
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     */
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
5378    override CastExp syntaxCopy()
5379    {
5380        return to ? new CastExp(loc, e1.syntaxCopy(), to.syntaxCopy()) : new CastExp(loc, e1.syntaxCopy(), mod);
5381    }
5382
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
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
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
5412    override void accept(Visitor v)
5413    {
5414        v.visit(this);
5415    }
5416}
5417
5418/***********************************************************
5419 */
5420extern (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
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
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.
5439    static void emplace(UnionExp* pue, const ref Loc loc, Expression e, Type type)
5440    {
5441        emplaceExp!(VectorExp)(pue, loc, e, type);
5442    }
5443
5444    override VectorExp syntaxCopy()
5445    {
5446        return new VectorExp(loc, e1.syntaxCopy(), to.syntaxCopy());
5447    }
5448
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 */
5460extern (C++) final class VectorArrayExp : UnaExp
5461{
5462    extern (D) this(const ref Loc loc, Expression e1)
5463    {
5464        super(loc, EXP.vectorArray, __traits(classInstanceSize, VectorArrayExp), e1);
5465    }
5466
5467    override bool isLvalue()
5468    {
5469        return e1.isLvalue();
5470    }
5471
5472    override Expression toLvalue(Scope* sc, Expression e)
5473    {
5474        e1 = e1.toLvalue(sc, e);
5475        return this;
5476    }
5477
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 */
5489extern (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    /************************************************************/
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
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
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
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
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
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
5546    override void accept(Visitor v)
5547    {
5548        v.visit(this);
5549    }
5550}
5551
5552/***********************************************************
5553 * The `.length` property of an array
5554 */
5555extern (C++) final class ArrayLengthExp : UnaExp
5556{
5557    extern (D) this(const ref Loc loc, Expression e1)
5558    {
5559        super(loc, EXP.arrayLength, __traits(classInstanceSize, ArrayLengthExp), e1);
5560    }
5561
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 */
5573extern (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
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
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
5601    override bool isLvalue()
5602    {
5603        if (type && type.toBasetype().ty == Tvoid)
5604            return false;
5605        return true;
5606    }
5607
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
5615    override void accept(Visitor v)
5616    {
5617        v.visit(this);
5618    }
5619}
5620
5621/***********************************************************
5622 */
5623extern (C++) final class DotExp : BinExp
5624{
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
5630    override void accept(Visitor v)
5631    {
5632        v.visit(this);
5633    }
5634}
5635
5636/***********************************************************
5637 */
5638extern (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
5657    override bool isLvalue()
5658    {
5659        return e2.isLvalue();
5660    }
5661
5662    override Expression toLvalue(Scope* sc, Expression e)
5663    {
5664        e2 = e2.toLvalue(sc, null);
5665        return this;
5666    }
5667
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
5679    override Expression addDtorHook(Scope* sc)
5680    {
5681        e2 = e2.addDtorHook(sc);
5682        return this;
5683    }
5684
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     */
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 */
5715extern (C++) final class IntervalExp : Expression
5716{
5717    Expression lwr;
5718    Expression upr;
5719
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
5727    override Expression syntaxCopy()
5728    {
5729        return new IntervalExp(loc, lwr.syntaxCopy(), upr.syntaxCopy());
5730    }
5731
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 */
5743extern (C++) final class DelegatePtrExp : UnaExp
5744{
5745    extern (D) this(const ref Loc loc, Expression e1)
5746    {
5747        super(loc, EXP.delegatePointer, __traits(classInstanceSize, DelegatePtrExp), e1);
5748    }
5749
5750    override bool isLvalue()
5751    {
5752        return e1.isLvalue();
5753    }
5754
5755    override Expression toLvalue(Scope* sc, Expression e)
5756    {
5757        e1 = e1.toLvalue(sc, e);
5758        return this;
5759    }
5760
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
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 */
5782extern (C++) final class DelegateFuncptrExp : UnaExp
5783{
5784    extern (D) this(const ref Loc loc, Expression e1)
5785    {
5786        super(loc, EXP.delegateFunctionPointer, __traits(classInstanceSize, DelegateFuncptrExp), e1);
5787    }
5788
5789    override bool isLvalue()
5790    {
5791        return e1.isLvalue();
5792    }
5793
5794    override Expression toLvalue(Scope* sc, Expression e)
5795    {
5796        e1 = e1.toLvalue(sc, e);
5797        return this;
5798    }
5799
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
5810    override void accept(Visitor v)
5811    {
5812        v.visit(this);
5813    }
5814}
5815
5816/***********************************************************
5817 * e1 [ e2 ]
5818 */
5819extern (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
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
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
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
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
5857    override Expression toLvalue(Scope* sc, Expression e)
5858    {
5859        if (isLvalue())
5860            return this;
5861        return Expression.toLvalue(sc, e);
5862    }
5863
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
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
5897    override void accept(Visitor v)
5898    {
5899        v.visit(this);
5900    }
5901}
5902
5903/***********************************************************
5904 * The postfix increment/decrement operator, `i++` / `i--`
5905 */
5906extern (C++) final class PostExp : BinExp
5907{
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
5914    override void accept(Visitor v)
5915    {
5916        v.visit(this);
5917    }
5918}
5919
5920/***********************************************************
5921 * The prefix increment/decrement operator, `++i` / `--i`
5922 */
5923extern (C++) final class PreExp : UnaExp
5924{
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
5931    override void accept(Visitor v)
5932    {
5933        v.visit(this);
5934    }
5935}
5936
5937enum 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 */
5949extern (C++) class AssignExp : BinExp
5950{
5951    MemorySet memset;
5952
5953    /************************************************************/
5954    /* op can be EXP.assign, EXP.construct, or EXP.blit */
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
5960    this(const ref Loc loc, EXP tok, Expression e1, Expression e2)
5961    {
5962        super(loc, tok, __traits(classInstanceSize, AssignExp), e1, e2);
5963    }
5964
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
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
5990    override void accept(Visitor v)
5991    {
5992        v.visit(this);
5993    }
5994}
5995
5996/***********************************************************
5997 */
5998extern (C++) final class ConstructExp : AssignExp
5999{
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.
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
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 */
6027extern (C++) final class BlitExp : AssignExp
6028{
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.
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
6047    override void accept(Visitor v)
6048    {
6049        v.visit(this);
6050    }
6051}
6052
6053/***********************************************************
6054 * `x += y`
6055 */
6056extern (C++) final class AddAssignExp : BinAssignExp
6057{
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
6063    override void accept(Visitor v)
6064    {
6065        v.visit(this);
6066    }
6067}
6068
6069/***********************************************************
6070 * `x -= y`
6071 */
6072extern (C++) final class MinAssignExp : BinAssignExp
6073{
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
6079    override void accept(Visitor v)
6080    {
6081        v.visit(this);
6082    }
6083}
6084
6085/***********************************************************
6086 * `x *= y`
6087 */
6088extern (C++) final class MulAssignExp : BinAssignExp
6089{
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
6095    override void accept(Visitor v)
6096    {
6097        v.visit(this);
6098    }
6099}
6100
6101/***********************************************************
6102 * `x /= y`
6103 */
6104extern (C++) final class DivAssignExp : BinAssignExp
6105{
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
6111    override void accept(Visitor v)
6112    {
6113        v.visit(this);
6114    }
6115}
6116
6117/***********************************************************
6118 * `x %= y`
6119 */
6120extern (C++) final class ModAssignExp : BinAssignExp
6121{
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
6127    override void accept(Visitor v)
6128    {
6129        v.visit(this);
6130    }
6131}
6132
6133/***********************************************************
6134 * `x &= y`
6135 */
6136extern (C++) final class AndAssignExp : BinAssignExp
6137{
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
6143    override void accept(Visitor v)
6144    {
6145        v.visit(this);
6146    }
6147}
6148
6149/***********************************************************
6150 * `x |= y`
6151 */
6152extern (C++) final class OrAssignExp : BinAssignExp
6153{
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
6159    override void accept(Visitor v)
6160    {
6161        v.visit(this);
6162    }
6163}
6164
6165/***********************************************************
6166 * `x ^= y`
6167 */
6168extern (C++) final class XorAssignExp : BinAssignExp
6169{
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
6175    override void accept(Visitor v)
6176    {
6177        v.visit(this);
6178    }
6179}
6180
6181/***********************************************************
6182 * `x ^^= y`
6183 */
6184extern (C++) final class PowAssignExp : BinAssignExp
6185{
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
6191    override void accept(Visitor v)
6192    {
6193        v.visit(this);
6194    }
6195}
6196
6197/***********************************************************
6198 * `x <<= y`
6199 */
6200extern (C++) final class ShlAssignExp : BinAssignExp
6201{
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
6207    override void accept(Visitor v)
6208    {
6209        v.visit(this);
6210    }
6211}
6212
6213/***********************************************************
6214 * `x >>= y`
6215 */
6216extern (C++) final class ShrAssignExp : BinAssignExp
6217{
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
6223    override void accept(Visitor v)
6224    {
6225        v.visit(this);
6226    }
6227}
6228
6229/***********************************************************
6230 * `x >>>= y`
6231 */
6232extern (C++) final class UshrAssignExp : BinAssignExp
6233{
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
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 */
6257extern (C++) class CatAssignExp : BinAssignExp
6258{
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
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
6269    override void accept(Visitor v)
6270    {
6271        v.visit(this);
6272    }
6273}
6274
6275/***********************************************************
6276 * The `~=` operator when appending a single element
6277 */
6278extern (C++) final class CatElemAssignExp : CatAssignExp
6279{
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
6286    override void accept(Visitor v)
6287    {
6288        v.visit(this);
6289    }
6290}
6291
6292/***********************************************************
6293 * The `~=` operator when appending a single `dchar`
6294 */
6295extern (C++) final class CatDcharAssignExp : CatAssignExp
6296{
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
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 */
6314extern (C++) final class AddExp : BinExp
6315{
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
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 */
6332extern (C++) final class MinExp : BinExp
6333{
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
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 */
6350extern (C++) final class CatExp : BinExp
6351{
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
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
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 */
6375extern (C++) final class MulExp : BinExp
6376{
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
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 */
6393extern (C++) final class DivExp : BinExp
6394{
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
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 */
6411extern (C++) final class ModExp : BinExp
6412{
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
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 */
6429extern (C++) final class PowExp : BinExp
6430{
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
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 */
6447extern (C++) final class ShlExp : BinExp
6448{
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
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 */
6465extern (C++) final class ShrExp : BinExp
6466{
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
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 */
6483extern (C++) final class UshrExp : BinExp
6484{
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
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 */
6501extern (C++) final class AndExp : BinExp
6502{
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
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 */
6519extern (C++) final class OrExp : BinExp
6520{
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
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 */
6537extern (C++) final class XorExp : BinExp
6538{
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
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 */
6556extern (C++) final class LogicalExp : BinExp
6557{
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
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 */
6578extern (C++) final class CmpExp : BinExp
6579{
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
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 */
6599extern (C++) final class InExp : BinExp
6600{
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
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 */
6617extern (C++) final class RemoveExp : BinExp
6618{
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
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 */
6638extern (C++) final class EqualExp : BinExp
6639{
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
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 */
6659extern (C++) final class IdentityExp : BinExp
6660{
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
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 */
6678extern (C++) final class CondExp : BinExp
6679{
6680    Expression econd;
6681
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
6688    override CondExp syntaxCopy()
6689    {
6690        return new CondExp(loc, econd.syntaxCopy(), e1.syntaxCopy(), e2.syntaxCopy());
6691    }
6692
6693    override bool isLvalue()
6694    {
6695        return e1.isLvalue() && e2.isLvalue();
6696    }
6697
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
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
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
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.
6799bool 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 */
6820extern (C++) class DefaultInitExp : Expression
6821{
6822    extern (D) this(const ref Loc loc, EXP op, int size)
6823    {
6824        super(loc, op, size);
6825    }
6826
6827    override void accept(Visitor v)
6828    {
6829        v.visit(this);
6830    }
6831}
6832
6833/***********************************************************
6834 * The `__FILE__` token as a default argument
6835 */
6836extern (C++) final class FileInitExp : DefaultInitExp
6837{
6838    extern (D) this(const ref Loc loc, EXP tok)
6839    {
6840        super(loc, tok, __traits(classInstanceSize, FileInitExp));
6841    }
6842
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
6858    override void accept(Visitor v)
6859    {
6860        v.visit(this);
6861    }
6862}
6863
6864/***********************************************************
6865 * The `__LINE__` token as a default argument
6866 */
6867extern (C++) final class LineInitExp : DefaultInitExp
6868{
6869    extern (D) this(const ref Loc loc)
6870    {
6871        super(loc, EXP.line, __traits(classInstanceSize, LineInitExp));
6872    }
6873
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
6881    override void accept(Visitor v)
6882    {
6883        v.visit(this);
6884    }
6885}
6886
6887/***********************************************************
6888 * The `__MODULE__` token as a default argument
6889 */
6890extern (C++) final class ModuleInitExp : DefaultInitExp
6891{
6892    extern (D) this(const ref Loc loc)
6893    {
6894        super(loc, EXP.moduleString, __traits(classInstanceSize, ModuleInitExp));
6895    }
6896
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
6906    override void accept(Visitor v)
6907    {
6908        v.visit(this);
6909    }
6910}
6911
6912/***********************************************************
6913 * The `__FUNCTION__` token as a default argument
6914 */
6915extern (C++) final class FuncInitExp : DefaultInitExp
6916{
6917    extern (D) this(const ref Loc loc)
6918    {
6919        super(loc, EXP.functionString, __traits(classInstanceSize, FuncInitExp));
6920    }
6921
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
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 */
6946extern (C++) final class PrettyFuncInitExp : DefaultInitExp
6947{
6948    extern (D) this(const ref Loc loc)
6949    {
6950        super(loc, EXP.prettyFunction, __traits(classInstanceSize, PrettyFuncInitExp));
6951    }
6952
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
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 */
6989extern (C++) final class ObjcClassReferenceExp : Expression
6990{
6991    ClassDeclaration classDeclaration;
6992
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
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 */
7011extern (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
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
7026    override GenericExp syntaxCopy()
7027    {
7028        return new GenericExp(loc, cntlExp.syntaxCopy(), Type.arraySyntaxCopy(types), Expression.arraySyntaxCopy(exps));
7029    }
7030
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 */
7046extern(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 */
7188private immutable ubyte[EXP.max + 1] exptab =
7189() {
7190    ubyte[EXP.max + 1] tab;
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
7200private enum EXPFLAGS : ubyte
7201{
7202    unary = 1,
7203    binary = 2,
7204    binaryAssign = 4,
7205}
7206
7207private 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
7216private 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
7227private 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