]> git.ipfire.org Git - thirdparty/gcc.git/blobdiff - gcc/d/dmd/expression.h
Merge dmd, druntime ceff48bf7d, phobos dcbfbd43a
[thirdparty/gcc.git] / gcc / d / dmd / expression.h
index dec3713b676b4802b443113af59f8d72e252254d..9cd73a965ba0d6bd58059fb98f9d8321fd41c6f4 100644 (file)
@@ -1,23 +1,24 @@
 
 /* Compiler implementation of the D programming language
- * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
+ * Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
  * written by Walter Bright
- * http://www.digitalmars.com
+ * https://www.digitalmars.com
  * Distributed under the Boost Software License, Version 1.0.
- * http://www.boost.org/LICENSE_1_0.txt
+ * https://www.boost.org/LICENSE_1_0.txt
  * https://github.com/dlang/dmd/blob/master/src/dmd/expression.h
  */
 
 #pragma once
 
 #include "ast_node.h"
-#include "complex_t.h"
 #include "globals.h"
 #include "arraytypes.h"
 #include "visitor.h"
 #include "tokens.h"
 
+#include "root/complex_t.h"
 #include "root/dcompat.h"
+#include "root/optional.h"
 
 class Type;
 class TypeVector;
@@ -37,17 +38,27 @@ class TemplateDeclaration;
 class ClassDeclaration;
 class OverloadSet;
 class StringExp;
-struct UnionExp;
+class InterpExp;
+class LoweredAssignExp;
 #ifdef IN_GCC
 typedef union tree_node Symbol;
 #else
 struct Symbol;          // back end symbol
 #endif
 
-void expandTuples(Expressions *exps);
-bool isTrivialExp(Expression *e);
-bool hasSideEffect(Expression *e, bool assumeImpureCalls = false);
-bool canThrow(Expression *e, FuncDeclaration *func, bool mustNotThrow);
+namespace dmd
+{
+    // in expressionsem.d
+    Expression *expressionSemantic(Expression *e, Scope *sc);
+    // in typesem.d
+    Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false);
+
+    // Entry point for CTFE.
+    // A compile-time result is required. Give an error if not possible
+    Expression *ctfeInterpret(Expression *e);
+    void expandTuples(Expressions *exps, Identifiers *names = nullptr);
+    Expression *optimize(Expression *exp, int result, bool keepLvalue = false);
+}
 
 typedef unsigned char OwnedBy;
 enum
@@ -57,6 +68,9 @@ enum
     OWNEDcache      // constant value cached for CTFE
 };
 
+#define WANTvalue  0 // default
+#define WANTexpand 1 // expand const/immutable variables if possible
+
 /**
  * Specifies how the checkModify deals with certain situations
  */
@@ -73,23 +87,19 @@ enum class ModifyFlags
 class Expression : public ASTNode
 {
 public:
-    TOK op;                     // to minimize use of dynamic_cast
-    unsigned char size;         // # of bytes in Expression so we can copy() it
-    unsigned char parens;       // if this is a parenthesized expression
     Type *type;                 // !=NULL means that semantic() has been run
     Loc loc;                    // file location
+    EXP op;                     // to minimize use of dynamic_cast
+    d_bool parens;              // if this is a parenthesized expression
 
+    size_t size() const;
     static void _init();
-    Expression *copy();
     virtual Expression *syntaxCopy();
 
     // kludge for template.isExpression()
-    DYNCAST dyncast() const { return DYNCAST_EXPRESSION; }
+    DYNCAST dyncast() const override final { return DYNCAST_EXPRESSION; }
 
-    const char *toChars() const;
-    void error(const char *format, ...) const;
-    void warning(const char *format, ...) const;
-    void deprecation(const char *format, ...) const;
+    const char *toChars() const override;
 
     virtual dinteger_t toInteger();
     virtual uinteger_t toUInteger();
@@ -97,29 +107,15 @@ public:
     virtual real_t toImaginary();
     virtual complex_t toComplex();
     virtual StringExp *toStringExp();
-    virtual TupleExp *toTupleExp();
     virtual bool isLvalue();
-    virtual Expression *toLvalue(Scope *sc, Expression *e);
-    virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
-    Expression *implicitCastTo(Scope *sc, Type *t);
-    MATCH implicitConvTo(Type *t);
-    Expression *castTo(Scope *sc, Type *t);
-    virtual Expression *resolveLoc(const Loc &loc, Scope *sc);
     virtual bool checkType();
     virtual bool checkValue();
-    bool checkDeprecated(Scope *sc, Dsymbol *s);
-    virtual Expression *addDtorHook(Scope *sc);
     Expression *addressOf();
     Expression *deref();
 
-    Expression *optimize(int result, bool keepLvalue = false);
-
-    // Entry point for CTFE.
-    // A compile-time result is required. Give an error if not possible
-    Expression *ctfeInterpret();
     int isConst();
-    virtual bool isBool(bool result);
-
+    virtual bool isIdentical(const Expression *e) const;
+    virtual Optional<bool> toBool();
     virtual bool hasCode()
     {
         return true;
@@ -137,6 +133,7 @@ public:
     SuperExp* isSuperExp();
     NullExp* isNullExp();
     StringExp* isStringExp();
+    InterpExp* isInterpExp();
     TupleExp* isTupleExp();
     ArrayLiteralExp* isArrayLiteralExp();
     AssocArrayLiteralExp* isAssocArrayLiteralExp();
@@ -202,6 +199,8 @@ public:
     ShrAssignExp* isShrAssignExp();
     UshrAssignExp* isUshrAssignExp();
     CatAssignExp* isCatAssignExp();
+    CatElemAssignExp* isCatElemAssignExp();
+    CatDcharAssignExp* isCatDcharAssignExp();
     AddExp* isAddExp();
     MinExp* isMinExp();
     CatExp* isCatExp();
@@ -229,73 +228,73 @@ public:
     FuncInitExp* isFuncInitExp();
     PrettyFuncInitExp* isPrettyFuncInitExp();
     ClassReferenceExp* isClassReferenceExp();
-    virtual BinAssignExp* isBinAssignExp();
+    ThrownExceptionExp* isThrownExceptionExp();
+    UnaExp* isUnaExp();
+    BinExp* isBinExp();
+    BinAssignExp* isBinAssignExp();
+    LoweredAssignExp* isLoweredAssignExp();
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class IntegerExp : public Expression
+class IntegerExp final : public Expression
 {
 public:
     dinteger_t value;
 
-    static IntegerExp *create(Loc loc, dinteger_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, dinteger_t value, Type *type);
-    bool equals(const RootObject *o) const;
-    dinteger_t toInteger();
-    real_t toReal();
-    real_t toImaginary();
-    complex_t toComplex();
-    bool isBool(bool result);
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    static IntegerExp *create(const Loc &loc, dinteger_t value, Type *type);
+    bool equals(const RootObject * const o) const override;
+    dinteger_t toInteger() override;
+    real_t toReal() override;
+    real_t toImaginary() override;
+    complex_t toComplex() override;
+    Optional<bool> toBool() override;
+    void accept(Visitor *v) override { v->visit(this); }
     dinteger_t getInteger() { return value; }
-    void setInteger(dinteger_t value);
     template<int v>
     static IntegerExp literal();
 };
 
-class ErrorExp : public Expression
+class ErrorExp final : public Expression
 {
 public:
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 
     static ErrorExp *errorexp; // handy shared value
 };
 
-class RealExp : public Expression
+class RealExp final : public Expression
 {
 public:
     real_t value;
 
-    static RealExp *create(Loc loc, real_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, real_t value, Type *type);
-    bool equals(const RootObject *o) const;
-    dinteger_t toInteger();
-    uinteger_t toUInteger();
-    real_t toReal();
-    real_t toImaginary();
-    complex_t toComplex();
-    bool isBool(bool result);
-    void accept(Visitor *v) { v->visit(this); }
+    static RealExp *create(const Loc &loc, real_t value, Type *type);
+    bool equals(const RootObject * const o) const override;
+    bool isIdentical(const Expression *e) const override;
+    dinteger_t toInteger() override;
+    uinteger_t toUInteger() override;
+    real_t toReal() override;
+    real_t toImaginary() override;
+    complex_t toComplex() override;
+    Optional<bool> toBool() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ComplexExp : public Expression
+class ComplexExp final : public Expression
 {
 public:
     complex_t value;
 
-    static ComplexExp *create(Loc loc, complex_t value, Type *type);
-    static void emplace(UnionExp *pue, Loc loc, complex_t value, Type *type);
-    bool equals(const RootObject *o) const;
-    dinteger_t toInteger();
-    uinteger_t toUInteger();
-    real_t toReal();
-    real_t toImaginary();
-    complex_t toComplex();
-    bool isBool(bool result);
-    void accept(Visitor *v) { v->visit(this); }
+    static ComplexExp *create(const Loc &loc, complex_t value, Type *type);
+    bool equals(const RootObject * const o) const override;
+    bool isIdentical(const Expression *e) const override;
+    dinteger_t toInteger() override;
+    uinteger_t toUInteger() override;
+    real_t toReal() override;
+    real_t toImaginary() override;
+    complex_t toComplex() override;
+    Optional<bool> toBool() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class IdentifierExp : public Expression
@@ -303,28 +302,26 @@ class IdentifierExp : public Expression
 public:
     Identifier *ident;
 
-    static IdentifierExp *create(Loc loc, Identifier *ident);
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    static IdentifierExp *create(const Loc &loc, Identifier *ident);
+    bool isLvalue() override final;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DollarExp : public IdentifierExp
+class DollarExp final : public IdentifierExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DsymbolExp : public Expression
+class DsymbolExp final : public Expression
 {
 public:
     Dsymbol *s;
-    bool hasOverloads;
+    d_bool hasOverloads;
 
-    DsymbolExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    DsymbolExp *syntaxCopy() override;
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class ThisExp : public Expression
@@ -332,59 +329,65 @@ class ThisExp : public Expression
 public:
     VarDeclaration *var;
 
-    ThisExp *syntaxCopy();
-    bool isBool(bool result);
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
+    ThisExp *syntaxCopy() override;
+    Optional<bool> toBool() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SuperExp : public ThisExp
+class SuperExp final : public ThisExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NullExp : public Expression
+class NullExp final : public Expression
 {
 public:
-    bool equals(const RootObject *o) const;
-    bool isBool(bool result);
-    StringExp *toStringExp();
-    void accept(Visitor *v) { v->visit(this); }
+    bool equals(const RootObject * const o) const override;
+    Optional<bool> toBool() override;
+    StringExp *toStringExp() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StringExp : public Expression
+class StringExp final : public Expression
 {
 public:
-    void *string;       // char, wchar, or dchar data
-    size_t len;         // number of chars, wchars, or dchars
-    unsigned char sz;   // 1: char, 2: wchar, 4: dchar
-    unsigned char committed;    // !=0 if type is committed
     utf8_t postfix;      // 'c', 'w', 'd'
     OwnedBy ownedByCtfe;
-
-    static StringExp *create(Loc loc, char *s);
-    static StringExp *create(Loc loc, void *s, size_t len);
-    static void emplace(UnionExp *pue, Loc loc, char *s);
-    static void emplace(UnionExp *pue, Loc loc, void *s, size_t len);
-    bool equals(const RootObject *o) const;
-    StringExp *toStringExp();
-    StringExp *toUTF8(Scope *sc);
-    bool isBool(bool result);
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    unsigned charAt(uinteger_t i) const;
-    void accept(Visitor *v) { v->visit(this); }
+    void *string;       // char, wchar, dchar, or long data
+    size_t len;         // number of chars, wchars, or dchars
+    unsigned char sz;   // 1: char, 2: wchar, 4: dchar
+    d_bool committed;   // if type is committed
+    d_bool hexString;   // if string is parsed from a hex string literal
+
+    static StringExp *create(const Loc &loc, const char *s);
+    static StringExp *create(const Loc &loc, const void *s, d_size_t len);
+    bool equals(const RootObject * const o) const override;
+    char32_t getCodeUnit(d_size_t i) const;
+    dinteger_t getIndex(d_size_t i) const;
+    StringExp *toStringExp() override;
+    Optional<bool> toBool() override;
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
     size_t numberOfCodeUnits(int tynto = 0) const;
     void writeTo(void* dest, bool zero, int tyto = 0) const;
 };
 
+class InterpExp final : public Expression
+{
+public:
+    utf8_t postfix;   // 'c', 'w', 'd'
+    OwnedBy ownedByCtfe;
+    void* interpolatedSet;
+
+    void accept(Visitor* v) override { v->visit(this); }
+};
+
 // Tuple
 
-class TupleExp : public Expression
+class TupleExp final : public Expression
 {
 public:
     Expression *e0;     // side-effect part
@@ -397,55 +400,60 @@ public:
      */
     Expressions *exps;
 
-    static TupleExp *create(Loc loc, Expressions *exps);
-    TupleExp *toTupleExp();
-    TupleExp *syntaxCopy();
-    bool equals(const RootObject *o) const;
+    static TupleExp *create(const Loc &loc, Expressions *exps);
+    TupleExp *syntaxCopy() override;
+    bool equals(const RootObject * const o) const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ArrayLiteralExp : public Expression
+class ArrayLiteralExp final : public Expression
 {
 public:
+    OwnedBy ownedByCtfe;
+    d_bool onstack;
     Expression *basis;
     Expressions *elements;
-    OwnedBy ownedByCtfe;
 
-    static ArrayLiteralExp *create(Loc loc, Expressions *elements);
-    static void emplace(UnionExp *pue, Loc loc, Expressions *elements);
-    ArrayLiteralExp *syntaxCopy();
-    bool equals(const RootObject *o) const;
-    Expression *getElement(d_size_t i); // use opIndex instead
-    Expression *opIndex(d_size_t i);
-    bool isBool(bool result);
-    StringExp *toStringExp();
+    static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
+    ArrayLiteralExp *syntaxCopy() override;
+    bool equals(const RootObject * const o) const override;
+    Expression *getElement(d_size_t i);
+    Optional<bool> toBool() override;
+    StringExp *toStringExp() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AssocArrayLiteralExp : public Expression
+class AssocArrayLiteralExp final : public Expression
 {
 public:
+    OwnedBy ownedByCtfe;
     Expressions *keys;
     Expressions *values;
-    OwnedBy ownedByCtfe;
+    Expression* lowering;
 
-    bool equals(const RootObject *o) const;
-    AssocArrayLiteralExp *syntaxCopy();
-    bool isBool(bool result);
+    bool equals(const RootObject * const o) const override;
+    AssocArrayLiteralExp *syntaxCopy() override;
+    Optional<bool> toBool() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StructLiteralExp : public Expression
+class StructLiteralExp final : public Expression
 {
 public:
     StructDeclaration *sd;      // which aggregate this is for
     Expressions *elements;      // parallels sd->fields[] with NULL entries for fields to skip
     Type *stype;                // final type of result (can be different from sd's type)
 
-    Symbol *sym;                // back end symbol to initialize with literal
+    union
+    {
+        Symbol *sym;                // back end symbol to initialize with literal (used as a Symbol*)
+
+        // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
+        StructLiteralExp *inlinecopy;
+    };
 
     /** pointer to the origin instance of the expression.
      * once a new expression is created, origin is set to 'this'.
@@ -454,98 +462,92 @@ public:
      */
     StructLiteralExp *origin;
 
-    // those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
-    StructLiteralExp *inlinecopy;
 
     /** anytime when recursive function is calling, 'stageflags' marks with bit flag of
      * current stage and unmarks before return from this function.
      * 'inlinecopy' uses similar 'stageflags' and from multiple evaluation 'doInline'
      * (with infinite recursion) of this expression.
      */
-    int stageflags;
+    uint8_t stageflags;
 
-    bool useStaticInit;         // if this is true, use the StructDeclaration's init symbol
-    bool isOriginal;            // used when moving instances to indicate `this is this.origin`
+    d_bool useStaticInit;         // if this is true, use the StructDeclaration's init symbol
+    d_bool isOriginal;            // used when moving instances to indicate `this is this.origin`
     OwnedBy ownedByCtfe;
 
-    static StructLiteralExp *create(Loc loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
-    bool equals(const RootObject *o) const;
-    StructLiteralExp *syntaxCopy();
-    Expression *getField(Type *type, unsigned offset);
-    int getFieldIndex(Type *type, unsigned offset);
-    Expression *addDtorHook(Scope *sc);
-    Expression *toLvalue(Scope *sc, Expression *e);
+    static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
+    bool equals(const RootObject * const o) const override;
+    StructLiteralExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeExp : public Expression
+class TypeExp final : public Expression
 {
 public:
-    TypeExp *syntaxCopy();
-    bool checkType();
-    bool checkValue();
-    void accept(Visitor *v) { v->visit(this); }
+    TypeExp *syntaxCopy() override;
+    bool checkType() override;
+    bool checkValue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ScopeExp : public Expression
+class ScopeExp final : public Expression
 {
 public:
     ScopeDsymbol *sds;
 
-    ScopeExp *syntaxCopy();
-    bool checkType();
-    bool checkValue();
-    void accept(Visitor *v) { v->visit(this); }
+    ScopeExp *syntaxCopy() override;
+    bool checkType() override;
+    bool checkValue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TemplateExp : public Expression
+class TemplateExp final : public Expression
 {
 public:
     TemplateDeclaration *td;
     FuncDeclaration *fd;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    bool checkType();
-    bool checkValue();
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    bool checkType() override;
+    bool checkValue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NewExp : public Expression
+class NewExp final : public Expression
 {
 public:
-    /* thisexp.new(newargs) newtype(arguments)
+    /* newtype(arguments)
      */
     Expression *thisexp;        // if !NULL, 'this' for class being allocated
-    Expressions *newargs;       // Array of Expression's to call new operator
     Type *newtype;
     Expressions *arguments;     // Array of Expression's
+    Identifiers *names;         // Array of names corresponding to expressions
 
     Expression *argprefix;      // expression to be evaluated just before arguments[]
 
     CtorDeclaration *member;    // constructor function
-    bool onstack;               // allocate on stack
-    bool thrownew;              // this NewExp is the expression of a ThrowStatement
+    d_bool onstack;               // allocate on stack
+    d_bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
-    static NewExp *create(Loc loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
-    NewExp *syntaxCopy();
+    Expression *lowering;       // lowered druntime hook: `_d_newclass`
 
-    void accept(Visitor *v) { v->visit(this); }
+    static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
+    NewExp *syntaxCopy() override;
+
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NewAnonClassExp : public Expression
+class NewAnonClassExp final : public Expression
 {
 public:
-    /* thisexp.new(newargs) class baseclasses { } (arguments)
+    /* class baseclasses { } (arguments)
      */
     Expression *thisexp;        // if !NULL, 'this' for class being allocated
-    Expressions *newargs;       // Array of Expression's to call new operator
     ClassDeclaration *cd;       // class being instantiated
     Expressions *arguments;     // Array of Expression's to call class constructor
 
-    NewAnonClassExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    NewAnonClassExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class SymbolExp : public Expression
@@ -553,66 +555,63 @@ class SymbolExp : public Expression
 public:
     Declaration *var;
     Dsymbol *originalScope;
-    bool hasOverloads;
+    d_bool hasOverloads;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Offset from symbol
 
-class SymOffExp : public SymbolExp
+class SymOffExp final : public SymbolExp
 {
 public:
     dinteger_t offset;
 
-    bool isBool(bool result);
+    Optional<bool> toBool() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Variable
 
-class VarExp : public SymbolExp
+class VarExp final : public SymbolExp
 {
 public:
-    bool delegateWasExtracted;
-    static VarExp *create(Loc loc, Declaration *var, bool hasOverloads = true);
-    bool equals(const RootObject *o) const;
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    d_bool delegateWasExtracted;
+    static VarExp *create(const Loc &loc, Declaration *var, bool hasOverloads = true);
+    bool equals(const RootObject * const o) const override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Overload Set
 
-class OverExp : public Expression
+class OverExp final : public Expression
 {
 public:
     OverloadSet *vars;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Function/Delegate literal
 
-class FuncExp : public Expression
+class FuncExp final : public Expression
 {
 public:
     FuncLiteralDeclaration *fd;
     TemplateDeclaration *td;
     TOK tok;
 
-    bool equals(const RootObject *o) const;
-    FuncExp *syntaxCopy();
-    const char *toChars() const;
-    bool checkType();
-    bool checkValue();
+    bool equals(const RootObject * const o) const override;
+    FuncExp *syntaxCopy() override;
+    const char *toChars() const override;
+    bool checkType() override;
+    bool checkValue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Declaration of a symbol
@@ -620,44 +619,44 @@ public:
 // D grammar allows declarations only as statements. However in AST representation
 // it can be part of any expression. This is used, for example, during internal
 // syntax re-writes to inject hidden symbols.
-class DeclarationExp : public Expression
+class DeclarationExp final : public Expression
 {
 public:
     Dsymbol *declaration;
 
-    DeclarationExp *syntaxCopy();
+    DeclarationExp *syntaxCopy() override;
 
-    bool hasCode();
+    bool hasCode() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeidExp : public Expression
+class TypeidExp final : public Expression
 {
 public:
     RootObject *obj;
 
-    TypeidExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    TypeidExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TraitsExp : public Expression
+class TraitsExp final : public Expression
 {
 public:
     Identifier *ident;
     Objects *args;
 
-    TraitsExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    TraitsExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class HaltExp : public Expression
+class HaltExp final : public Expression
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class IsExp : public Expression
+class IsExp final : public Expression
 {
 public:
     /* is(targ id tok tspec)
@@ -670,8 +669,8 @@ public:
     TOK tok;       // ':' or '=='
     TOK tok2;      // 'struct', 'union', etc.
 
-    IsExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    IsExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
@@ -680,13 +679,10 @@ class UnaExp : public Expression
 {
 public:
     Expression *e1;
-    Type *att1; // Save alias this type to detect recursion
 
-    UnaExp *syntaxCopy();
-    Expression *incompatibleTypes();
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
+    UnaExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class BinExp : public Expression
@@ -698,334 +694,326 @@ public:
     Type *att1; // Save alias this type to detect recursion
     Type *att2; // Save alias this type to detect recursion
 
-    BinExp *syntaxCopy();
-    Expression *incompatibleTypes();
-
-    Expression *reorderSettingAAElem(Scope *sc);
+    BinExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class BinAssignExp : public BinExp
 {
 public:
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *ex);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    BinAssignExp* isBinAssignExp();
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override final;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
 
-class MixinExp : public UnaExp
+class MixinExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ImportExp : public UnaExp
+class ImportExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AssertExp : public UnaExp
+class AssertExp final : public UnaExp
 {
 public:
     Expression *msg;
 
-    AssertExp *syntaxCopy();
+    AssertExp *syntaxCopy() override;
+
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
+class ThrowExp final : public UnaExp
+{
+public:
+    ThrowExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotIdExp : public UnaExp
+class DotIdExp final : public UnaExp
 {
 public:
     Identifier *ident;
-    bool noderef;       // true if the result of the expression will never be dereferenced
-    bool wantsym;       // do not replace Symbol with its initializer during semantic()
+    d_bool noderef;       // true if the result of the expression will never be dereferenced
+    d_bool wantsym;       // do not replace Symbol with its initializer during semantic()
+    d_bool arrow;         // ImportC: if -> instead of .
 
-    static DotIdExp *create(Loc loc, Expression *e, Identifier *ident);
-    void accept(Visitor *v) { v->visit(this); }
+    static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident);
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotTemplateExp : public UnaExp
+class DotTemplateExp final : public UnaExp
 {
 public:
     TemplateDeclaration *td;
 
-    bool checkType();
-    bool checkValue();
-    void accept(Visitor *v) { v->visit(this); }
+    bool checkType() override;
+    bool checkValue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotVarExp : public UnaExp
+class DotVarExp final : public UnaExp
 {
 public:
     Declaration *var;
-    bool hasOverloads;
+    d_bool hasOverloads;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotTemplateInstanceExp : public UnaExp
+class DotTemplateInstanceExp final : public UnaExp
 {
 public:
     TemplateInstance *ti;
 
-    DotTemplateInstanceExp *syntaxCopy();
-    bool findTempDecl(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    DotTemplateInstanceExp *syntaxCopy() override;
+    bool checkType() override;
+    bool checkValue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DelegateExp : public UnaExp
+class DelegateExp final : public UnaExp
 {
 public:
     FuncDeclaration *func;
-    bool hasOverloads;
+    d_bool hasOverloads;
     VarDeclaration *vthis2;  // container for multi-context
 
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotTypeExp : public UnaExp
+class DotTypeExp final : public UnaExp
 {
 public:
     Dsymbol *sym;               // symbol that represents a type
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CallExp : public UnaExp
+class CallExp final : public UnaExp
 {
 public:
     Expressions *arguments;     // function arguments
+    Identifiers *names;
     FuncDeclaration *f;         // symbol to call
-    bool directcall;            // true if a virtual call is devirtualized
-    bool inDebugStatement;      // true if this was in a debug statement
-    bool ignoreAttributes;      // don't enforce attributes (e.g. call @gc function in @nogc code)
+    d_bool directcall;            // true if a virtual call is devirtualized
+    d_bool inDebugStatement;      // true if this was in a debug statement
+    d_bool ignoreAttributes;      // don't enforce attributes (e.g. call @gc function in @nogc code)
+    d_bool isUfcsRewrite;       // the first argument was pushed in here by a UFCS rewrite
     VarDeclaration *vthis2;     // container for multi-context
 
-    static CallExp *create(Loc loc, Expression *e, Expressions *exps);
-    static CallExp *create(Loc loc, Expression *e);
-    static CallExp *create(Loc loc, Expression *e, Expression *earg1);
-    static CallExp *create(Loc loc, FuncDeclaration *fd, Expression *earg1);
+    static CallExp *create(const Loc &loc, Expression *e, Expressions *exps);
+    static CallExp *create(const Loc &loc, Expression *e);
+    static CallExp *create(const Loc &loc, Expression *e, Expression *earg1);
+    static CallExp *create(const Loc &loc, FuncDeclaration *fd, Expression *earg1);
 
-    CallExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *addDtorHook(Scope *sc);
+    CallExp *syntaxCopy() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AddrExp : public UnaExp
+class AddrExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PtrExp : public UnaExp
+class PtrExp final : public UnaExp
 {
 public:
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NegExp : public UnaExp
+class NegExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class UAddExp : public UnaExp
+class UAddExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ComExp : public UnaExp
+class ComExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NotExp : public UnaExp
+class NotExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DeleteExp : public UnaExp
+class DeleteExp final : public UnaExp
 {
 public:
-    bool isRAII;
-    void accept(Visitor *v) { v->visit(this); }
+    d_bool isRAII;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CastExp : public UnaExp
+class CastExp final : public UnaExp
 {
 public:
     // Possible to cast to one type while painting to another type
     Type *to;                   // type to cast to
     unsigned char mod;          // MODxxxxx
 
-    CastExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
+    CastExp *syntaxCopy() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VectorExp : public UnaExp
+class VectorExp final : public UnaExp
 {
 public:
     TypeVector *to;             // the target vector type before semantic()
     unsigned dim;               // number of elements in the vector
     OwnedBy ownedByCtfe;
 
-    static VectorExp *create(Loc loc, Expression *e, Type *t);
-    static void emplace(UnionExp *pue, Loc loc, Expression *e, Type *t);
-    VectorExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    static VectorExp *create(const Loc &loc, Expression *e, Type *t);
+    VectorExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VectorArrayExp : public UnaExp
+class VectorArrayExp final : public UnaExp
 {
 public:
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SliceExp : public UnaExp
+class SliceExp final : public UnaExp
 {
 public:
     Expression *upr;            // NULL if implicit 0
     Expression *lwr;            // NULL if implicit [length - 1]
     VarDeclaration *lengthVar;
-    bool upperIsInBounds;       // true if upr <= e1.length
-    bool lowerIsLessThanUpper;  // true if lwr <= upr
-    bool arrayop;               // an array operation, rather than a slice
 
-    SliceExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    bool isBool(bool result);
+    bool upperIsInBounds() const; // true if upr <= e1.length
+    bool upperIsInBounds(bool v);
+    bool lowerIsLessThanUpper() const; // true if lwr <= upr
+    bool lowerIsLessThanUpper(bool v);
+    bool arrayop() const; // an array operation, rather than a slice
+    bool arrayop(bool v);
+private:
+    uint8_t bitFields;
+
+public:
+    SliceExp *syntaxCopy() override;
+    bool isLvalue() override;
+    Optional<bool> toBool() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ArrayLengthExp : public UnaExp
+class ArrayLengthExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class IntervalExp : public Expression
+class IntervalExp final : public Expression
 {
 public:
     Expression *lwr;
     Expression *upr;
 
-    IntervalExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    IntervalExp *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DelegatePtrExp : public UnaExp
+class DelegatePtrExp final : public UnaExp
 {
 public:
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DelegateFuncptrExp : public UnaExp
+class DelegateFuncptrExp final : public UnaExp
 {
 public:
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // e1[a0,a1,a2,a3,...]
 
-class ArrayExp : public UnaExp
+class ArrayExp final : public UnaExp
 {
 public:
     Expressions *arguments;             // Array of Expression's
     size_t currentDimension;            // for opDollar
     VarDeclaration *lengthVar;
 
-    ArrayExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
+    ArrayExp *syntaxCopy() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
 
-class DotExp : public BinExp
+class DotExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CommaExp : public BinExp
+class CommaExp final : public BinExp
 {
 public:
-    bool isGenerated;
-    bool allowCommaExp;
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    bool isBool(bool result);
-    Expression *addDtorHook(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    d_bool isGenerated;
+    d_bool allowCommaExp;
+    bool isLvalue() override;
+    Optional<bool> toBool() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class IndexExp : public BinExp
+class IndexExp final : public BinExp
 {
 public:
     VarDeclaration *lengthVar;
-    bool modifiable;
-    bool indexIsInBounds;       // true if 0 <= e2 && e2 <= e1.length - 1
+    d_bool modifiable;
+    d_bool indexIsInBounds;       // true if 0 <= e2 && e2 <= e1.length - 1
 
-    IndexExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    IndexExp *syntaxCopy() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* For both i++ and i--
  */
-class PostExp : public BinExp
+class PostExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* For both ++i and --i
  */
-class PreExp : public UnaExp
+class PreExp final : public UnaExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 enum class MemorySet
@@ -1040,245 +1028,266 @@ class AssignExp : public BinExp
 public:
     MemorySet memset;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *ex);
+    bool isLvalue() override final;
+
+    void accept(Visitor *v) override { v->visit(this); }
+};
 
-    void accept(Visitor *v) { v->visit(this); }
+class ConstructExp final : public AssignExp
+{
+public:
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ConstructExp : public AssignExp
+class LoweredAssignExp final : public AssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    Expression *lowering;
+
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class BlitExp : public AssignExp
+class BlitExp final : public AssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AddAssignExp : public BinAssignExp
+class AddAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class MinAssignExp : public BinAssignExp
+class MinAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class MulAssignExp : public BinAssignExp
+class MulAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DivAssignExp : public BinAssignExp
+class DivAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ModAssignExp : public BinAssignExp
+class ModAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AndAssignExp : public BinAssignExp
+class AndAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class OrAssignExp : public BinAssignExp
+class OrAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class XorAssignExp : public BinAssignExp
+class XorAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PowAssignExp : public BinAssignExp
+class PowAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ShlAssignExp : public BinAssignExp
+class ShlAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ShrAssignExp : public BinAssignExp
+class ShrAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class UshrAssignExp : public BinAssignExp
+class UshrAssignExp final : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class CatAssignExp : public BinAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    Expression *lowering;   // lowered druntime hook `_d_arrayappend{cTX,T}`
+
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AddExp : public BinExp
+class CatElemAssignExp final : public CatAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class MinExp : public BinExp
+class CatDcharAssignExp final : public CatAssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CatExp : public BinExp
+class AddExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class MulExp : public BinExp
+class MinExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DivExp : public BinExp
+class CatExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    Expression *lowering;  // call to druntime hook `_d_arraycatnTX`
+
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ModExp : public BinExp
+class MulExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PowExp : public BinExp
+class DivExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ShlExp : public BinExp
+class ModExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ShrExp : public BinExp
+class PowExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class UshrExp : public BinExp
+class ShlExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AndExp : public BinExp
+class ShrExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class OrExp : public BinExp
+class UshrExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class XorExp : public BinExp
+class AndExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class LogicalExp : public BinExp
+class OrExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CmpExp : public BinExp
+class XorExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class InExp : public BinExp
+class LogicalExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class RemoveExp : public BinExp
+class CmpExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
+class InExp final : public BinExp
+{
+public:
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
+class RemoveExp final : public BinExp
+{
+public:
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // == and !=
 
-class EqualExp : public BinExp
+class EqualExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // is and !is
 
-class IdentityExp : public BinExp
+class IdentityExp final : public BinExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
 
-class CondExp : public BinExp
+class CondExp final : public BinExp
 {
 public:
     Expression *econd;
 
-    CondExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void hookDtors(Scope *sc);
+    CondExp *syntaxCopy() override;
+    bool isLvalue() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class GenericExp : Expression
+class GenericExp final : Expression
 {
-    Expression cntlExp;
+    Expression *cntlExp;
     Types *types;
     Expressions *exps;
 
-    GenericExp *syntaxCopy();
+    GenericExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
@@ -1286,106 +1295,45 @@ class GenericExp : Expression
 class DefaultInitExp : public Expression
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class FileInitExp : public DefaultInitExp
+class FileInitExp final : public DefaultInitExp
 {
 public:
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class LineInitExp : public DefaultInitExp
+class LineInitExp final : public DefaultInitExp
 {
 public:
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ModuleInitExp : public DefaultInitExp
+class ModuleInitExp final : public DefaultInitExp
 {
 public:
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class FuncInitExp : public DefaultInitExp
+class FuncInitExp final : public DefaultInitExp
 {
 public:
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PrettyFuncInitExp : public DefaultInitExp
+class PrettyFuncInitExp final : public DefaultInitExp
 {
 public:
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
-};
-
-/****************************************************************/
-
-/* A type meant as a union of all the Expression types,
- * to serve essentially as a Variant that will sit on the stack
- * during CTFE to reduce memory consumption.
- */
-struct UnionExp
-{
-    UnionExp() { }  // yes, default constructor does nothing
-
-    UnionExp(Expression *e)
-    {
-        memcpy(this, (void *)e, e->size);
-    }
-
-    /* Extract pointer to Expression
-     */
-    Expression *exp() { return (Expression *)&u; }
-
-    /* Convert to an allocated Expression
-     */
-    Expression *copy();
-
-private:
-    // Ensure that the union is suitably aligned.
-#if defined(__GNUC__) || defined(__clang__)
-    __attribute__((aligned(8)))
-#elif defined(_MSC_VER)
-    __declspec(align(8))
-#elif defined(__DMC__)
-    #pragma pack(8)
-#endif
-    union
-    {
-        char exp       [sizeof(Expression)];
-        char integerexp[sizeof(IntegerExp)];
-        char errorexp  [sizeof(ErrorExp)];
-        char realexp   [sizeof(RealExp)];
-        char complexexp[sizeof(ComplexExp)];
-        char symoffexp [sizeof(SymOffExp)];
-        char stringexp [sizeof(StringExp)];
-        char arrayliteralexp [sizeof(ArrayLiteralExp)];
-        char assocarrayliteralexp [sizeof(AssocArrayLiteralExp)];
-        char structliteralexp [sizeof(StructLiteralExp)];
-        char nullexp   [sizeof(NullExp)];
-        char dotvarexp [sizeof(DotVarExp)];
-        char addrexp   [sizeof(AddrExp)];
-        char indexexp  [sizeof(IndexExp)];
-        char sliceexp  [sizeof(SliceExp)];
-        char vectorexp [sizeof(VectorExp)];
-    } u;
-#if defined(__DMC__)
-    #pragma pack()
-#endif
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
 
-class ObjcClassReferenceExp : public Expression
+class ObjcClassReferenceExp final : public Expression
 {
 public:
     ClassDeclaration* classDeclaration;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };