diff mbox series

[committed] d: Merge upstream dmd 4d07f22f2, druntime f89da313, phobos d46814c86.

Message ID 20220527191017.2663556-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd 4d07f22f2, druntime f89da313, phobos d46814c86. | expand

Commit Message

Iain Buclaw May 27, 2022, 7:10 p.m. UTC
Hi,

This patch merges the D front-end with upstream dmd 4d07f22f2, and
the standard library with druntime f89da313 and phobos d46814c86.

D front-end changes:

    - `scope' semantics are now enforced in `@safe' code on pointers to
      stack memory, but only as deprecation warnings.
    - Overriding virtual functions are now marked with the `override'
      and `final' in the generated headers of `-fdump-c++-spec='.
    - `-fpreview=fiximmmutableconv` has been added that disallows
      implicitly converting a return value with indirections to
      immutable if it determines the result must be unique.

D runtime changes:

    - Posix (excluding Darwin): Switch default GC signals from SIGUSR1/2
      to SIGRTMIN/SIGRTMIN+1

Phobos changes:

    - Import latest bug fixes to mainline.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, and
committed to mainline.

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 4d07f22f2
	* d-lang.cc (d_handle_option): Handle OPT_fpreview_fiximmutableconv.
	* lang.opt (fpreview=fiximmutableconv): New option.
	* runtime.def (ARRAYAPPENDT): Remove.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime f89da313.
	* src/MERGE: Merge upstream phobos d46814c86.

Signed-off-by: Iain Buclaw <ibuclaw@gdcproject.org>
---
 gcc/d/d-lang.cc                               |   5 +
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/aggregate.h                         |  80 +-
 gcc/d/dmd/aliasthis.h                         |  10 +-
 gcc/d/dmd/attrib.h                            | 212 ++---
 gcc/d/dmd/cond.h                              |  34 +-
 gcc/d/dmd/cparse.d                            | 156 +++-
 gcc/d/dmd/ctfe.h                              |  20 +-
 gcc/d/dmd/dcast.d                             |  21 +-
 gcc/d/dmd/declaration.h                       | 396 +++++-----
 gcc/d/dmd/dmodule.d                           |  33 +-
 gcc/d/dmd/dsymbol.d                           |  23 +-
 gcc/d/dmd/dsymbol.h                           |  64 +-
 gcc/d/dmd/dsymbolsem.d                        |  20 +-
 gcc/d/dmd/dtemplate.d                         |   2 +-
 gcc/d/dmd/dtoh.d                              |  28 +-
 gcc/d/dmd/enum.h                              |  34 +-
 gcc/d/dmd/escape.d                            | 231 ++++--
 gcc/d/dmd/expression.d                        |  22 +-
 gcc/d/dmd/expression.h                        | 732 +++++++++---------
 gcc/d/dmd/expressionsem.d                     |  59 +-
 gcc/d/dmd/func.d                              | 102 ++-
 gcc/d/dmd/globals.d                           |   3 +-
 gcc/d/dmd/globals.h                           |   4 +-
 gcc/d/dmd/hdrgen.d                            |  18 +-
 gcc/d/dmd/id.d                                |   2 +
 gcc/d/dmd/identifier.h                        |   7 +-
 gcc/d/dmd/import.h                            |  26 +-
 gcc/d/dmd/init.d                              |   2 +-
 gcc/d/dmd/init.h                              |  30 +-
 gcc/d/dmd/initsem.d                           |   5 +-
 gcc/d/dmd/lexer.d                             |  60 +-
 gcc/d/dmd/module.h                            |  27 +-
 gcc/d/dmd/mtype.d                             | 109 +--
 gcc/d/dmd/mtype.h                             | 540 +++++++------
 gcc/d/dmd/nspace.h                            |  20 +-
 gcc/d/dmd/parsetimevisitor.d                  |   4 +
 gcc/d/dmd/root/object.h                       |   4 +-
 gcc/d/dmd/safe.d                              |  19 +-
 gcc/d/dmd/sideeffect.d                        |  29 +-
 gcc/d/dmd/statement.d                         |   2 +-
 gcc/d/dmd/statement.h                         | 318 ++++----
 gcc/d/dmd/statementsem.d                      |  13 +-
 gcc/d/dmd/staticassert.h                      |  12 +-
 gcc/d/dmd/template.h                          | 154 ++--
 gcc/d/dmd/transitivevisitor.d                 |  14 +-
 gcc/d/dmd/typesem.d                           |  20 +-
 gcc/d/dmd/version.h                           |  28 +-
 gcc/d/dmd/visitor.h                           |   6 +
 gcc/d/lang.opt                                |   4 +
 gcc/d/runtime.def                             |   4 -
 .../compilable/dtoh_ClassDeclaration.d        |  10 +-
 .../compilable/dtoh_TemplateDeclaration.d     |   2 +-
 gcc/testsuite/gdc.test/compilable/test22865.d |  35 +
 .../fail_compilation/dip1000_deprecation.d    |  59 ++
 .../gdc.test/fail_compilation/dip25.d         |   2 +-
 .../gdc.test/fail_compilation/fail12390.d     |   3 +-
 .../gdc.test/fail_compilation/fail22351.d     |  20 +
 .../gdc.test/fail_compilation/fail23135.d     |  17 +
 .../gdc.test/fail_compilation/fail_scope.d    |   2 +-
 .../gdc.test/fail_compilation/fix22108.d      |  13 +
 .../gdc.test/fail_compilation/fix23138.d      |  16 +
 .../gdc.test/fail_compilation/test15660.d     |   2 +-
 .../gdc.test/fail_compilation/test18484.d     |   2 +-
 .../gdc.test/fail_compilation/test20881.d     |   2 +-
 .../runnable_cxx/extra-files/test22351.cpp    |  46 ++
 .../runnable_cxx/extra-files/test23135.cpp    |  52 ++
 .../gdc.test/runnable_cxx/test22351.d         |  55 ++
 .../gdc.test/runnable_cxx/test23135.d         |  38 +
 libphobos/libdruntime/MERGE                   |   2 +-
 .../core/internal/array/appending.d           |  21 +-
 libphobos/libdruntime/core/memory.d           |   2 +-
 libphobos/libdruntime/core/thread/fiber.d     |   7 +-
 libphobos/libdruntime/core/thread/osthread.d  |  21 +-
 .../libdruntime/core/thread/threadbase.d      |   4 +-
 libphobos/libdruntime/object.d                |  25 +-
 libphobos/libdruntime/rt/arrayassign.d        |  72 --
 libphobos/libdruntime/rt/lifetime.d           |  39 -
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/package.d                   |   2 +
 libphobos/src/std/process.d                   |   4 +-
 libphobos/src/std/utf.d                       |   4 +-
 82 files changed, 2497 insertions(+), 1854 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/compilable/test22865.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22351.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail23135.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fix22108.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fix23138.d
 create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp
 create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp
 create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/test22351.d
 create mode 100644 gcc/testsuite/gdc.test/runnable_cxx/test23135.d
diff mbox series

Patch

diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index d1f4959f119..ef0fe0b8adb 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -581,6 +581,7 @@  d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.rvalueRefParam = FeatureState::enabled;
       global.params.inclusiveInContracts = value;
       global.params.shortenedMethods = value;
+      global.params.fixImmutableConv = value;
       break;
 
     case OPT_fpreview_bitfields:
@@ -615,6 +616,10 @@  d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.fixAliasThis = value;
       break;
 
+    case OPT_fpreview_fiximmutableconv:
+      global.params.fixImmutableConv = value;
+      break;
+
     case OPT_fpreview_in:
       global.params.previewIn = value;
       break;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index b4d42ec6d2b..c37da0585d9 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-a6c5224b2d6b61fa3856aa8a3369581f7c949b68
+4d07f22f29d098869ad937f0499d8895df089a71
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index bdeb38e8b45..f27ca0769c9 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -120,20 +120,20 @@  public:
     Sizeok sizeok;              // set when structsize contains valid data
 
     virtual Scope *newScope(Scope *sc);
-    void setScope(Scope *sc);
+    void setScope(Scope *sc) override final;
     size_t nonHiddenFields();
     bool determineSize(const Loc &loc);
     virtual void finalizeSize() = 0;
-    uinteger_t size(const Loc &loc);
+    uinteger_t size(const Loc &loc) override final;
     bool fill(const Loc &loc, Expressions *elements, bool ctorinit);
-    Type *getType();
-    bool isDeprecated() const;         // is aggregate deprecated?
+    Type *getType() override final;
+    bool isDeprecated() const override final; // is aggregate deprecated?
     void setDeprecated();
     bool isNested() const;
-    bool isExport() const;
+    bool isExport() const override final;
     Dsymbol *searchCtor();
 
-    Visibility visible();
+    Visibility visible() override final;
 
     // 'this' type
     Type *handleType() { return type; }
@@ -143,8 +143,8 @@  public:
     // Back end
     void *sinit;
 
-    AggregateDeclaration *isAggregateDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    AggregateDeclaration *isAggregateDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 struct StructFlags
@@ -186,28 +186,28 @@  public:
     TypeTuple *argTypes;
 
     static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
-    StructDeclaration *syntaxCopy(Dsymbol *s);
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    const char *kind() const;
-    void finalizeSize();
+    StructDeclaration *syntaxCopy(Dsymbol *s) override;
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
+    const char *kind() const override;
+    void finalizeSize() override final;
     bool isPOD();
 
-    StructDeclaration *isStructDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    StructDeclaration *isStructDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 
     unsigned numArgTypes() const;
     Type *argType(unsigned index);
     bool hasRegularCtor(bool checkDisabled = false);
 };
 
-class UnionDeclaration : public StructDeclaration
+class UnionDeclaration final : public StructDeclaration
 {
 public:
-    UnionDeclaration *syntaxCopy(Dsymbol *s);
-    const char *kind() const;
+    UnionDeclaration *syntaxCopy(Dsymbol *s) override;
+    const char *kind() const override;
 
-    UnionDeclaration *isUnionDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    UnionDeclaration *isUnionDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 struct BaseClass
@@ -279,9 +279,9 @@  public:
     Symbol *cpp_type_info_ptr_sym;      // cached instance of class Id.cpp_type_info_ptr
 
     static ClassDeclaration *create(const Loc &loc, Identifier *id, BaseClasses *baseclasses, Dsymbols *members, bool inObject);
-    const char *toPrettyChars(bool QualifyTypes = false);
-    ClassDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
+    const char *toPrettyChars(bool QualifyTypes = false) override;
+    ClassDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
     bool isBaseOf2(ClassDeclaration *cd);
 
     #define OFFSET_RUNTIME 0x76543210
@@ -289,9 +289,9 @@  public:
     virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
 
     bool isBaseInfoComplete();
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
     ClassDeclaration *searchBase(Identifier *ident);
-    void finalizeSize();
+    void finalizeSize() override;
     bool hasMonitor();
     bool isFuncHidden(FuncDeclaration *fd);
     FuncDeclaration *findFunc(Identifier *ident, TypeFunction *tf);
@@ -301,30 +301,30 @@  public:
     virtual bool isCPPinterface() const;
     bool isAbstract();
     virtual int vtblOffset() const;
-    const char *kind() const;
+    const char *kind() const override;
 
-    void addLocalClass(ClassDeclarations *);
-    void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories);
+    void addLocalClass(ClassDeclarations *) override final;
+    void addObjcSymbols(ClassDeclarations *classes, ClassDeclarations *categories) override final;
 
     // Back end
     Dsymbol *vtblsym;
     Dsymbol *vtblSymbol();
 
-    ClassDeclaration *isClassDeclaration() { return (ClassDeclaration *)this; }
-    void accept(Visitor *v) { v->visit(this); }
+    ClassDeclaration *isClassDeclaration() override final { return (ClassDeclaration *)this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class InterfaceDeclaration : public ClassDeclaration
+class InterfaceDeclaration final : public ClassDeclaration
 {
 public:
-    InterfaceDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    bool isBaseOf(ClassDeclaration *cd, int *poffset);
-    const char *kind() const;
-    int vtblOffset() const;
-    bool isCPPinterface() const;
-    bool isCOMinterface() const;
-
-    InterfaceDeclaration *isInterfaceDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    InterfaceDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    bool isBaseOf(ClassDeclaration *cd, int *poffset) override;
+    const char *kind() const override;
+    int vtblOffset() const override;
+    bool isCPPinterface() const override;
+    bool isCOMinterface() const override;
+
+    InterfaceDeclaration *isInterfaceDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/aliasthis.h b/gcc/d/dmd/aliasthis.h
index 3b67903c4d0..c63d717a7bd 100644
--- a/gcc/d/dmd/aliasthis.h
+++ b/gcc/d/dmd/aliasthis.h
@@ -15,7 +15,7 @@ 
 
 /**************************************************************/
 
-class AliasThis : public Dsymbol
+class AliasThis final : public Dsymbol
 {
 public:
    // alias Identifier this;
@@ -23,9 +23,9 @@  public:
     Dsymbol    *sym;
     bool       isDeprecated_;
 
-    AliasThis *syntaxCopy(Dsymbol *);
-    const char *kind() const;
+    AliasThis *syntaxCopy(Dsymbol *) override;
+    const char *kind() const override;
     AliasThis *isAliasThis() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
-    bool isDeprecated() const { return this->isDeprecated_; }
+    void accept(Visitor *v) override { v->visit(this); }
+    bool isDeprecated() const override { return this->isDeprecated_; }
 };
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 812729b3f27..1fe33a6ba51 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -26,20 +26,20 @@  public:
 
     virtual Dsymbols *include(Scope *sc);
     virtual Scope *newScope(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope *sc);
-    void importAll(Scope *sc);
-    void addComment(const utf8_t *comment);
-    const char *kind() const;
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
-    bool hasPointers();
-    bool hasStaticCtorOrDtor();
-    void checkCtorConstInit();
-    void addLocalClass(ClassDeclarations *);
-    AttribDeclaration *isAttribDeclaration() { return this; }
-
-    void accept(Visitor *v) { v->visit(this); }
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope *sc) override;
+    void importAll(Scope *sc) override;
+    void addComment(const utf8_t *comment) override;
+    const char *kind() const override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
+    bool hasPointers() override final;
+    bool hasStaticCtorOrDtor() override final;
+    void checkCtorConstInit() override final;
+    void addLocalClass(ClassDeclarations *) override final;
+    AttribDeclaration *isAttribDeclaration() override final { return this; }
+
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class StorageClassDeclaration : public AttribDeclaration
@@ -47,90 +47,90 @@  class StorageClassDeclaration : public AttribDeclaration
 public:
     StorageClass stc;
 
-    StorageClassDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    StorageClassDeclaration *isStorageClassDeclaration() { return this; }
+    StorageClassDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override final;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    StorageClassDeclaration *isStorageClassDeclaration() override { return this; }
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DeprecatedDeclaration : public StorageClassDeclaration
+class DeprecatedDeclaration final : public StorageClassDeclaration
 {
 public:
     Expression *msg;
     const char *msgstr;
 
-    DeprecatedDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    void setScope(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    void setScope(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class LinkDeclaration : public AttribDeclaration
+class LinkDeclaration final : public AttribDeclaration
 {
 public:
     LINK linkage;
 
     static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
-    LinkDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    const char *toChars() const;
-    void accept(Visitor *v) { v->visit(this); }
+    LinkDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CPPMangleDeclaration : public AttribDeclaration
+class CPPMangleDeclaration final : public AttribDeclaration
 {
 public:
     CPPMANGLE cppmangle;
 
-    CPPMangleDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    void setScope(Scope *sc);
-    const char *toChars() const;
-    void accept(Visitor *v) { v->visit(this); }
+    CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    void setScope(Scope *sc) override;
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CPPNamespaceDeclaration : public AttribDeclaration
+class CPPNamespaceDeclaration final : public AttribDeclaration
 {
 public:
     Expression *exp;
 
-    CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    const char *toChars() const;
-    void accept(Visitor *v) { v->visit(this); }
+    CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VisibilityDeclaration : public AttribDeclaration
+class VisibilityDeclaration final : public AttribDeclaration
 {
 public:
     Visibility visibility;
     DArray<Identifier*> pkg_identifiers;
 
-    VisibilityDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    const char *kind() const;
-    const char *toPrettyChars(bool unused);
-    VisibilityDeclaration *isVisibilityDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    VisibilityDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    const char *kind() const override;
+    const char *toPrettyChars(bool unused) override;
+    VisibilityDeclaration *isVisibilityDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AlignDeclaration : public AttribDeclaration
+class AlignDeclaration final : public AttribDeclaration
 {
 public:
     Expressions *alignExps;
     structalign_t salign;
 
     AlignDeclaration(const Loc &loc, Expression *ealign, Dsymbols *decl);
-    AlignDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    AlignDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class AnonDeclaration : public AttribDeclaration
+class AnonDeclaration final : public AttribDeclaration
 {
 public:
     bool isunion;
@@ -139,24 +139,24 @@  public:
     unsigned anonstructsize;    // size of anonymous struct
     unsigned anonalignsize;     // size of anonymous struct for alignment purposes
 
-    AnonDeclaration *syntaxCopy(Dsymbol *s);
-    void setScope(Scope *sc);
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
-    const char *kind() const;
-    AnonDeclaration *isAnonDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    AnonDeclaration *syntaxCopy(Dsymbol *s) override;
+    void setScope(Scope *sc) override;
+    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
+    const char *kind() const override;
+    AnonDeclaration *isAnonDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PragmaDeclaration : public AttribDeclaration
+class PragmaDeclaration final : public AttribDeclaration
 {
 public:
     Expressions *args;          // array of Expression's
 
-    PragmaDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
+    PragmaDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
     PINLINE evalPragmaInline(Scope* sc);
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class ConditionalDeclaration : public AttribDeclaration
@@ -165,31 +165,31 @@  public:
     Condition *condition;
     Dsymbols *elsedecl; // array of Dsymbol's for else block
 
-    ConditionalDeclaration *syntaxCopy(Dsymbol *s);
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    Dsymbols *include(Scope *sc);
-    void addComment(const utf8_t *comment);
-    void setScope(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    ConditionalDeclaration *syntaxCopy(Dsymbol *s) override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override final;
+    Dsymbols *include(Scope *sc) override;
+    void addComment(const utf8_t *comment) override final;
+    void setScope(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticIfDeclaration : public ConditionalDeclaration
+class StaticIfDeclaration final : public ConditionalDeclaration
 {
 public:
     ScopeDsymbol *scopesym;
     bool addisdone;
     bool onStack;
 
-    StaticIfDeclaration *syntaxCopy(Dsymbol *s);
-    Dsymbols *include(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope *sc);
-    void importAll(Scope *sc);
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
+    Dsymbols *include(Scope *sc) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope *sc) override;
+    void importAll(Scope *sc) override;
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticForeachDeclaration : public AttribDeclaration
+class StaticForeachDeclaration final : public AttribDeclaration
 {
 public:
     StaticForeach *sfe;
@@ -198,31 +198,31 @@  public:
     bool cached;
     Dsymbols *cache;
 
-    StaticForeachDeclaration *syntaxCopy(Dsymbol *s);
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    Dsymbols *include(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void addComment(const utf8_t *comment);
-    void setScope(Scope *sc);
-    void importAll(Scope *sc);
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    Dsymbols *include(Scope *sc) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void addComment(const utf8_t *comment) override;
+    void setScope(Scope *sc) override;
+    void importAll(Scope *sc) override;
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ForwardingAttribDeclaration : public AttribDeclaration
+class ForwardingAttribDeclaration final : public AttribDeclaration
 {
 public:
     ForwardingScopeDsymbol *sym;
 
-    Scope *newScope(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    ForwardingAttribDeclaration *isForwardingAttribDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    Scope *newScope(Scope *sc) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Mixin declarations
 
-class CompileDeclaration : public AttribDeclaration
+class CompileDeclaration final : public AttribDeclaration
 {
 public:
     Expressions *exps;
@@ -230,26 +230,26 @@  public:
     ScopeDsymbol *scopesym;
     bool compiled;
 
-    CompileDeclaration *syntaxCopy(Dsymbol *s);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope *sc);
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    CompileDeclaration *syntaxCopy(Dsymbol *s) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope *sc) override;
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**
  * User defined attributes look like:
  *      @(args, ...)
  */
-class UserAttributeDeclaration : public AttribDeclaration
+class UserAttributeDeclaration final : public AttribDeclaration
 {
 public:
     Expressions *atts;
 
-    UserAttributeDeclaration *syntaxCopy(Dsymbol *s);
-    Scope *newScope(Scope *sc);
-    void setScope(Scope *sc);
+    UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override;
+    Scope *newScope(Scope *sc) override;
+    void setScope(Scope *sc) override;
     Expressions *getAttributes();
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/cond.h b/gcc/d/dmd/cond.h
index d69c13e8101..b33f288f9df 100644
--- a/gcc/d/dmd/cond.h
+++ b/gcc/d/dmd/cond.h
@@ -35,14 +35,16 @@  public:
     Loc loc;
     Include inc;
 
+    DYNCAST dyncast() const override final { return DYNCAST_CONDITION; }
+
     virtual Condition *syntaxCopy() = 0;
     virtual int include(Scope *sc) = 0;
     virtual DebugCondition *isDebugCondition() { return NULL; }
     virtual VersionCondition *isVersionCondition() { return NULL; }
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticForeach
+class StaticForeach final : public RootObject
 {
 public:
     Loc loc;
@@ -62,37 +64,37 @@  public:
     Identifier *ident;
     Module *mod;
 
-    DVCondition *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    DVCondition *syntaxCopy() override final;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DebugCondition : public DVCondition
+class DebugCondition final : public DVCondition
 {
 public:
     static void addGlobalIdent(const char *ident);
 
-    int include(Scope *sc);
-    DebugCondition *isDebugCondition() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    int include(Scope *sc) override;
+    DebugCondition *isDebugCondition() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VersionCondition : public DVCondition
+class VersionCondition final : public DVCondition
 {
 public:
     static void addGlobalIdent(const char *ident);
     static void addPredefinedGlobalIdent(const char *ident);
 
-    int include(Scope *sc);
-    VersionCondition *isVersionCondition() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    int include(Scope *sc) override;
+    VersionCondition *isVersionCondition() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticIfCondition : public Condition
+class StaticIfCondition final : public Condition
 {
 public:
     Expression *exp;
 
-    StaticIfCondition *syntaxCopy();
-    int include(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    StaticIfCondition *syntaxCopy() override;
+    int include(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index fde06484370..344933ace83 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -59,8 +59,16 @@  final class CParser(AST) : Parser!AST
      */
     Array!(void*) typedefTab;  /// Array of AST.Type[Identifier], typedef's indexed by Identifier
 
+    /* This is passed in as a list of #define lines, as generated by the C preprocessor with the
+     * appropriate switch to emit them. We append to it any #define's and #undef's encountered in the source
+     * file, as cpp with the -dD embeds them in the preprocessed output file.
+     * Once the file is parsed, then the #define's are converted to D symbols and appended to the array
+     * of Dsymbols returned by parseModule().
+     */
+    OutBuffer* defines;
+
     extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
-                            const ref TARGET target)
+                            const ref TARGET target, OutBuffer* defines)
     {
         super(_module, input, doDocComment);
 
@@ -69,6 +77,7 @@  final class CParser(AST) : Parser!AST
         linkage = LINK.c;
         Ccompile = true;
         this.packalign.setDefault();
+        this.defines = defines;
 
         // Configure sizes for C `long`, `long double`, `wchar_t`, ...
         this.boolsize = target.boolsize;
@@ -104,6 +113,8 @@  final class CParser(AST) : Parser!AST
         {
             if (token.value == TOK.endOfFile)
             {
+                addDefines();   // convert #define's to Dsymbols
+
                 // wrap the symbols in `extern (C) { symbols }`
                 auto wrap = new AST.Dsymbols();
                 auto ld = new AST.LinkDeclaration(token.loc, LINK.c, symbols);
@@ -976,16 +987,19 @@  final class CParser(AST) : Parser!AST
                         // ( type-name )
                         e = new AST.TypeExp(loc, t);
                     }
-                    e = new AST.DotIdExp(loc, e, Id.__sizeof);
-                    break;
                 }
-                // must be an expression
-                e = cparsePrimaryExp();
-                e = new AST.DotIdExp(loc, e, Id.__sizeof);
-                break;
+                else
+                {
+                    // must be an expression
+                    e = cparseUnaryExp();
+                }
+            }
+            else
+            {
+                //C11 6.5.3
+                e = cparseUnaryExp();
             }
 
-            e = cparseUnaryExp();
             e = new AST.DotIdExp(loc, e, Id.__sizeof);
             break;
         }
@@ -1697,7 +1711,7 @@  final class CParser(AST) : Parser!AST
         while (1)
         {
             Identifier id;
-            AST.Expression asmname;
+            AST.StringExp asmName;
             auto dt = cparseDeclarator(DTR.xdirect, tspec, id, specifier);
             if (!dt)
             {
@@ -1719,7 +1733,7 @@  final class CParser(AST) : Parser!AST
                 case TOK.asm_:
                 case TOK.__attribute__:
                     if (token.value == TOK.asm_)
-                        asmname = cparseSimpleAsmExpr();
+                        asmName = cparseSimpleAsmExpr();
                     if (token.value == TOK.__attribute__)
                     {
                         cparseGnuAttributes(specifier);
@@ -1876,14 +1890,26 @@  final class CParser(AST) : Parser!AST
                     s = new AST.LinkDeclaration(s.loc, linkage, decls);
                 }
                 // Saw `asm("name")` in the function, type, or variable definition.
-                // This maps directly to `pragma(mangle, "name")`
-                if (asmname)
+                // This is equivalent to `pragma(mangle, "name")` in D
+                if (asmName)
                 {
-                    auto args = new AST.Expressions(1);
-                    (*args)[0] = asmname;
-                    auto decls = new AST.Dsymbols(1);
-                    (*decls)[0] = s;
-                    s = new AST.PragmaDeclaration(asmname.loc, Id.mangle, args, decls);
+                    /*
+                    https://issues.dlang.org/show_bug.cgi?id=23012
+                    Ideally this would be translated to a pragma(mangle)
+                    decl. This is not possible because ImportC symbols are
+                    (currently) merged before semantic analysis is performed,
+                    so the pragma(mangle) never effects any change on the declarations
+                    it pertains too.
+
+                    Writing to mangleOverride directly avoids this, and is possible
+                    because C only a StringExp is allowed unlike a full fat pragma(mangle)
+                    which is more liberal.
+                    */
+                    if (auto p = s.isDeclaration())
+                    {
+                        auto str = asmName.peekString();
+                        p.mangleOverride = str;
+                    }
                 }
                 symbols.push(s);
             }
@@ -3062,7 +3088,7 @@  final class CParser(AST) : Parser!AST
      * asm-string-literal:
      *   string-literal
      */
-    private AST.Expression cparseSimpleAsmExpr()
+    private AST.StringExp cparseSimpleAsmExpr()
     {
         nextToken();     // move past asm
         check(TOK.leftParenthesis);
@@ -3070,7 +3096,7 @@  final class CParser(AST) : Parser!AST
             error("string literal expected");
         auto label = cparsePrimaryExp();
         check(TOK.rightParenthesis);
-        return label;
+        return cast(AST.StringExp) label;
     }
 
     /*************************
@@ -4250,12 +4276,21 @@  final class CParser(AST) : Parser!AST
                 case TOK._Bool:
                 //case TOK._Imaginary: // ? missing in Spec
                 case TOK._Complex:
-
-                // typedef-name
-                case TOK.identifier:    // will not know until semantic if typedef
                     t = peek(t);
                     break;
 
+                case TOK.identifier:
+                    // Use typedef table to disambiguate
+                    if (isTypedef(t.ident))
+                    {
+                        t = peek(t);
+                        break;
+                    }
+                    else
+                    {
+                        return false;
+                    }
+
                 // struct-or-union-specifier
                 // enum-specifier
                 case TOK.struct_:
@@ -4891,6 +4926,17 @@  final class CParser(AST) : Parser!AST
                 poundLine(n, false);
                 return true;
             }
+            else if (defines && (n.ident == Id.define || n.ident == Id.undef))
+            {
+                /* Append this line to `defines`.
+                 * Not canonicalizing it - assume it already is
+                 */
+                defines.writeByte('#');
+                defines.writestring(n.ident.toString());
+                skipToNextLine(defines);
+                defines.writeByte('\n');
+                return true;
+            }
             else if (n.ident == Id.__pragma)
             {
                 pragmaDirective(scanloc);
@@ -5078,4 +5124,70 @@  final class CParser(AST) : Parser!AST
     }
 
     //}
+
+    /******************************************************************************/
+    /********************************* #define Parser *****************************/
+    //{
+
+    /**
+     * Go through the #define's in the defines buffer and see what we can convert
+     * to Dsymbols, which are then appended to symbols[]
+     */
+    void addDefines()
+    {
+        if (!defines || defines.length < 10)  // minimum length of a #define line
+            return;
+        const length = defines.length;
+        auto slice = defines.peekChars()[0 .. length];
+        resetDefineLines(slice);                // reset lexer
+
+        const(char)* endp = &slice[length - 7];
+
+        Token n;
+
+        while (p < endp)
+        {
+            if (p[0 .. 7] == "#define")
+            {
+                p += 7;
+                scan(&n);
+                //printf("%s\n", n.toChars());
+                if (n.value == TOK.identifier)
+                {
+                    auto id = n.ident;
+                    scan(&n);
+                    if (n.value == TOK.endOfLine)       // #define identifier
+                    {
+                        nextDefineLine();
+                        continue;
+                    }
+                    if (n.value == TOK.int32Literal)
+                    {
+                        const value = n.intvalue;
+                        scan(&n);
+                        if (n.value == TOK.endOfLine)
+                        {
+                            /* Declare manifest constant:
+                             *  enum id = value;
+                             */
+                            AST.Expression e = new AST.IntegerExp(scanloc, value, AST.Type.tint32);
+                            auto v = new AST.VarDeclaration(scanloc, AST.Type.tint32, id, new AST.ExpInitializer(scanloc, e), STC.manifest);
+                            symbols.push(v);
+                            nextDefineLine();
+                            continue;
+                        }
+                    }
+                }
+                skipToNextLine();
+            }
+            else if (n.value != TOK.endOfLine)
+            {
+                skipToNextLine();
+            }
+            nextDefineLine();
+            assert(p - slice.ptr <= length);
+        }
+    }
+
+    //}
 }
diff --git a/gcc/d/dmd/ctfe.h b/gcc/d/dmd/ctfe.h
index 5979aa70e41..ab022ff505e 100644
--- a/gcc/d/dmd/ctfe.h
+++ b/gcc/d/dmd/ctfe.h
@@ -17,7 +17,7 @@ 
   A reference to a class, or an interface. We need this when we
   point to a base class (we must record what the type is).
  */
-class ClassReferenceExp : public Expression
+class ClassReferenceExp final : public Expression
 {
 public:
     StructLiteralExp *value;
@@ -26,39 +26,39 @@  public:
     /// Return index of the field, or -1 if not found
     /// Same as getFieldIndex, but checks for a direct match with the VarDeclaration
     int findFieldIndexByName(VarDeclaration *v);
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**
   An uninitialized value
  */
-class VoidInitExp : public Expression
+class VoidInitExp final : public Expression
 {
 public:
     VarDeclaration *var;
 
-    const char *toChars() const;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**
   Fake class which holds the thrown exception.
   Used for implementing exception handling.
 */
-class ThrownExceptionExp : public Expression
+class ThrownExceptionExp final : public Expression
 {
 public:
     ClassReferenceExp *thrown; // the thing being tossed
-    const char *toChars() const;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *toChars() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
 
 // This type is only used by the interpreter.
 
-class CTFEExp : public Expression
+class CTFEExp final : public Expression
 {
 public:
-    const char *toChars() const;
+    const char *toChars() const override;
 };
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index c0a86f57dd2..4607d6fee7c 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -824,9 +824,8 @@  MATCH implicitConvTo(Expression e, Type t)
          * convert to immutable
          */
         if (e.f &&
-            // lots of legacy code breaks with the following purity check
-            (global.params.useDIP1000 != FeatureState.enabled || e.f.isPure() >= PURE.const_) &&
-             e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
+            (!global.params.fixImmutableConv || e.f.isPure() >= PURE.const_) &&
+            e.f.isReturnIsolated() // check isReturnIsolated last, because it is potentially expensive.
            )
         {
             result = e.type.immutableOf().implicitConvTo(t);
@@ -2768,16 +2767,14 @@  Expression scaleFactor(BinExp be, Scope* sc)
     else
         assert(0);
 
-    if (sc.func && !sc.intypeof)
+
+    eoff = eoff.optimize(WANTvalue);
+    if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
     {
-        eoff = eoff.optimize(WANTvalue);
-        if (eoff.op == EXP.int64 && eoff.toInteger() == 0)
-        {
-        }
-        else if (sc.func.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
-        {
-            return ErrorExp.get();
-        }
+    }
+    else if (sc.setUnsafe(false, be.loc, "pointer arithmetic not allowed in @safe functions"))
+    {
+        return ErrorExp.get();
     }
 
     return be;
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 0bde33dd9e9..2c7d381e797 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -122,10 +122,10 @@  public:
     Symbol* isym;               // import version of csym
     DString mangleOverride;     // overridden symbol with pragma(mangle, "...")
 
-    const char *kind() const;
-    uinteger_t size(const Loc &loc);
+    const char *kind() const override;
+    uinteger_t size(const Loc &loc) override final;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
 
     bool isStatic() const { return (storage_class & STCstatic) != 0; }
     LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one
@@ -142,7 +142,7 @@  public:
     bool isScope() const        { return (storage_class & STCscope) != 0; }
     bool isSynchronized() const { return (storage_class & STCsynchronized) != 0; }
     bool isParameter() const    { return (storage_class & STCparameter) != 0; }
-    bool isDeprecated() const   { return (storage_class & STCdeprecated) != 0; }
+    bool isDeprecated() const override final { return (storage_class & STCdeprecated) != 0; }
     bool isOverride() const     { return (storage_class & STCoverride) != 0; }
     bool isResult() const       { return (storage_class & STCresult) != 0; }
     bool isField() const        { return (storage_class & STCfield) != 0; }
@@ -154,15 +154,15 @@  public:
 
     bool isFuture() const { return (storage_class & STCfuture) != 0; }
 
-    Visibility visible();
+    Visibility visible() override final;
 
-    Declaration *isDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    Declaration *isDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
 
-class TupleDeclaration : public Declaration
+class TupleDeclaration final : public Declaration
 {
 public:
     Objects *objects;
@@ -170,19 +170,19 @@  public:
 
     TypeTuple *tupletype;       // !=NULL if this is a type tuple
 
-    TupleDeclaration *syntaxCopy(Dsymbol *);
-    const char *kind() const;
-    Type *getType();
-    Dsymbol *toAlias2();
-    bool needThis();
+    TupleDeclaration *syntaxCopy(Dsymbol *) override;
+    const char *kind() const override;
+    Type *getType() override;
+    Dsymbol *toAlias2() override;
+    bool needThis() override;
 
-    TupleDeclaration *isTupleDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    TupleDeclaration *isTupleDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
 
-class AliasDeclaration : public Declaration
+class AliasDeclaration final : public Declaration
 {
 public:
     Dsymbol *aliassym;
@@ -190,36 +190,36 @@  public:
     Dsymbol *_import;           // !=NULL if unresolved internal alias for selective import
 
     static AliasDeclaration *create(const Loc &loc, Identifier *id, Type *type);
-    AliasDeclaration *syntaxCopy(Dsymbol *);
-    bool overloadInsert(Dsymbol *s);
-    const char *kind() const;
-    Type *getType();
-    Dsymbol *toAlias();
-    Dsymbol *toAlias2();
-    bool isOverloadable() const;
+    AliasDeclaration *syntaxCopy(Dsymbol *) override;
+    bool overloadInsert(Dsymbol *s) override;
+    const char *kind() const override;
+    Type *getType() override;
+    Dsymbol *toAlias() override;
+    Dsymbol *toAlias2() override;
+    bool isOverloadable() const override;
 
-    AliasDeclaration *isAliasDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    AliasDeclaration *isAliasDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
 
-class OverDeclaration : public Declaration
+class OverDeclaration final : public Declaration
 {
 public:
     Dsymbol *overnext;          // next in overload list
     Dsymbol *aliassym;
 
-    const char *kind() const;
-    bool equals(const RootObject *o) const;
-    bool overloadInsert(Dsymbol *s);
+    const char *kind() const override;
+    bool equals(const RootObject *o) const override;
+    bool overloadInsert(Dsymbol *s) override;
 
-    Dsymbol *toAlias();
+    Dsymbol *toAlias() override;
     Dsymbol *isUnique();
-    bool isOverloadable() const;
+    bool isOverloadable() const override;
 
-    OverDeclaration *isOverDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    OverDeclaration *isOverDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
@@ -271,26 +271,26 @@  public:
     bool isArgDtorVar() const; // temporary created to handle scope destruction of a function argument
     bool isArgDtorVar(bool v);
     static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
-    VarDeclaration *syntaxCopy(Dsymbol *);
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
-    const char *kind() const;
-    AggregateDeclaration *isThis();
-    bool needThis();
-    bool isExport() const;
-    bool isImportedSymbol() const;
+    VarDeclaration *syntaxCopy(Dsymbol *) override;
+    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final;
+    const char *kind() const override;
+    AggregateDeclaration *isThis() override final;
+    bool needThis() override final;
+    bool isExport() const override final;
+    bool isImportedSymbol() const override final;
     bool isCtorinit() const;
-    bool isDataseg();
-    bool isThreadlocal();
+    bool isDataseg() override final;
+    bool isThreadlocal() override final;
     bool isCTFE();
     bool isOverlappedWith(VarDeclaration *v);
-    bool hasPointers();
+    bool hasPointers() override final;
     bool canTakeAddressOf();
     bool needsScopeDtor();
-    void checkCtorConstInit();
-    Dsymbol *toAlias();
+    void checkCtorConstInit() override final;
+    Dsymbol *toAlias() override final;
     // Eliminate need for dynamic_cast
-    VarDeclaration *isVarDeclaration() { return (VarDeclaration *)this; }
-    void accept(Visitor *v) { v->visit(this); }
+    VarDeclaration *isVarDeclaration() override final { return (VarDeclaration *)this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
@@ -303,23 +303,23 @@  public:
     unsigned fieldWidth;
     unsigned bitOffset;
 
-    BitFieldDeclaration *syntaxCopy(Dsymbol*);
-    BitFieldDeclaration *isBitFieldDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    BitFieldDeclaration *syntaxCopy(Dsymbol *) override;
+    BitFieldDeclaration *isBitFieldDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
 
 // This is a shell around a back end symbol
 
-class SymbolDeclaration : public Declaration
+class SymbolDeclaration final : public Declaration
 {
 public:
     AggregateDeclaration *dsym;
 
     // Eliminate need for dynamic_cast
-    SymbolDeclaration *isSymbolDeclaration() { return (SymbolDeclaration *)this; }
-    void accept(Visitor *v) { v->visit(this); }
+    SymbolDeclaration *isSymbolDeclaration() override { return (SymbolDeclaration *)this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeInfoDeclaration : public VarDeclaration
@@ -328,149 +328,149 @@  public:
     Type *tinfo;
 
     static TypeInfoDeclaration *create(Type *tinfo);
-    TypeInfoDeclaration *syntaxCopy(Dsymbol *);
-    const char *toChars() const;
+    TypeInfoDeclaration *syntaxCopy(Dsymbol *) override final;
+    const char *toChars() const override final;
 
-    TypeInfoDeclaration *isTypeInfoDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    TypeInfoDeclaration *isTypeInfoDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoStructDeclaration : public TypeInfoDeclaration
+class TypeInfoStructDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoStructDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoClassDeclaration : public TypeInfoDeclaration
+class TypeInfoClassDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoClassDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoInterfaceDeclaration : public TypeInfoDeclaration
+class TypeInfoInterfaceDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoInterfaceDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoPointerDeclaration : public TypeInfoDeclaration
+class TypeInfoPointerDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoPointerDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoArrayDeclaration : public TypeInfoDeclaration
+class TypeInfoArrayDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoArrayDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoStaticArrayDeclaration : public TypeInfoDeclaration
+class TypeInfoStaticArrayDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoStaticArrayDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoAssociativeArrayDeclaration : public TypeInfoDeclaration
+class TypeInfoAssociativeArrayDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoAssociativeArrayDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoEnumDeclaration : public TypeInfoDeclaration
+class TypeInfoEnumDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoEnumDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoFunctionDeclaration : public TypeInfoDeclaration
+class TypeInfoFunctionDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoFunctionDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoDelegateDeclaration : public TypeInfoDeclaration
+class TypeInfoDelegateDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoDelegateDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoTupleDeclaration : public TypeInfoDeclaration
+class TypeInfoTupleDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoTupleDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoConstDeclaration : public TypeInfoDeclaration
+class TypeInfoConstDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoConstDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoInvariantDeclaration : public TypeInfoDeclaration
+class TypeInfoInvariantDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoInvariantDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoSharedDeclaration : public TypeInfoDeclaration
+class TypeInfoSharedDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoSharedDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoWildDeclaration : public TypeInfoDeclaration
+class TypeInfoWildDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoWildDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeInfoVectorDeclaration : public TypeInfoDeclaration
+class TypeInfoVectorDeclaration final : public TypeInfoDeclaration
 {
 public:
     static TypeInfoVectorDeclaration *create(Type *tinfo);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
 
-class ThisDeclaration : public VarDeclaration
+class ThisDeclaration final : public VarDeclaration
 {
 public:
-    ThisDeclaration *syntaxCopy(Dsymbol *);
-    ThisDeclaration *isThisDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    ThisDeclaration *syntaxCopy(Dsymbol *) override;
+    ThisDeclaration *isThisDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 enum class ILS : unsigned char
@@ -614,9 +614,7 @@  public:
 
     FuncDeclarations *inlinedNestedCallees;
 
-private:
     AttributeViolation* safetyViolation;
-public:
 
     unsigned flags;                     // FUNCFLAGxxxxx
 
@@ -625,31 +623,31 @@  public:
     ObjcFuncDeclaration objc;
 
     static FuncDeclaration *create(const Loc &loc, const Loc &endloc, Identifier *id, StorageClass storage_class, Type *type, bool noreturn = false);
-    FuncDeclaration *syntaxCopy(Dsymbol *);
+    FuncDeclaration *syntaxCopy(Dsymbol *) override;
     bool functionSemantic();
     bool functionSemantic3();
-    bool equals(const RootObject *o) const;
+    bool equals(const RootObject *o) const override final;
 
     int overrides(FuncDeclaration *fd);
     int findVtblIndex(Dsymbols *vtbl, int dim);
     BaseClass *overrideInterface();
-    bool overloadInsert(Dsymbol *s);
+    bool overloadInsert(Dsymbol *s) override;
     bool inUnittest();
     MATCH leastAsSpecialized(FuncDeclaration *g);
     LabelDsymbol *searchLabel(Identifier *ident, const Loc &loc);
     int getLevel(FuncDeclaration *fd, int intypeof); // lexical nesting level difference
     int getLevelAndCheck(const Loc &loc, Scope *sc, FuncDeclaration *fd);
-    const char *toPrettyChars(bool QualifyTypes = false);
+    const char *toPrettyChars(bool QualifyTypes = false) override;
     const char *toFullSignature();  // for diagnostics, e.g. 'int foo(int x, int y) pure'
     bool isMain() const;
     bool isCMain() const;
     bool isWinMain() const;
     bool isDllMain() const;
-    bool isExport() const;
-    bool isImportedSymbol() const;
-    bool isCodeseg() const;
-    bool isOverloadable() const;
-    bool isAbstract();
+    bool isExport() const override final;
+    bool isImportedSymbol() const override final;
+    bool isCodeseg() const override final;
+    bool isOverloadable() const override final;
+    bool isAbstract() override final;
     PURE isPure();
     PURE isPureBypassingInference();
     bool isSafe();
@@ -676,14 +674,14 @@  public:
     void isCrtDtor(bool v);
 
     virtual bool isNested() const;
-    AggregateDeclaration *isThis();
-    bool needThis();
+    AggregateDeclaration *isThis() override;
+    bool needThis() override final;
     bool isVirtualMethod();
     virtual bool isVirtual() const;
     bool isFinalFunc() const;
     virtual bool addPreInvariant();
     virtual bool addPostInvariant();
-    const char *kind() const;
+    const char *kind() const override;
     bool isUnique();
     bool needsClosure();
     bool hasNestedFrameRefs();
@@ -694,26 +692,26 @@  public:
 
     bool checkNRVO();
 
-    FuncDeclaration *isFuncDeclaration() { return this; }
+    FuncDeclaration *isFuncDeclaration() override final { return this; }
 
     virtual FuncDeclaration *toAliasFunc() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class FuncAliasDeclaration : public FuncDeclaration
+class FuncAliasDeclaration final : public FuncDeclaration
 {
 public:
     FuncDeclaration *funcalias;
     bool hasOverloads;
 
-    FuncAliasDeclaration *isFuncAliasDeclaration() { return this; }
-    const char *kind() const;
+    FuncAliasDeclaration *isFuncAliasDeclaration() override { return this; }
+    const char *kind() const override;
 
-    FuncDeclaration *toAliasFunc();
-    void accept(Visitor *v) { v->visit(this); }
+    FuncDeclaration *toAliasFunc() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class FuncLiteralDeclaration : public FuncDeclaration
+class FuncLiteralDeclaration final : public FuncDeclaration
 {
 public:
     TOK tok;                       // TOKfunction or TOKdelegate
@@ -722,85 +720,85 @@  public:
     // backend
     bool deferToObj;
 
-    FuncLiteralDeclaration *syntaxCopy(Dsymbol *);
-    bool isNested() const;
-    AggregateDeclaration *isThis();
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
+    FuncLiteralDeclaration *syntaxCopy(Dsymbol *) override;
+    bool isNested() const override;
+    AggregateDeclaration *isThis() override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
 
     void modifyReturns(Scope *sc, Type *tret);
 
-    FuncLiteralDeclaration *isFuncLiteralDeclaration() { return this; }
-    const char *kind() const;
-    const char *toPrettyChars(bool QualifyTypes = false);
-    void accept(Visitor *v) { v->visit(this); }
+    FuncLiteralDeclaration *isFuncLiteralDeclaration() override { return this; }
+    const char *kind() const override;
+    const char *toPrettyChars(bool QualifyTypes = false) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CtorDeclaration : public FuncDeclaration
+class CtorDeclaration final : public FuncDeclaration
 {
 public:
     bool isCpCtor;
-    CtorDeclaration *syntaxCopy(Dsymbol *);
-    const char *kind() const;
-    const char *toChars() const;
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
+    CtorDeclaration *syntaxCopy(Dsymbol *) override;
+    const char *kind() const override;
+    const char *toChars() const override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
 
-    CtorDeclaration *isCtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    CtorDeclaration *isCtorDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PostBlitDeclaration : public FuncDeclaration
+class PostBlitDeclaration final : public FuncDeclaration
 {
 public:
-    PostBlitDeclaration *syntaxCopy(Dsymbol *);
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
-    bool overloadInsert(Dsymbol *s);
+    PostBlitDeclaration *syntaxCopy(Dsymbol *) override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
+    bool overloadInsert(Dsymbol *s) override;
 
-    PostBlitDeclaration *isPostBlitDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    PostBlitDeclaration *isPostBlitDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DtorDeclaration : public FuncDeclaration
+class DtorDeclaration final : public FuncDeclaration
 {
 public:
-    DtorDeclaration *syntaxCopy(Dsymbol *);
-    const char *kind() const;
-    const char *toChars() const;
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
-    bool overloadInsert(Dsymbol *s);
+    DtorDeclaration *syntaxCopy(Dsymbol *) override;
+    const char *kind() const override;
+    const char *toChars() const override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
+    bool overloadInsert(Dsymbol *s) override;
 
-    DtorDeclaration *isDtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    DtorDeclaration *isDtorDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class StaticCtorDeclaration : public FuncDeclaration
 {
 public:
-    StaticCtorDeclaration *syntaxCopy(Dsymbol *);
-    AggregateDeclaration *isThis();
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
-    bool hasStaticCtorOrDtor();
+    StaticCtorDeclaration *syntaxCopy(Dsymbol *) override;
+    AggregateDeclaration *isThis() override final;
+    bool isVirtual() const override final;
+    bool addPreInvariant() override final;
+    bool addPostInvariant() override final;
+    bool hasStaticCtorOrDtor() override final;
 
-    StaticCtorDeclaration *isStaticCtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    StaticCtorDeclaration *isStaticCtorDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SharedStaticCtorDeclaration : public StaticCtorDeclaration
+class SharedStaticCtorDeclaration final : public StaticCtorDeclaration
 {
 public:
-    SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *);
+    SharedStaticCtorDeclaration *syntaxCopy(Dsymbol *) override;
 
-    SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    SharedStaticCtorDeclaration *isSharedStaticCtorDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class StaticDtorDeclaration : public FuncDeclaration
@@ -808,39 +806,39 @@  class StaticDtorDeclaration : public FuncDeclaration
 public:
     VarDeclaration *vgate;      // 'gate' variable
 
-    StaticDtorDeclaration *syntaxCopy(Dsymbol *);
-    AggregateDeclaration *isThis();
-    bool isVirtual() const;
-    bool hasStaticCtorOrDtor();
-    bool addPreInvariant();
-    bool addPostInvariant();
+    StaticDtorDeclaration *syntaxCopy(Dsymbol *) override;
+    AggregateDeclaration *isThis() override final;
+    bool isVirtual() const override final;
+    bool hasStaticCtorOrDtor() override final;
+    bool addPreInvariant() override final;
+    bool addPostInvariant() override final;
 
-    StaticDtorDeclaration *isStaticDtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    StaticDtorDeclaration *isStaticDtorDeclaration() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SharedStaticDtorDeclaration : public StaticDtorDeclaration
+class SharedStaticDtorDeclaration final : public StaticDtorDeclaration
 {
 public:
-    SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *);
+    SharedStaticDtorDeclaration *syntaxCopy(Dsymbol *) override;
 
-    SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    SharedStaticDtorDeclaration *isSharedStaticDtorDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class InvariantDeclaration : public FuncDeclaration
+class InvariantDeclaration final : public FuncDeclaration
 {
 public:
-    InvariantDeclaration *syntaxCopy(Dsymbol *);
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
+    InvariantDeclaration *syntaxCopy(Dsymbol *) override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
 
-    InvariantDeclaration *isInvariantDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    InvariantDeclaration *isInvariantDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class UnitTestDeclaration : public FuncDeclaration
+class UnitTestDeclaration final : public FuncDeclaration
 {
 public:
     char *codedoc; /** For documented unittest. */
@@ -848,25 +846,25 @@  public:
     // toObjFile() these nested functions after this one
     FuncDeclarations deferredNested;
 
-    UnitTestDeclaration *syntaxCopy(Dsymbol *);
-    AggregateDeclaration *isThis();
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
+    UnitTestDeclaration *syntaxCopy(Dsymbol *) override;
+    AggregateDeclaration *isThis() override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
 
-    UnitTestDeclaration *isUnitTestDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    UnitTestDeclaration *isUnitTestDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NewDeclaration : public FuncDeclaration
+class NewDeclaration final : public FuncDeclaration
 {
 public:
-    NewDeclaration *syntaxCopy(Dsymbol *);
-    const char *kind() const;
-    bool isVirtual() const;
-    bool addPreInvariant();
-    bool addPostInvariant();
+    NewDeclaration *syntaxCopy(Dsymbol *) override;
+    const char *kind() const override;
+    bool isVirtual() const override;
+    bool addPreInvariant() override;
+    bool addPostInvariant() override;
 
-    NewDeclaration *isNewDeclaration() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    NewDeclaration *isNewDeclaration() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 26a0ff03092..f8e5073a5f1 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -363,6 +363,9 @@  extern (C++) final class Module : Package
     int selfimports;            // 0: don't know, 1: does not, 2: does
     Dsymbol[void*] tagSymTab;   /// ImportC: tag symbols that conflict with other symbols used as the index
 
+    private OutBuffer defines;  // collect all the #define lines here
+
+
     /*************************************
      * Return true if module imports itself.
      */
@@ -677,33 +680,7 @@  extern (C++) final class Module : Package
             FileName.equalsExt(srcfile.toString(), c_ext) &&
             FileName.exists(srcfile.toString()))
         {
-            /* Look for "importc.h" by searching along import path.
-             * It should be in the same place as "object.d"
-             */
-            const(char)* importc_h;
-
-            foreach (entry; (global.path ? (*global.path)[] : null))
-            {
-                auto f = FileName.combine(entry, "importc.h");
-                if (FileName.exists(f) == 1)
-                {
-                     importc_h = f;
-                     break;
-                }
-                FileName.free(f);
-            }
-
-            if (importc_h)
-            {
-                if (global.params.verbose)
-                    message("include   %s", importc_h);
-            }
-            else
-            {
-                error("cannot find \"importc.h\" along import path");
-                fatal();
-            }
-            filename = global.preprocess(srcfile, importc_h, global.params.cppswitches, ifile);  // run C preprocessor
+            filename = global.preprocess(srcfile, loc, global.params.cppswitches, ifile, &defines);  // run C preprocessor
         }
 
         if (auto result = global.fileManager.lookup(filename))
@@ -1001,7 +978,7 @@  extern (C++) final class Module : Package
         {
             filetype = FileType.c;
 
-            scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c);
+            scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c, &defines);
             p.nextToken();
             checkCompiledImport();
             members = p.parseModule();
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index b0069403408..3b3a527dc52 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -1978,8 +1978,9 @@  extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
         }
 
         const DYNCAST kind = arrayContent.dyncast();
-        if (kind == DYNCAST.dsymbol)
+        switch (kind) with (DYNCAST)
         {
+        case dsymbol:
             TupleDeclaration td = cast(TupleDeclaration) arrayContent;
             /* $ gives the number of elements in the tuple
              */
@@ -1989,10 +1990,10 @@  extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
             v.storage_class |= STC.temp | STC.static_ | STC.const_;
             v.dsymbolSemantic(sc);
             return v;
-        }
-        if (kind == DYNCAST.type)
-        {
+        case type:
             return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
+        default:
+            break;
         }
         Expression exp = cast(Expression) arrayContent;
         if (auto ie = exp.isIndexExp())
@@ -2531,6 +2532,16 @@  Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
         if (log) printf(" collision\n");
         return null;
     }
+    /*
+    Handle merging declarations with asm("foo") and their definitions
+    */
+    static void mangleWrangle(Declaration oldDecl, Declaration newDecl)
+    {
+        if (oldDecl && newDecl)
+        {
+            newDecl.mangleOverride = oldDecl.mangleOverride ? oldDecl.mangleOverride : null;
+        }
+    }
 
     auto vd = s.isVarDeclaration(); // new declaration
     auto vd2 = s2.isVarDeclaration(); // existing declaration
@@ -2548,6 +2559,8 @@  Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
         if (i1 && i2)
             return collision();         // can't both have initializers
 
+        mangleWrangle(vd2, vd);
+
         if (i1)                         // vd is the definition
         {
             vd2.storage_class |= STC.extern_;  // so toObjFile() won't emit it
@@ -2593,6 +2606,8 @@  Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
         if (fd.fbody && fd2.fbody)
             return collision();         // can't both have bodies
 
+        mangleWrangle(fd2, fd);
+
         if (fd.fbody)                   // fd is the definition
         {
             if (log) printf(" replace existing with new\n");
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 35500af4548..23a2c775d4c 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -185,11 +185,11 @@  public:
     UserAttributeDeclaration *userAttribDecl;   // user defined attributes
 
     static Dsymbol *create(Identifier *);
-    const char *toChars() const;
+    const char *toChars() const override;
     virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
     Loc getLoc();
     const char *locToChars();
-    bool equals(const RootObject *o) const;
+    bool equals(const RootObject *o) const override;
     bool isAnonymous() const;
     void error(const Loc &loc, const char *format, ...);
     void error(const char *format, ...);
@@ -211,7 +211,7 @@  public:
     Ungag ungagSpeculative();
 
     // kludge for template.isSymbol()
-    DYNCAST dyncast() const { return DYNCAST_DSYMBOL; }
+    DYNCAST dyncast() const override final { return DYNCAST_DSYMBOL; }
 
     virtual Identifier *getIdent();
     virtual const char *toPrettyChars(bool QualifyTypes = false);
@@ -310,7 +310,7 @@  public:
     virtual OverloadSet *isOverloadSet() { return NULL; }
     virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
     virtual StaticAssert *isStaticAssert() { return NULL; }
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Dsymbol that generates a scope
@@ -329,89 +329,89 @@  private:
     BitArray accessiblePackages, privateAccessiblePackages;
 
 public:
-    ScopeDsymbol *syntaxCopy(Dsymbol *s);
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+    ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     virtual void importScope(Dsymbol *s, Visibility visibility);
     virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
-    bool isforwardRef();
+    bool isforwardRef() override final;
     static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
-    const char *kind() const;
+    const char *kind() const override;
     FuncDeclaration *findGetMembers();
     virtual Dsymbol *symtabInsert(Dsymbol *s);
     virtual Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
-    bool hasStaticCtorOrDtor();
+    bool hasStaticCtorOrDtor() override;
 
-    ScopeDsymbol *isScopeDsymbol() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    ScopeDsymbol *isScopeDsymbol() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // With statement scope
 
-class WithScopeSymbol : public ScopeDsymbol
+class WithScopeSymbol final : public ScopeDsymbol
 {
 public:
     WithStatement *withstate;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
 
-    WithScopeSymbol *isWithScopeSymbol() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    WithScopeSymbol *isWithScopeSymbol() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Array Index/Slice scope
 
-class ArrayScopeSymbol : public ScopeDsymbol
+class ArrayScopeSymbol final : public ScopeDsymbol
 {
 private:
     RootObject *arrayContent;
 public:
     Scope *sc;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override;
 
-    ArrayScopeSymbol *isArrayScopeSymbol() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    ArrayScopeSymbol *isArrayScopeSymbol() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Overload Sets
 
-class OverloadSet : public Dsymbol
+class OverloadSet final : public Dsymbol
 {
 public:
     Dsymbols a;         // array of Dsymbols
 
     void push(Dsymbol *s);
-    OverloadSet *isOverloadSet() { return this; }
-    const char *kind() const;
-    void accept(Visitor *v) { v->visit(this); }
+    OverloadSet *isOverloadSet() override { return this; }
+    const char *kind() const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Forwarding ScopeDsymbol
 
-class ForwardingScopeDsymbol : public ScopeDsymbol
+class ForwardingScopeDsymbol final : public ScopeDsymbol
 {
 public:
     ScopeDsymbol *forward;
 
-    Dsymbol *symtabInsert(Dsymbol *s);
-    Dsymbol *symtabLookup(Dsymbol *s, Identifier *id);
-    void importScope(Dsymbol *s, Visibility visibility);
-    const char *kind() const;
+    Dsymbol *symtabInsert(Dsymbol *s) override;
+    Dsymbol *symtabLookup(Dsymbol *s, Identifier *id) override;
+    void importScope(Dsymbol *s, Visibility visibility) override;
+    const char *kind() const override;
 
-    ForwardingScopeDsymbol *isForwardingScopeDsymbol() { return this; }
+    ForwardingScopeDsymbol *isForwardingScopeDsymbol() override { return this; }
 };
 
-class ExpressionDsymbol : public Dsymbol
+class ExpressionDsymbol final : public Dsymbol
 {
 public:
     Expression *exp;
 
-    ExpressionDsymbol *isExpressionDsymbol() { return this; }
+    ExpressionDsymbol *isExpressionDsymbol() override { return this; }
 };
 
 // Table of Dsymbol's
 
-class DsymbolTable : public RootObject
+class DsymbolTable final : public RootObject
 {
 public:
     AA *tab;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 5d880560c4e..e49127220a0 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -468,12 +468,9 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         dsym.type.checkComplexTransition(dsym.loc, sc);
 
         // Calculate type size + safety checks
-        if (sc.func && !sc.intypeof)
+        if (dsym.storage_class & STC.gshared && !dsym.isMember())
         {
-            if (dsym.storage_class & STC.gshared && !dsym.isMember())
-            {
-                sc.func.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
-            }
+            sc.setUnsafe(false, dsym.loc, "__gshared not allowed in safe functions; use shared");
         }
 
         Dsymbol parent = dsym.toParent();
@@ -857,23 +854,23 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
 
         // Calculate type size + safety checks
-        if (sc.func && !sc.intypeof)
+        if (1)
         {
             if (dsym._init && dsym._init.isVoidInitializer() &&
                 (dsym.type.hasPointers() || dsym.type.hasInvariant())) // also computes type size
             {
                 if (dsym.type.hasPointers())
-                    sc.func.setUnsafe(false, dsym.loc,
+                    sc.setUnsafe(false, dsym.loc,
                         "`void` initializers for pointers not allowed in safe functions");
                 else
-                    sc.func.setUnsafe(false, dsym.loc,
+                    sc.setUnsafe(false, dsym.loc,
                         "`void` initializers for structs with invariants are not allowed in safe functions");
             }
             else if (!dsym._init &&
                      !(dsym.storage_class & (STC.static_ | STC.extern_ | STC.gshared | STC.manifest | STC.field | STC.parameter)) &&
                      dsym.type.hasVoidInitPointers())
             {
-                sc.func.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
+                sc.setUnsafe(false, dsym.loc, "`void` initializers for pointers not allowed in safe functions");
             }
         }
 
@@ -3595,6 +3592,11 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         break;
                     }
 
+                    auto vtf = getFunctionType(fdv);
+                    if (vtf.trust > TRUST.system && f.trust == TRUST.system)
+                        funcdecl.error("cannot override `@safe` method `%s` with a `@system` attribute",
+                                       fdv.toPrettyChars);
+
                     if (fdc.toParent() == parent)
                     {
                         //printf("vi = %d,\tthis = %p %s %s @ [%s]\n\tfdc  = %p %s %s @ [%s]\n\tfdv  = %p %s %s @ [%s]\n",
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index ed0126eeef6..a450ea559ac 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -5352,7 +5352,7 @@  extern (C++) class TemplateParameter : ASTNode
         return this.ident.toChars();
     }
 
-    override DYNCAST dyncast() const pure @nogc nothrow @safe
+    override DYNCAST dyncast() const
     {
         return DYNCAST.templateparameter;
     }
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 55f7c724e5a..9afcc7fe687 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -801,26 +801,22 @@  public:
         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
             writeProtection(AST.Visibility.Kind.private_);
         funcToBuffer(tf, fd);
-        // FIXME: How to determine if fd is const without tf?
-        if (adparent && tf && (tf.isConst() || tf.isImmutable()))
+        if (adparent)
         {
-            bool fdOverridesAreConst = true;
-            foreach (fdv; fd.foverrides)
+            if (tf && (tf.isConst() || tf.isImmutable()))
+                buf.writestring(" const");
+            if (global.params.cplusplus >= CppStdRevision.cpp11)
             {
-                auto tfv = cast(AST.TypeFunction)fdv.type;
-                if (!tfv.isConst() && !tfv.isImmutable())
-                {
-                    fdOverridesAreConst = false;
-                    break;
-                }
+                if (fd.vtblIndex != -1 && !(adparent.storage_class & AST.STC.final_) && fd.isFinalFunc())
+                    buf.writestring(" final");
+                if (fd.isOverride())
+                    buf.writestring(" override");
             }
-
-            buf.writestring(fdOverridesAreConst ? " const" : " /* const */");
+            if (fd.isAbstract())
+                buf.writestring(" = 0");
+            else if (global.params.cplusplus >= CppStdRevision.cpp11 && fd.isDisabled())
+                buf.writestring(" = delete");
         }
-        if (adparent && fd.isAbstract())
-            buf.writestring(" = 0");
-        if (adparent && fd.isDisabled && global.params.cplusplus >= CppStdRevision.cpp11)
-            buf.writestring(" = delete");
         buf.writestringln(";");
         if (adparent && fd.isDisabled && global.params.cplusplus < CppStdRevision.cpp11)
             writeProtection(AST.Visibility.Kind.public_);
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index ab80c8b9073..9ec130099fe 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -17,7 +17,7 @@  class Identifier;
 class Type;
 class Expression;
 
-class EnumDeclaration : public ScopeDsymbol
+class EnumDeclaration final : public ScopeDsymbol
 {
 public:
     /* The separate, and distinct, cases are:
@@ -40,27 +40,27 @@  public:
     bool added;
     int inuse;
 
-    EnumDeclaration *syntaxCopy(Dsymbol *s);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope *sc);
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    Type *getType();
-    const char *kind() const;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    bool isDeprecated() const;                // is Dsymbol deprecated?
-    Visibility visible();
+    EnumDeclaration *syntaxCopy(Dsymbol *s) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope *sc) override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    Type *getType() override;
+    const char *kind() const override;
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
+    bool isDeprecated() const override;       // is Dsymbol deprecated?
+    Visibility visible() override;
     bool isSpecial() const;
     Expression *getDefaultValue(const Loc &loc);
     Type *getMemtype(const Loc &loc);
 
-    EnumDeclaration *isEnumDeclaration() { return this; }
+    EnumDeclaration *isEnumDeclaration() override { return this; }
 
     Symbol *sinit;
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 
-class EnumMember : public VarDeclaration
+class EnumMember final : public VarDeclaration
 {
 public:
     /* Can take the following forms:
@@ -78,9 +78,9 @@  public:
 
     EnumDeclaration *ed;
 
-    EnumMember *syntaxCopy(Dsymbol *s);
-    const char *kind() const;
+    EnumMember *syntaxCopy(Dsymbol *s) override;
+    const char *kind() const override;
 
-    EnumMember *isEnumMember() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    EnumMember *isEnumMember() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 3f41c298c2c..97a655289b5 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -145,7 +145,7 @@  bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
             refs = true;
             auto var = outerVars[i - (len - outerVars.length)];
             eb.isMutable = var.type.isMutable();
-            eb.er.byref.push(var);
+            eb.er.pushRef(var, false);
             continue;
         }
 
@@ -165,7 +165,7 @@  bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
         if (!(eb.isMutable || eb2.isMutable))
             return;
 
-        if (!(global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe()))
+        if (!(global.params.useDIP1000 == FeatureState.enabled && sc.setUnsafe()))
             return;
 
         if (!gag)
@@ -1185,6 +1185,8 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         if (v.isDataseg())
             continue;
 
+        const vsr = buildScopeRef(v.storage_class);
+
         Dsymbol p = v.toParent2();
 
         if ((v.isScope() || (v.storage_class & STC.maybescope)) &&
@@ -1200,8 +1202,13 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
 
         if (v.isScope())
         {
-            if (v.storage_class & STC.return_)
+            /* If `return scope` applies to v.
+             */
+            if (vsr == ScopeRef.ReturnScope ||
+                vsr == ScopeRef.Ref_ReturnScope)
+            {
                 continue;
+            }
 
             auto pfunc = p.isFuncDeclaration();
             if (pfunc &&
@@ -1245,7 +1252,7 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         }
     }
 
-    foreach (VarDeclaration v; er.byref)
+    foreach (i, VarDeclaration v; er.byref[])
     {
         if (log)
         {
@@ -1281,9 +1288,16 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
             }
             else
             {
-                if (!gag)
-                    previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
-                result = true;
+                if (er.refRetRefTransition[i])
+                {
+                    result |= sc.setUnsafeDIP1000(gag, e.loc, msg, e, v);
+                }
+                else
+                {
+                    if (!gag)
+                        previewErrorFunc(sc.isDeprecated(), featureState)(e.loc, msg, e.toChars(), v.toChars());
+                    result = true;
+                }
             }
         }
 
@@ -1374,14 +1388,21 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         }
     }
 
-    foreach (Expression ee; er.byexp)
+    foreach (i, Expression ee; er.byexp[])
     {
         if (log) printf("byexp %s\n", ee.toChars());
-        if (!gag)
-            error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars());
-        result = true;
+        if (er.expRetRefTransition[i])
+        {
+            result |= sc.setUnsafeDIP1000(gag, ee.loc,
+                "escaping reference to stack allocated value returned by `%s`", ee);
+        }
+        else
+        {
+            if (!gag)
+                error(ee.loc, "escaping reference to stack allocated value returned by `%s`", ee.toChars());
+            result = true;
+        }
     }
-
     return result;
 }
 
@@ -1449,8 +1470,9 @@  private void inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
  *      e = expression to be returned by value
  *      er = where to place collected data
  *      live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+  *     retRefTransition = if `e` is returned through a `return ref scope` function call
  */
-void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
+void escapeByValue(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
 {
     //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars());
 
@@ -1465,14 +1487,14 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
          * but it'll be placed in static data so no need to check it.
          */
         if (e.e1.op != EXP.structLiteral)
-            escapeByRef(e.e1, er, live);
+            escapeByRef(e.e1, er, live, retRefTransition);
     }
 
     void visitSymOff(SymOffExp e)
     {
         VarDeclaration v = e.var.isVarDeclaration();
         if (v)
-            er.byref.push(v);
+            er.pushRef(v, retRefTransition);
     }
 
     void visitVar(VarExp e)
@@ -1494,7 +1516,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
     void visitPtr(PtrExp e)
     {
         if (live && e.type.hasPointers())
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitDotVar(DotVarExp e)
@@ -1502,7 +1524,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         auto t = e.e1.type.toBasetype();
         if (e.type.hasPointers() && (live || t.ty == Tstruct))
         {
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
         }
     }
 
@@ -1510,9 +1532,9 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
     {
         Type t = e.e1.type.toBasetype();
         if (t.ty == Tclass || t.ty == Tpointer)
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
         else
-            escapeByRef(e.e1, er, live);
+            escapeByRef(e.e1, er, live, retRefTransition);
         er.byfunc.push(e.func);
     }
 
@@ -1533,11 +1555,11 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         if (tb.ty == Tsarray || tb.ty == Tarray)
         {
             if (e.basis)
-                escapeByValue(e.basis, er, live);
+                escapeByValue(e.basis, er, live, retRefTransition);
             foreach (el; *e.elements)
             {
                 if (el)
-                    escapeByValue(el, er, live);
+                    escapeByValue(el, er, live, retRefTransition);
             }
         }
     }
@@ -1549,7 +1571,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
             foreach (ex; *e.elements)
             {
                 if (ex)
-                    escapeByValue(ex, er, live);
+                    escapeByValue(ex, er, live, retRefTransition);
             }
         }
     }
@@ -1562,7 +1584,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
             foreach (ex; *e.arguments)
             {
                 if (ex)
-                    escapeByValue(ex, er, live);
+                    escapeByValue(ex, er, live, retRefTransition);
             }
         }
     }
@@ -1574,10 +1596,10 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         Type tb = e.type.toBasetype();
         if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray)
         {
-            escapeByRef(e.e1, er, live);
+            escapeByRef(e.e1, er, live, retRefTransition);
         }
         else
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitSlice(SliceExp e)
@@ -1602,10 +1624,10 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         {
             Type tb = e.type.toBasetype();
             if (tb.ty != Tsarray)
-                escapeByRef(e.e1, er, live);
+                escapeByRef(e.e1, er, live, retRefTransition);
         }
         else
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitIndex(IndexExp e)
@@ -1613,7 +1635,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         if (e.e1.type.toBasetype().ty == Tsarray ||
             live && e.type.hasPointers())
         {
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
         }
     }
 
@@ -1622,30 +1644,30 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         Type tb = e.type.toBasetype();
         if (tb.ty == Tpointer)
         {
-            escapeByValue(e.e1, er, live);
-            escapeByValue(e.e2, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
+            escapeByValue(e.e2, er, live, retRefTransition);
         }
     }
 
     void visitBinAssign(BinAssignExp e)
     {
-        escapeByValue(e.e1, er, live);
+        escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitAssign(AssignExp e)
     {
-        escapeByValue(e.e1, er, live);
+        escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitComma(CommaExp e)
     {
-        escapeByValue(e.e2, er, live);
+        escapeByValue(e.e2, er, live, retRefTransition);
     }
 
     void visitCond(CondExp e)
     {
-        escapeByValue(e.e1, er, live);
-        escapeByValue(e.e2, er, live);
+        escapeByValue(e.e1, er, live, retRefTransition);
+        escapeByValue(e.e2, er, live, retRefTransition);
     }
 
     void visitCall(CallExp e)
@@ -1686,7 +1708,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
                     const stc = tf.parameterStorageClass(null, p);
                     ScopeRef psr = buildScopeRef(stc);
                     if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                        escapeByValue(arg, er, live);
+                        escapeByValue(arg, er, live, retRefTransition);
                     else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                     {
                         if (tf.isref)
@@ -1696,10 +1718,10 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
                              * as:
                              *   p;
                              */
-                            escapeByValue(arg, er, live);
+                            escapeByValue(arg, er, live, retRefTransition);
                         }
                         else
-                            escapeByRef(arg, er, live);
+                            escapeByRef(arg, er, live, retRefTransition);
                     }
                 }
             }
@@ -1709,7 +1731,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         {
             DotVarExp dve = e.e1.isDotVarExp();
             FuncDeclaration fd = dve.var.isFuncDeclaration();
-            if (global.params.useDIP1000 == FeatureState.enabled)
+            if (1)
             {
                 if (fd && fd.isThis())
                 {
@@ -1741,7 +1763,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
 
                     const psr = buildScopeRef(getThisStorageClass(fd));
                     if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                        escapeByValue(dve.e1, er, live);
+                        escapeByValue(dve.e1, er, live, retRefTransition);
                     else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                     {
                         if (tf.isref)
@@ -1751,10 +1773,10 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
                              * as:
                              *   this;
                              */
-                            escapeByValue(dve.e1, er, live);
+                            escapeByValue(dve.e1, er, live, retRefTransition);
                         }
                         else
-                            escapeByRef(dve.e1, er, live);
+                            escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
                     }
                 }
             }
@@ -1767,16 +1789,16 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
 
                 const psr = buildScopeRef(stc);
                 if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                    escapeByValue(dve.e1, er, live);
+                    escapeByValue(dve.e1, er, live, retRefTransition);
                 else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                    escapeByRef(dve.e1, er, live);
+                    escapeByRef(dve.e1, er, live, retRefTransition);
             }
 
             // If it's also a nested function that is 'return scope'
             if (fd && fd.isNested())
             {
                 if (tf.isreturn && tf.isScopeQual)
-                    er.byexp.push(e);
+                    er.pushExp(e, false);
             }
         }
 
@@ -1786,7 +1808,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
         if (dg)
         {
             if (tf.isreturn)
-                escapeByValue(e.e1, er, live);
+                escapeByValue(e.e1, er, live, retRefTransition);
         }
 
         /* If it's a nested function that is 'return scope'
@@ -1797,7 +1819,7 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
             if (fd && fd.isNested())
             {
                 if (tf.isreturn && tf.isScopeQual)
-                    er.byexp.push(e);
+                    er.pushExp(e, false);
             }
         }
     }
@@ -1852,10 +1874,11 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
  *      e = expression to be returned by 'ref'
  *      er = where to place collected data
  *      live = if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
+ *      retRefTransition = if `e` is returned through a `return ref scope` function call
  */
-void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
+void escapeByRef(Expression e, EscapeByResults* er, bool live = false, bool retRefTransition = false)
 {
-    //printf("[%s] escapeByRef, e: %s\n", e.loc.toChars(), e.toChars());
+    //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition);
     void visit(Expression e)
     {
     }
@@ -1874,27 +1897,27 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                 if (ExpInitializer ez = v._init.isExpInitializer())
                 {
                     if (auto ce = ez.exp.isConstructExp())
-                        escapeByRef(ce.e2, er, live);
+                        escapeByRef(ce.e2, er, live, retRefTransition);
                     else
-                        escapeByRef(ez.exp, er, live);
+                        escapeByRef(ez.exp, er, live, retRefTransition);
                 }
             }
             else
-                er.byref.push(v);
+                er.pushRef(v, retRefTransition);
         }
     }
 
     void visitThis(ThisExp e)
     {
         if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
-            escapeByValue(e, er, live);
+            escapeByValue(e, er, live, retRefTransition);
         else if (e.var)
-            er.byref.push(e.var);
+            er.pushRef(e.var, retRefTransition);
     }
 
     void visitPtr(PtrExp e)
     {
-        escapeByValue(e.e1, er, live);
+        escapeByValue(e.e1, er, live, retRefTransition);
     }
 
     void visitIndex(IndexExp e)
@@ -1907,18 +1930,18 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
             {
                 if (v && v.storage_class & STC.variadic)
                 {
-                    er.byref.push(v);
+                    er.pushRef(v, retRefTransition);
                     return;
                 }
             }
         }
         if (tb.ty == Tsarray)
         {
-            escapeByRef(e.e1, er, live);
+            escapeByRef(e.e1, er, live, retRefTransition);
         }
         else if (tb.ty == Tarray)
         {
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
         }
     }
 
@@ -1929,40 +1952,40 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
             foreach (ex; *e.elements)
             {
                 if (ex)
-                    escapeByRef(ex, er, live);
+                    escapeByRef(ex, er, live, retRefTransition);
             }
         }
-        er.byexp.push(e);
+        er.pushExp(e, retRefTransition);
     }
 
     void visitDotVar(DotVarExp e)
     {
         Type t1b = e.e1.type.toBasetype();
         if (t1b.ty == Tclass)
-            escapeByValue(e.e1, er, live);
+            escapeByValue(e.e1, er, live, retRefTransition);
         else
-            escapeByRef(e.e1, er, live);
+            escapeByRef(e.e1, er, live, retRefTransition);
     }
 
     void visitBinAssign(BinAssignExp e)
     {
-        escapeByRef(e.e1, er, live);
+        escapeByRef(e.e1, er, live, retRefTransition);
     }
 
     void visitAssign(AssignExp e)
     {
-        escapeByRef(e.e1, er, live);
+        escapeByRef(e.e1, er, live, retRefTransition);
     }
 
     void visitComma(CommaExp e)
     {
-        escapeByRef(e.e2, er, live);
+        escapeByRef(e.e2, er, live, retRefTransition);
     }
 
     void visitCond(CondExp e)
     {
-        escapeByRef(e.e1, er, live);
-        escapeByRef(e.e2, er, live);
+        escapeByRef(e.e1, er, live, retRefTransition);
+        escapeByRef(e.e2, er, live, retRefTransition);
     }
 
     void visitCall(CallExp e)
@@ -1997,16 +2020,16 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                         const stc = tf.parameterStorageClass(null, p);
                         ScopeRef psr = buildScopeRef(stc);
                         if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                            escapeByRef(arg, er, live);
+                            escapeByRef(arg, er, live, retRefTransition);
                         else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
                         {
                             if (auto de = arg.isDelegateExp())
                             {
                                 if (de.func.isNested())
-                                    er.byexp.push(de);
+                                    er.pushExp(de, false);
                             }
                             else
-                                escapeByValue(arg, er, live);
+                                escapeByValue(arg, er, live, retRefTransition);
                         }
                     }
                 }
@@ -2019,7 +2042,7 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                 // https://issues.dlang.org/show_bug.cgi?id=20149#c10
                 if (dve.var.isCtorDeclaration())
                 {
-                    er.byexp.push(e);
+                    er.pushExp(e, false);
                     return;
                 }
 
@@ -2035,23 +2058,23 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
 
                 const psr = buildScopeRef(stc);
                 if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                        escapeByRef(dve.e1, er, live);
+                    escapeByRef(dve.e1, er, live, psr == ScopeRef.ReturnRef_Scope);
                 else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                        escapeByValue(dve.e1, er, live);
+                    escapeByValue(dve.e1, er, live, retRefTransition);
 
                 // If it's also a nested function that is 'return ref'
                 if (FuncDeclaration fd = dve.var.isFuncDeclaration())
                 {
                     if (fd.isNested() && tf.isreturn)
                     {
-                        er.byexp.push(e);
+                        er.pushExp(e, false);
                     }
                 }
             }
             // If it's a delegate, check it too
             if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
             {
-                escapeByValue(e.e1, er, live);
+                escapeByValue(e.e1, er, live, retRefTransition);
             }
 
             /* If it's a nested function that is 'return ref'
@@ -2062,12 +2085,12 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                 if (fd && fd.isNested())
                 {
                     if (tf.isreturn)
-                        er.byexp.push(e);
+                        er.pushExp(e, false);
                 }
             }
         }
         else
-            er.byexp.push(e);
+            er.pushExp(e, retRefTransition);
     }
 
     switch (e.op)
@@ -2091,7 +2114,6 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
     }
 }
 
-
 /************************************
  * Aggregate the data collected by the escapeBy??() functions.
  */
@@ -2099,8 +2121,23 @@  struct EscapeByResults
 {
     VarDeclarations byref;      // array into which variables being returned by ref are inserted
     VarDeclarations byvalue;    // array into which variables with values containing pointers are inserted
-    FuncDeclarations byfunc;    // nested functions that are turned into delegates
-    Expressions byexp;          // array into which temporaries being returned by ref are inserted
+    private FuncDeclarations byfunc; // nested functions that are turned into delegates
+    private Expressions byexp;       // array into which temporaries being returned by ref are inserted
+
+    import dmd.root.array: Array;
+
+    /**
+     * Whether the variable / expression went through a `return ref scope` function call
+     *
+     * This is needed for the dip1000 by default transition, since the rules for
+     * disambiguating `return scope ref` have changed. Therefore, functions in legacy code
+     * can be mistakenly treated as `return ref` making the compiler believe stack variables
+     * are being escaped, which is an error even in `@system` code. By keeping track of this
+     * information, variables escaped through `return ref` can be treated as a deprecation instead
+     * of error, see test/fail_compilation/dip1000_deprecation.d
+     */
+    private Array!bool refRetRefTransition;
+    private Array!bool expRetRefTransition;
 
     /** Reset arrays so the storage can be used again
      */
@@ -2110,6 +2147,33 @@  struct EscapeByResults
         byvalue.setDim(0);
         byfunc.setDim(0);
         byexp.setDim(0);
+
+        refRetRefTransition.setDim(0);
+        expRetRefTransition.setDim(0);
+    }
+
+    /**
+     * Escape variable `v` by reference
+     * Params:
+     *   v = variable to escape
+     *   retRefTransition = `v` is escaped through a `return ref scope` function call
+     */
+    void pushRef(VarDeclaration v, bool retRefTransition)
+    {
+        byref.push(v);
+        refRetRefTransition.push(retRefTransition);
+    }
+
+    /**
+     * Escape a reference to expression `e`
+     * Params:
+     *   e = expression to escape
+     *   retRefTransition = `e` is escaped through a `return ref scope` function call
+     */
+    void pushExp(Expression e, bool retRefTransition)
+    {
+        byexp.push(e);
+        expRetRefTransition.push(retRefTransition);
     }
 }
 
@@ -2438,7 +2502,7 @@  private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, con
     }
     else if (fs == FeatureState.enabled)
     {
-        return sc.func.setUnsafe(gag, loc, msg, arg0, arg1);
+        return sc.setUnsafe(gag, loc, msg, arg0, arg1);
     }
     else
     {
@@ -2449,6 +2513,11 @@  private bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, con
                     loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : ""
                 );
         }
+        else if (!sc.func.safetyViolation)
+        {
+            import dmd.func : AttributeViolation;
+            sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1);
+        }
         return false;
     }
 }
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 08723565355..4d171059306 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -1370,7 +1370,7 @@  extern (C++) abstract class Expression : ASTNode
          */
         if (v.storage_class & STC.gshared)
         {
-            if (sc.func.setUnsafe(false, this.loc,
+            if (sc.setUnsafe(false, this.loc,
                 "`@safe` function `%s` cannot access `__gshared` data `%s`", sc.func, v))
             {
                 err = true;
@@ -1419,7 +1419,7 @@  extern (C++) abstract class Expression : ASTNode
                 error("`@safe` %s `%s` cannot call `@system` %s `%s`",
                     sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
                     prettyChars);
-                f.errorSupplementalInferredSafety(/*max depth*/ 10);
+                f.errorSupplementalInferredSafety(/*max depth*/ 10, /*deprecation*/ false);
                 .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
 
                 checkOverridenDtor(sc, f, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
@@ -1427,6 +1427,20 @@  extern (C++) abstract class Expression : ASTNode
                 return true;
             }
         }
+        else if (f.isSafe() && f.safetyViolation)
+        {
+            // for dip1000 by default transition, print deprecations for calling functions that will become `@system`
+            if (sc.func.isSafeBypassingInference())
+            {
+                .deprecation(this.loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
+                errorSupplementalInferredSafety(f, 10, true);
+            }
+            else if (!sc.func.safetyViolation)
+            {
+                import dmd.func : AttributeViolation;
+                sc.func.safetyViolation = new AttributeViolation(this.loc, null, f, null);
+            }
+        }
         return false;
     }
 
@@ -5761,7 +5775,7 @@  extern (C++) final class DelegatePtrExp : UnaExp
 
     override Expression modifiableLvalue(Scope* sc, Expression e)
     {
-        if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
+        if (sc.setUnsafe(false, this.loc, "cannot modify delegate pointer in `@safe` code `%s`", this))
         {
             return ErrorExp.get();
         }
@@ -5799,7 +5813,7 @@  extern (C++) final class DelegateFuncptrExp : UnaExp
 
     override Expression modifiableLvalue(Scope* sc, Expression e)
     {
-        if (sc.func.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
+        if (sc.setUnsafe(false, this.loc, "cannot modify delegate function pointer in `@safe` code `%s`", this))
         {
             return ErrorExp.get();
         }
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 330dcdb77ec..9ab1cab9877 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -90,9 +90,9 @@  public:
     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;
+    const char *toChars() const override;
     void error(const char *format, ...) const;
     void warning(const char *format, ...) const;
     void deprecation(const char *format, ...) const;
@@ -206,6 +206,8 @@  public:
     ShrAssignExp* isShrAssignExp();
     UshrAssignExp* isUshrAssignExp();
     CatAssignExp* isCatAssignExp();
+    CatElemAssignExp* isCatElemAssignExp();
+    CatDcharAssignExp* isCatDcharAssignExp();
     AddExp* isAddExp();
     MinExp* isMinExp();
     CatExp* isCatExp();
@@ -238,71 +240,71 @@  public:
     BinExp* isBinExp();
     BinAssignExp* isBinAssignExp();
 
-    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(const Loc &loc, dinteger_t value, Type *type);
     static void emplace(UnionExp *pue, const 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();
-    Optional<bool> toBool();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool equals(const RootObject *o) const override;
+    dinteger_t toInteger() override;
+    real_t toReal() override;
+    real_t toImaginary() override;
+    complex_t toComplex() override;
+    Optional<bool> toBool() override;
+    Expression *toLvalue(Scope *sc, Expression *e) 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); }
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    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(const Loc &loc, real_t value, Type *type);
     static void emplace(UnionExp *pue, const 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();
-    Optional<bool> toBool();
-    void accept(Visitor *v) { v->visit(this); }
+    bool equals(const RootObject *o) 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(const Loc &loc, complex_t value, Type *type);
     static void emplace(UnionExp *pue, const 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();
-    Optional<bool> toBool();
-    void accept(Visitor *v) { v->visit(this); }
+    bool equals(const RootObject *o) 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
@@ -311,27 +313,27 @@  public:
     Identifier *ident;
 
     static IdentifierExp *create(const Loc &loc, Identifier *ident);
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override final;
+    Expression *toLvalue(Scope *sc, Expression *e) 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;
 
-    DsymbolExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    DsymbolExp *syntaxCopy() override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class ThisExp : public Expression
@@ -339,30 +341,30 @@  class ThisExp : public Expression
 public:
     VarDeclaration *var;
 
-    ThisExp *syntaxCopy();
-    Optional<bool> toBool();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
+    ThisExp *syntaxCopy() override;
+    Optional<bool> toBool() override;
+    bool isLvalue() override final;
+    Expression *toLvalue(Scope *sc, Expression *e) override final;
 
-    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;
-    Optional<bool> toBool();
-    StringExp *toStringExp();
-    void accept(Visitor *v) { v->visit(this); }
+    bool equals(const RootObject *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
@@ -375,23 +377,23 @@  public:
     static StringExp *create(const Loc &loc, const char *s);
     static StringExp *create(const Loc &loc, const void *s, d_size_t len);
     static void emplace(UnionExp *pue, const Loc &loc, const char *s);
-    bool equals(const RootObject *o) const;
+    bool equals(const RootObject *o) const override;
     char32_t getCodeUnit(d_size_t i) const;
     void setCodeUnit(d_size_t i, char32_t c);
-    StringExp *toStringExp();
+    StringExp *toStringExp() override;
     StringExp *toUTF8(Scope *sc);
-    Optional<bool> toBool();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    Optional<bool> toBool() override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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;
 };
 
 // Tuple
 
-class TupleExp : public Expression
+class TupleExp final : public Expression
 {
 public:
     Expression *e0;     // side-effect part
@@ -405,13 +407,13 @@  public:
     Expressions *exps;
 
     static TupleExp *create(const Loc &loc, Expressions *exps);
-    TupleExp *syntaxCopy();
-    bool equals(const RootObject *o) const;
+    TupleExp *syntaxCopy() override;
+    bool equals(const RootObject *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:
     Expression *basis;
@@ -420,31 +422,31 @@  public:
 
     static ArrayLiteralExp *create(const Loc &loc, Expressions *elements);
     static void emplace(UnionExp *pue, const Loc &loc, Expressions *elements);
-    ArrayLiteralExp *syntaxCopy();
-    bool equals(const RootObject *o) const;
+    ArrayLiteralExp *syntaxCopy() override;
+    bool equals(const RootObject *o) const override;
     Expression *getElement(d_size_t i); // use opIndex instead
     Expression *opIndex(d_size_t i);
-    Optional<bool> toBool();
-    StringExp *toStringExp();
+    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:
     Expressions *keys;
     Expressions *values;
     OwnedBy ownedByCtfe;
 
-    bool equals(const RootObject *o) const;
-    AssocArrayLiteralExp *syntaxCopy();
-    Optional<bool> toBool();
+    bool equals(const RootObject *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
@@ -475,50 +477,50 @@  public:
     OwnedBy ownedByCtfe;
 
     static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
-    bool equals(const RootObject *o) const;
-    StructLiteralExp *syntaxCopy();
+    bool equals(const RootObject *o) const override;
+    StructLiteralExp *syntaxCopy() override;
     Expression *getField(Type *type, unsigned offset);
     int getFieldIndex(Type *type, unsigned offset);
-    Expression *addDtorHook(Scope *sc);
-    Expression *toLvalue(Scope *sc, Expression *e);
+    Expression *addDtorHook(Scope *sc) override;
+    Expression *toLvalue(Scope *sc, Expression *e) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) 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:
     /* newtype(arguments)
@@ -534,12 +536,12 @@  public:
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
     static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
-    NewExp *syntaxCopy();
+    NewExp *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class NewAnonClassExp : public Expression
+class NewAnonClassExp final : public Expression
 {
 public:
     /* class baseclasses { } (arguments)
@@ -548,8 +550,8 @@  public:
     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
@@ -559,64 +561,64 @@  public:
     Dsymbol *originalScope;
     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;
 
-    Optional<bool> toBool();
+    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(const 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);
+    bool equals(const RootObject *o) const override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) 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 *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
@@ -624,44 +626,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)
@@ -674,8 +676,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); }
 };
 
 /****************************************************************/
@@ -686,11 +688,11 @@  public:
     Expression *e1;
     Type *att1; // Save alias this type to detect recursion
 
-    UnaExp *syntaxCopy();
+    UnaExp *syntaxCopy() override;
     Expression *incompatibleTypes();
-    Expression *resolveLoc(const Loc &loc, Scope *sc);
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override final;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class BinExp : public Expression
@@ -702,56 +704,56 @@  public:
     Type *att1; // Save alias this type to detect recursion
     Type *att2; // Save alias this type to detect recursion
 
-    BinExp *syntaxCopy();
+    BinExp *syntaxCopy() override;
     Expression *incompatibleTypes();
 
     Expression *reorderSettingAAElem(Scope *sc);
 
-    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);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override final;
+    Expression *toLvalue(Scope *sc, Expression *ex) override final;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ThrowExp : public UnaExp
+class ThrowExp final : public UnaExp
 {
 public:
-    ThrowExp *syntaxCopy();
+    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;
@@ -760,44 +762,44 @@  public:
     bool arrow;         // ImportC: if -> instead of .
 
     static DotIdExp *create(const Loc &loc, Expression *e, Identifier *ident);
-    void accept(Visitor *v) { v->visit(this); }
+    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;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DotTemplateInstanceExp : public UnaExp
+class DotTemplateInstanceExp final : public UnaExp
 {
 public:
     TemplateInstance *ti;
 
-    DotTemplateInstanceExp *syntaxCopy();
+    DotTemplateInstanceExp *syntaxCopy() override;
     bool findTempDecl(Scope *sc);
-    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 DelegateExp : public UnaExp
+class DelegateExp final : public UnaExp
 {
 public:
     FuncDeclaration *func;
@@ -805,18 +807,18 @@  public:
     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
@@ -831,76 +833,76 @@  public:
     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;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *addDtorHook(Scope *sc) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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); }
+    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;
+    Expression *toLvalue(Scope *sc, Expression *e) 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()
@@ -909,19 +911,19 @@  public:
 
     static VectorExp *create(const Loc &loc, Expression *e, Type *t);
     static void emplace(UnionExp *pue, const Loc &loc, Expression *e, Type *t);
-    VectorExp *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    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;
+    Expression *toLvalue(Scope *sc, Expression *e) 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
@@ -931,115 +933,115 @@  public:
     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);
-    Optional<bool> toBool();
+    SliceExp *syntaxCopy() override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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;
+    Expression *toLvalue(Scope *sc, Expression *e) 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);
-    Optional<bool> toBool();
-    Expression *addDtorHook(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) override;
+    Optional<bool> toBool() override;
+    Expression *addDtorHook(Scope *sc) 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
 
-    IndexExp *syntaxCopy();
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *e);
-    Expression *modifiableLvalue(Scope *sc, Expression *e);
+    IndexExp *syntaxCopy() override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) 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
@@ -1054,245 +1056,257 @@  class AssignExp : public BinExp
 public:
     MemorySet memset;
 
-    bool isLvalue();
-    Expression *toLvalue(Scope *sc, Expression *ex);
+    bool isLvalue() override final;
+    Expression *toLvalue(Scope *sc, Expression *ex) override final;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ConstructExp : public AssignExp
+class ConstructExp final : public AssignExp
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    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); }
+    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); }
+    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);
+    CondExp *syntaxCopy() override;
+    bool isLvalue() override;
+    Expression *toLvalue(Scope *sc, Expression *e) override;
+    Expression *modifiableLvalue(Scope *sc, Expression *e) override;
     void hookDtors(Scope *sc);
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class GenericExp : Expression
+class GenericExp final : Expression
 {
     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); }
 };
 
 /****************************************************************/
@@ -1300,42 +1314,42 @@  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); }
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override;
+    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); }
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override;
+    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); }
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override;
+    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); }
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override;
+    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); }
+    Expression *resolveLoc(const Loc &loc, Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /****************************************************************/
@@ -1396,10 +1410,10 @@  private:
 
 /****************************************************************/
 
-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); }
 };
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index b65b0ed1375..cb720271ae7 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -4989,7 +4989,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
                     err = true;
                 }
-                if (tf.trust <= TRUST.system && sc.func.setUnsafe())
+                if (tf.trust <= TRUST.system && sc.setUnsafe())
                 {
                     exp.error("`@safe` %s `%s` cannot call `@system` %s `%s`",
                         sc.func.kind(), sc.func.toPrettyChars(), p, exp.e1.toChars());
@@ -5995,7 +5995,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         auto idxReserved = FileName.findReservedChar(namez);
         if (idxReserved != size_t.max)
         {
-            e.error("`%s` is  not a valid filename on this platform", se.toChars());
+            e.error("`%s` is not a valid filename on this platform", se.toChars());
             e.errorSupplemental("Character `'%c'` is reserved and cannot be used", namez[idxReserved]);
             return setError();
         }
@@ -6543,8 +6543,9 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 RootObject o = (*tup.objects)[i];
                 Expression e;
                 Declaration var;
-                if (o.dyncast() == DYNCAST.expression)
+                switch (o.dyncast()) with (DYNCAST)
                 {
+                case expression:
                     e = cast(Expression)o;
                     if (auto se = e.isDsymbolExp())
                         var = se.s.isDeclaration();
@@ -6553,9 +6554,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                             // Exempt functions for backwards compatibility reasons.
                             // See: https://issues.dlang.org/show_bug.cgi?id=20470#c1
                             var = ve.var;
-                }
-                else if (o.dyncast() == DYNCAST.dsymbol)
-                {
+                    break;
+                case dsymbol:
                     Dsymbol s = cast(Dsymbol) o;
                     Declaration d = s.isDeclaration();
                     if (!d || d.isFuncDeclaration())
@@ -6564,13 +6564,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         e = new DsymbolExp(exp.loc, s);
                     else
                         var = d;
-                }
-                else if (o.dyncast() == DYNCAST.type)
-                {
+                    break;
+                case type:
                     e = new TypeExp(exp.loc, cast(Type)o);
-                }
-                else
-                {
+                    break;
+                default:
                     exp.error("`%s` is not an expression", o.toChars());
                     return setError();
                 }
@@ -6894,9 +6892,9 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                          * because it might end up being a pointer to undefined
                          * memory.
                          */
-                        if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
+                        if (1)
                         {
-                            if (sc.func.setUnsafe(false, exp.loc,
+                            if (sc.setUnsafe(false, exp.loc,
                                 "cannot take address of lazy parameter `%s` in `@safe` function `%s`", ve, sc.func))
                             {
                                 setError();
@@ -7045,7 +7043,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     }
                     if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
                     {
-                        sc.func.setUnsafe(false, exp.loc,
+                        sc.setUnsafe(false, exp.loc,
                             "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
                             f, sc.func);
                     }
@@ -7552,10 +7550,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // Check for unsafe casts
-        if (!sc.intypeof &&
-            !(sc.flags & SCOPE.debug_) &&
-            !isSafeCast(ex, t1b, tob) &&
-            (!sc.func && sc.stc & STC.safe || sc.func && sc.func.setUnsafe()))
+        if (!isSafeCast(ex, t1b, tob) &&
+            (!sc.func && sc.stc & STC.safe || sc.setUnsafe()))
         {
             exp.error("cast from `%s` to `%s` not allowed in safe code", exp.e1.type.toChars(), exp.to.toChars());
             return setError();
@@ -7816,11 +7812,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 return setError();
             }
-            if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
-            {
-                if (sc.func.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
-                    return setError();
-            }
+            if (sc.setUnsafe(false, exp.loc, "pointer slicing not allowed in safe functions"))
+                return setError();
         }
         else if (t1b.ty == Tarray)
         {
@@ -8328,11 +8321,9 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (exp.e2.op == EXP.int64 && exp.e2.toInteger() == 0)
             {
             }
-            else if (sc.func && !(sc.flags & SCOPE.debug_))
+            else if (sc.setUnsafe(false, exp.loc, "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
             {
-                if (sc.func.setUnsafe(false, exp.loc,
-                    "`@safe` function `%s` cannot index pointer `%s`", sc.func, exp.e1))
-                    return setError();
+                return setError();
             }
             exp.type = (cast(TypeNext)t1b).next;
             break;
@@ -9729,11 +9720,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
             {
-                if (!sc.intypeof && sc.func && !(sc.flags & SCOPE.debug_))
-                {
-                    if (sc.func.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
-                        return setError();
-                }
+                if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
+                    return setError();
             }
         }
         else
@@ -13089,9 +13077,8 @@  bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
             v.storage_class &= ~STC.maybescope;
             v.doNotInferScope = true;
             if (global.params.useDIP1000 != FeatureState.enabled &&
-                !(sc.flags & SCOPE.debug_) &&
                 !(v.storage_class & STC.temp) &&
-                sc.func.setUnsafe())
+                sc.setUnsafe())
             {
                 exp.error("cannot take address of %s `%s` in `@safe` function `%s`", p, v.toChars(), sc.func.toChars());
                 return false;
@@ -13304,7 +13291,7 @@  private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions
         {
             if ((!stype.alignment.isDefault() && stype.alignment.get() < target.ptrsize ||
                  (v.offset & (target.ptrsize - 1))) &&
-                (sc.func && sc.func.setUnsafe(false, loc,
+                (sc.setUnsafe(false, loc,
                     "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, v)))
             {
                 return false;
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index e53a540bb12..04039483930 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -346,7 +346,7 @@  extern (C++) class FuncDeclaration : Declaration
 
     /// In case of failed `@safe` inference, store the error that made the function `@system` for
     /// better diagnostics
-    private AttributeViolation* safetyViolation;
+    AttributeViolation* safetyViolation;
 
     /// Function flags: A collection of boolean packed for memory efficiency
     /// See the `FUNCFLAG` enum
@@ -713,6 +713,44 @@  extern (C++) class FuncDeclaration : Declaration
                 }
             }
         }
+        if (_linkage == LINK.cpp && bestvi != -1)
+        {
+            StorageClass stc = 0;
+            FuncDeclaration fdv = (*vtbl)[bestvi].isFuncDeclaration();
+            assert(fdv && fdv.ident == ident);
+            if (type.covariant(fdv.type, &stc, /*cppCovariant=*/true) == Covariant.no)
+            {
+                /* https://issues.dlang.org/show_bug.cgi?id=22351
+                 * Under D rules, `type` and `fdv.type` are covariant, but under C++ rules, they are not.
+                 * For now, continue to allow D covariant rules to apply when `override` has been used,
+                 * but issue a deprecation warning that this behaviour will change in the future.
+                 * Otherwise, follow the C++ covariant rules, which will create a new vtable entry.
+                 */
+                if (isOverride())
+                {
+                    /* @@@DEPRECATED_2.110@@@
+                     * After deprecation period has ended, be sure to remove this entire `LINK.cpp` branch,
+                     * but also the `cppCovariant` parameter from Type.covariant, and update the function
+                     * so that both `LINK.cpp` covariant conditions within are always checked.
+                     */
+                    .deprecation(loc, "overriding `extern(C++)` function `%s%s` with `const` qualified function `%s%s%s` is deprecated",
+                                 fdv.toPrettyChars(), fdv.type.toTypeFunction().parameterList.parametersTypeToChars(),
+                                 toPrettyChars(), type.toTypeFunction().parameterList.parametersTypeToChars(), type.modToChars());
+
+                    const char* where = type.isNaked() ? "parameters" : "type";
+                    deprecationSupplemental(loc, "Either remove `override`, or adjust the `const` qualifiers of the "
+                                            ~ "overriding function %s", where);
+                }
+                else
+                {
+                    // Treat as if Covariant.no
+                    mismatchvi = bestvi;
+                    mismatchstc = stc;
+                    mismatch = fdv;
+                    bestvi = -1;
+                }
+            }
+        }
         if (bestvi == -1 && mismatch)
         {
             //type.print();
@@ -1447,7 +1485,7 @@  extern (C++) class FuncDeclaration : Declaration
         {
             flags &= ~FUNCFLAG.safetyInprocess;
             type.toTypeFunction().trust = TRUST.system;
-            if (!gag && !safetyViolation && (fmt || arg0))
+            if (fmt || arg0)
                 safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1);
 
             if (fes)
@@ -4321,6 +4359,50 @@  extern (C++) final class NewDeclaration : FuncDeclaration
     }
 }
 
+/**************************************
+ * A statement / expression in this scope is not `@safe`,
+ * so mark the enclosing function as `@system`
+ *
+ * Params:
+ *   sc = scope that the unsafe statement / expression is in
+ *   gag = surpress error message (used in escape.d)
+ *   loc = location of error
+ *   fmt = printf-style format string
+ *   arg0  = (optional) argument for first %s format specifier
+ *   arg1  = (optional) argument for second %s format specifier
+ * Returns: whether there's a safe error
+ */
+bool setUnsafe(Scope* sc,
+    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null, RootObject arg1 = null)
+{
+    // TODO:
+    // For @system variables, unsafe initializers at global scope should mark
+    // the variable @system, see https://dlang.org/dips/1035
+
+    if (!sc.func)
+        return false;
+
+    if (sc.intypeof)
+        return false; // typeof(cast(int*)0) is safe
+
+    if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
+        return false;
+
+    if (sc.flags & SCOPE.compile) // __traits(compiles, x)
+    {
+        if (sc.func.isSafeBypassingInference())
+        {
+            // Message wil be gagged, but still call error() to update global.errors and for
+            // -verrors=spec
+            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "");
+            return true;
+        }
+        return false;
+    }
+
+    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1);
+}
+
 /// Stores a reason why a function failed to infer a function attribute like `@safe` or `pure`
 ///
 /// Has two modes:
@@ -4329,7 +4411,7 @@  extern (C++) final class NewDeclaration : FuncDeclaration
 ///   that function might recursively also have a `AttributeViolation`. This way, in case
 ///   of a big call stack, the error can go down all the way to the root cause.
 ///   The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
-private struct AttributeViolation
+struct AttributeViolation
 {
     /// location of error
     Loc loc = Loc.init;
@@ -4345,21 +4427,25 @@  private struct AttributeViolation
 /// Params:
 ///   fd = function to check
 ///   maxDepth = up to how many functions deep to report errors
-void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth)
+///   deprecation = print deprecations instead of errors
+void errorSupplementalInferredSafety(FuncDeclaration fd, int maxDepth, bool deprecation)
 {
+    auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
     if (auto s = fd.safetyViolation)
     {
         if (s.fmtStr)
         {
-            errorSupplemental(s.loc, "which was inferred `@system` because of:");
-            errorSupplemental(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "");
+            errorFunc(s.loc, deprecation ?
+                "which would be `@system` because of:" :
+                "which was inferred `@system` because of:");
+            errorFunc(s.loc, s.fmtStr, s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "");
         }
         else if (FuncDeclaration fd2 = cast(FuncDeclaration) s.arg0)
         {
             if (maxDepth > 0)
             {
-                errorSupplemental(s.loc, "which calls `%s`", fd2.toPrettyChars());
-                errorSupplementalInferredSafety(fd2, maxDepth - 1);
+                errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
+                errorSupplementalInferredSafety(fd2, maxDepth - 1, deprecation);
             }
         }
     }
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index ba4ccbe5134..3766a0be07d 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -118,6 +118,7 @@  extern (C++) struct Param
     bool useInline = false;     // inline expand functions
     FeatureState useDIP25;  // implement https://wiki.dlang.org/DIP25
     FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
+    bool fixImmutableConv;  // error on unsound immutable conversion - https://github.com/dlang/dmd/pull/14070
     bool useDIP1021;        // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
     bool release;           // build release version
     bool preservePaths;     // true means don't strip path from source file
@@ -298,7 +299,7 @@  extern (C++) struct Global
 
     enum recursionLimit = 500; /// number of recursive template expansions before abort
 
-    extern (C++) FileName function(FileName, const(char)* importc_h, ref Array!(const(char)*) cppswitches, out bool) preprocess;
+    extern (C++) FileName function(FileName, ref const Loc, ref Array!(const(char)*) cppswitches, out bool, OutBuffer* defines) preprocess;
 
   nothrow:
 
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 5c164fd484d..07298ddb792 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -20,6 +20,7 @@ 
 template <typename TYPE> struct Array;
 
 class FileManager;
+struct Loc;
 
 typedef unsigned char Diagnostic;
 enum
@@ -117,6 +118,7 @@  struct Param
     bool useInline;     // inline expand functions
     FeatureState useDIP25;      // implement https://wiki.dlang.org/DIP25
     FeatureState useDIP1000; // implement https://dlang.org/spec/memory-safe-d.html#scope-return-params
+    bool fixImmutableConv;
     bool useDIP1021;    // implement https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1021.md
     bool release;       // build release version
     bool preservePaths; // true means don't strip path from source file
@@ -270,7 +272,7 @@  struct Global
 
     FileManager* fileManager;
 
-    FileName (*preprocess)(FileName, const char*, Array<const char *>& cppswitches, bool&);
+    FileName (*preprocess)(FileName, const Loc&, Array<const char *>& cppswitches, bool&, OutBuffer&);
 
     /* Start gagging. Return the current number of gagged errors
      */
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index fd35e1cf846..fcc9b61b54a 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -3835,26 +3835,24 @@  private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
     {
         foreach (id; t.idents)
         {
-            if (id.dyncast() == DYNCAST.dsymbol)
+            switch (id.dyncast()) with (DYNCAST)
             {
+            case dsymbol:
                 buf.writeByte('.');
                 TemplateInstance ti = cast(TemplateInstance)id;
                 ti.dsymbolToBuffer(buf, hgs);
-            }
-            else if (id.dyncast() == DYNCAST.expression)
-            {
+                break;
+            case expression:
                 buf.writeByte('[');
                 (cast(Expression)id).expressionToBuffer(buf, hgs);
                 buf.writeByte(']');
-            }
-            else if (id.dyncast() == DYNCAST.type)
-            {
+                break;
+            case type:
                 buf.writeByte('[');
                 typeToBufferx(cast(Type)id, buf, hgs);
                 buf.writeByte(']');
-            }
-            else
-            {
+                break;
+            default:
                 buf.writeByte('.');
                 buf.writestring(id.toString());
             }
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index ab9528a4f00..4993a9eb1b2 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -523,6 +523,8 @@  immutable Msgtable[] msgtable =
     { "show" },
     { "push" },
     { "pop" },
+    { "define" },
+    { "undef" },
 ];
 
 
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
index 4c748beb5d8..fa7a25aaaa1 100644
--- a/gcc/d/dmd/identifier.h
+++ b/gcc/d/dmd/identifier.h
@@ -13,7 +13,7 @@ 
 #include "root/dcompat.h"
 #include "root/object.h"
 
-class Identifier : public RootObject
+class Identifier final : public RootObject
 {
 private:
     int value;
@@ -22,12 +22,11 @@  private:
 
 public:
     static Identifier* create(const char *string);
-    bool equals(const RootObject *o) const;
-    const char *toChars() const;
+    const char *toChars() const override;
     int getValue() const;
     bool isAnonymous() const;
     const char *toHChars2() const;
-    DYNCAST dyncast() const;
+    DYNCAST dyncast() const override;
 
     static Identifier *generateId(const char *prefix, size_t length, size_t suffix);
     static Identifier *idPool(const char *s, unsigned len);
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index 5e7550e16ec..f749ef5b5f6 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -17,7 +17,7 @@  struct Scope;
 class Module;
 class Package;
 
-class Import : public Dsymbol
+class Import final : public Dsymbol
 {
 public:
     /* static import aliasId = pkg1.pkg2.id : alias1 = name1, alias2 = name2;
@@ -38,17 +38,17 @@  public:
 
     AliasDeclarations aliasdecls; // corresponding AliasDeclarations for alias=name pairs
 
-    const char *kind() const;
-    Visibility visible();
-    Import *syntaxCopy(Dsymbol *s);    // copy only syntax trees
+    const char *kind() const override;
+    Visibility visible() override;
+    Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
     void load(Scope *sc);
-    void importAll(Scope *sc);
-    Dsymbol *toAlias();
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope* sc);
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    bool overloadInsert(Dsymbol *s);
-
-    Import *isImport() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    void importAll(Scope *sc) override;
+    Dsymbol *toAlias() override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope* sc) override;
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
+    bool overloadInsert(Dsymbol *s) override;
+
+    Import *isImport() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index 179e0b6a5ab..164a5f3e56b 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -44,7 +44,7 @@  extern (C++) class Initializer : ASTNode
     Loc loc;
     InitKind kind;
 
-    override DYNCAST dyncast() const nothrow pure
+    override DYNCAST dyncast() const
     {
         return DYNCAST.initializer;
     }
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
index 73dc4bba2e4..296c31d1a5e 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -33,7 +33,9 @@  public:
     Loc loc;
     unsigned char kind;
 
-    const char *toChars() const;
+    DYNCAST dyncast() const override { return DYNCAST_INITIALIZER; }
+
+    const char *toChars() const override final;
 
     ErrorInitializer   *isErrorInitializer();
     VoidInitializer    *isVoidInitializer();
@@ -42,33 +44,33 @@  public:
     ExpInitializer     *isExpInitializer();
     CInitializer       *isCInitializer();
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VoidInitializer : public Initializer
+class VoidInitializer final : public Initializer
 {
 public:
     Type *type;         // type that this will initialize to
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ErrorInitializer : public Initializer
+class ErrorInitializer final : public Initializer
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StructInitializer : public Initializer
+class StructInitializer final : public Initializer
 {
 public:
     Identifiers field;  // of Identifier *'s
     Initializers value; // parallel array of Initializer *'s
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ArrayInitializer : public Initializer
+class ArrayInitializer final : public Initializer
 {
 public:
     Expressions index;  // indices
@@ -80,16 +82,16 @@  public:
     bool isAssociativeArray() const;
     Expression *toAssocArrayLiteral();
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ExpInitializer : public Initializer
+class ExpInitializer final : public Initializer
 {
 public:
     bool expandTuples;
     Expression *exp;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 struct Designator
@@ -104,14 +106,14 @@  struct DesigInit
     Initializer *initializer;
 };
 
-class CInitializer : public Initializer
+class CInitializer final : public Initializer
 {
 public:
     DesigInits initializerList;
     Type *type;         // type that array will be used to initialize
     bool sem;           // true if semantic() is run
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 2cddd282a02..a1963dabcdc 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -197,10 +197,9 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 if (vd.type.hasPointers)
                 {
                     if ((!t.alignment.isDefault() && t.alignment.get() < target.ptrsize ||
-                         (vd.offset & (target.ptrsize - 1))) &&
-                        sc.func)
+                         (vd.offset & (target.ptrsize - 1))))
                     {
-                        if (sc.func.setUnsafe(false, i.value[j].loc,
+                        if (sc.setUnsafe(false, i.value[j].loc,
                             "field `%s.%s` cannot assign to misaligned pointers in `@safe` code", sd, vd))
                         {
                             errors = true;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 5945da32259..ef918e275d0 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -146,6 +146,36 @@  class Lexer
         }
     }
 
+    /******************
+     * Used for unittests for a mock Lexer
+     */
+    this() { }
+
+    /**************************************
+     * Reset lexer to lex #define's
+     */
+    final void resetDefineLines(const(char)[] slice)
+    {
+        base = slice.ptr;
+        end = base + slice.length;
+        assert(*end == 0);
+        p = base;
+        line = p;
+        tokenizeNewlines = true;
+        inTokenStringConstant = 0;
+        lastDocLine = 0;
+        scanloc = Loc("#defines", 1, 1);
+    }
+
+    /**********************************
+     * Set up for next #define line.
+     * p should be at start of next line.
+     */
+    final void nextDefineLine()
+    {
+        tokenizeNewlines = true;
+    }
+
     version (DMDLIB)
     {
         this(const(char)* filename, const(char)* base, size_t begoffset, size_t endoffset,
@@ -1184,7 +1214,7 @@  class Lexer
      * Returns:
      *  the escape sequence as a single character
      */
-    private static dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile)
+    private dchar escapeSequence(const ref Loc loc, ref const(char)* sequence, bool Ccompile)
     {
         const(char)* p = sequence; // cache sequence reference on stack
         scope(exit) sequence = p;
@@ -1268,13 +1298,13 @@  class Lexer
                             break;
                         if (!ishex(cast(char)c))
                         {
-                            .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
+                            error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
                             break;
                         }
                     }
                     if (ndigits != 2 && !utf_isValidDchar(v))
                     {
-                        .error(loc, "invalid UTF character \\U%08x", v);
+                        error(loc, "invalid UTF character \\U%08x", v);
                         v = '?'; // recover with valid UTF character
                     }
                 }
@@ -1282,7 +1312,7 @@  class Lexer
             }
             else
             {
-                .error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c);
+                error(loc, "undefined escape hex sequence \\%c%c", sequence[0], c);
                 p++;
             }
             break;
@@ -1299,7 +1329,7 @@  class Lexer
                     c = HtmlNamedEntity(idstart, p - idstart);
                     if (c == ~0)
                     {
-                        .error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart);
+                        error(loc, "unnamed character entity &%.*s;", cast(int)(p - idstart), idstart);
                         c = '?';
                     }
                     p++;
@@ -1307,7 +1337,7 @@  class Lexer
                 default:
                     if (isalpha(*p) || (p != idstart && isdigit(*p)))
                         continue;
-                    .error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart);
+                    error(loc, "unterminated named entity &%.*s;", cast(int)(p - idstart + 1), idstart);
                     c = '?';
                     break;
                 }
@@ -1332,11 +1362,11 @@  class Lexer
                 while (++n < 3 && isoctal(cast(char)c));
                 c = v;
                 if (c > 0xFF)
-                    .error(loc, "escape octal sequence \\%03o is larger than \\377", c);
+                    error(loc, "escape octal sequence \\%03o is larger than \\377", c);
             }
             else
             {
-                .error(loc, "undefined escape sequence \\%c", c);
+                error(loc, "undefined escape sequence \\%c", c);
                 p++;
             }
             break;
@@ -2732,8 +2762,10 @@  class Lexer
 
     /***************************************
      * Scan forward to start of next line.
+     * Params:
+     *    defines = send characters to `defines`
      */
-    final void skipToNextLine()
+    final void skipToNextLine(OutBuffer* defines = null)
     {
         while (1)
         {
@@ -2754,7 +2786,9 @@  class Lexer
                 break;
 
             default:
-                if (*p & 0x80)
+                if (defines)
+                    defines.writeByte(*p); // don't care about Unicode line endings for C
+                else if (*p & 0x80)
                 {
                     const u = decodeUTF();
                     if (u == PS || u == LS)
@@ -3146,7 +3180,8 @@  unittest
     static void test(T)(string sequence, T expected, bool Ccompile = false)
     {
         auto p = cast(const(char)*)sequence.ptr;
-        assert(expected == Lexer.escapeSequence(Loc.initial, p, Ccompile));
+        Lexer lexer = new Lexer();
+        assert(expected == lexer.escapeSequence(Loc.initial, p, Ccompile));
         assert(p == sequence.ptr + sequence.length);
     }
 
@@ -3212,7 +3247,8 @@  unittest
         gotError = false;
         expected = expectedError;
         auto p = cast(const(char)*)sequence.ptr;
-        auto actualReturnValue = Lexer.escapeSequence(Loc.initial, p, Ccompile);
+        Lexer lexer = new Lexer();
+        auto actualReturnValue = lexer.escapeSequence(Loc.initial, p, Ccompile);
         assert(gotError);
         assert(expectedReturnValue == actualReturnValue);
 
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 048b3a0452c..5808c28dc82 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -35,21 +35,21 @@  public:
     unsigned tag;       // auto incremented tag, used to mask package tree in scopes
     Module *mod;        // != NULL if isPkgMod == PKGmodule
 
-    const char *kind() const;
+    const char *kind() const override;
 
-    bool equals(const RootObject *o) const;
+    bool equals(const RootObject *o) const override;
 
-    Package *isPackage() { return this; }
+    Package *isPackage() override final { return this; }
 
     bool isAncestorPackageOf(const Package * const pkg) const;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    void accept(Visitor *v) { v->visit(this); }
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
+    void accept(Visitor *v) override { v->visit(this); }
 
     Module *isPackageMod();
 };
 
-class Module : public Package
+class Module final : public Package
 {
 public:
     static Module *rootModule;
@@ -82,6 +82,7 @@  public:
     int needmoduleinfo;
     int selfimports;            // 0: don't know, 1: does not, 2: does
     void* tagSymTab;            // ImportC: tag symbols that conflict with other symbols used as the index
+    OutBuffer defines;          // collect all the #define lines here
     bool selfImports();         // returns true if module imports itself
 
     int rootimports;            // 0: don't know, 1: does not, 2: does
@@ -119,14 +120,14 @@  public:
 
     static Module *load(const Loc &loc, Identifiers *packages, Identifier *ident);
 
-    const char *kind() const;
+    const char *kind() const override;
     bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
     Module *parse();    // syntactic parse
-    void importAll(Scope *sc);
+    void importAll(Scope *sc) override;
     int needModuleInfo();
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
-    Dsymbol *symtabInsert(Dsymbol *s);
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
+    bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
+    Dsymbol *symtabInsert(Dsymbol *s) override;
     void deleteObjFile();
     static void runDeferredSemantic();
     static void runDeferredSemantic2();
@@ -155,8 +156,8 @@  public:
 
     void *ctfe_cov;             // stores coverage information from ctfe
 
-    Module *isModule() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    Module *isModule() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index be17ab3e9ad..052c23d4420 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -525,10 +525,12 @@  extern (C++) abstract class Type : ASTNode
      * Params:
      *      t = type 'this' is covariant with
      *      pstc = if not null, store STCxxxx which would make it covariant
+     *      cppCovariant = true if extern(C++) function types should follow C++ covariant rules
      * Returns:
      *     An enum value of either `Covariant.yes` or a reason it's not covariant.
      */
-    final Covariant covariant(Type t, StorageClass* pstc = null)
+    extern (D)
+    final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false)
     {
         version (none)
         {
@@ -563,11 +565,11 @@  extern (C++) abstract class Type : ASTNode
             foreach (i, fparam1; t1.parameterList)
             {
                 Parameter fparam2 = t2.parameterList[i];
+                Type tp1 = fparam1.type;
+                Type tp2 = fparam2.type;
 
-                if (!fparam1.type.equals(fparam2.type))
+                if (!tp1.equals(tp2))
                 {
-                    Type tp1 = fparam1.type;
-                    Type tp2 = fparam2.type;
                     if (tp1.ty == tp2.ty)
                     {
                         if (auto tc1 = tp1.isTypeClass())
@@ -600,6 +602,16 @@  extern (C++) abstract class Type : ASTNode
                 }
             Lcov:
                 notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
+
+                /* https://issues.dlang.org/show_bug.cgi?id=23135
+                 * extern(C++) mutable parameters are not covariant with const.
+                 */
+                if (t1.linkage == LINK.cpp && cppCovariant)
+                {
+                    notcovariant |= tp1.isNaked() != tp2.isNaked();
+                    if (auto tpn1 = tp1.nextOf())
+                        notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
+                }
             }
         }
         else if (t1.parameterList.parameters != t2.parameterList.parameters)
@@ -701,6 +713,12 @@  extern (C++) abstract class Type : ASTNode
         else if (t1.isreturn && !t2.isreturn)
             goto Lnotcovariant;
 
+        /* https://issues.dlang.org/show_bug.cgi?id=23135
+         * extern(C++) mutable member functions are not covariant with const.
+         */
+        if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
+            goto Lnotcovariant;
+
         /* Can convert mutable to const
          */
         if (!MODimplicitConv(t2.mod, t1.mod))
@@ -3237,7 +3255,7 @@  extern (C++) final class TypeBasic : Type
         return this;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         uint size;
         //printf("TypeBasic::size()\n");
@@ -3325,32 +3343,32 @@  extern (C++) final class TypeBasic : Type
         return (flags & TFlags.integral) != 0;
     }
 
-    override bool isfloating() const
+    override bool isfloating()
     {
         return (flags & TFlags.floating) != 0;
     }
 
-    override bool isreal() const
+    override bool isreal()
     {
         return (flags & TFlags.real_) != 0;
     }
 
-    override bool isimaginary() const
+    override bool isimaginary()
     {
         return (flags & TFlags.imaginary) != 0;
     }
 
-    override bool iscomplex() const
+    override bool iscomplex()
     {
         return (flags & TFlags.complex) != 0;
     }
 
-    override bool isscalar() const
+    override bool isscalar()
     {
         return (flags & (TFlags.integral | TFlags.floating)) != 0;
     }
 
-    override bool isunsigned() const
+    override bool isunsigned()
     {
         return (flags & TFlags.unsigned) != 0;
     }
@@ -3447,7 +3465,7 @@  extern (C++) final class TypeBasic : Type
         return MATCH.convert;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         switch (ty)
         {
@@ -3543,7 +3561,7 @@  extern (C++) final class TypeVector : Type
         return basetype.nextOf().isunsigned();
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return false;
     }
@@ -3860,13 +3878,13 @@  extern (C++) final class TypeDArray : TypeArray
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         //printf("TypeDArray::size()\n");
         return target.ptrsize * 2;
     }
 
-    override uint alignsize() const
+    override uint alignsize()
     {
         // A DArray consists of two ptr-sized values, so align it on pointer size
         // boundary
@@ -3879,12 +3897,12 @@  extern (C++) final class TypeDArray : TypeArray
         return nty.isSomeChar;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;
     }
@@ -3918,7 +3936,7 @@  extern (C++) final class TypeDArray : TypeArray
         return Type.implicitConvTo(to);
     }
 
-    override bool hasPointers() const
+    override bool hasPointers()
     {
         return true;
     }
@@ -3964,22 +3982,22 @@  extern (C++) final class TypeAArray : TypeArray
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;
     }
 
-    override bool hasPointers() const
+    override bool hasPointers()
     {
         return true;
     }
@@ -4056,7 +4074,7 @@  extern (C++) final class TypePointer : TypeNext
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize;
     }
@@ -4112,17 +4130,17 @@  extern (C++) final class TypePointer : TypeNext
         return TypeNext.constConv(to);
     }
 
-    override bool isscalar() const
+    override bool isscalar()
     {
         return true;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
 
-    override bool hasPointers() const
+    override bool hasPointers()
     {
         return true;
     }
@@ -4159,12 +4177,12 @@  extern (C++) final class TypeReference : TypeNext
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
@@ -4760,7 +4778,7 @@  extern (C++) final class TypeFunction : TypeNext
                                         char[] s;
                                         if (!f.isPure && sc.func.setImpure())
                                             s ~= "pure ";
-                                        if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
+                                        if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
                                             s ~= "@safe ";
                                         if (!f.isNogc && sc.func.setGC())
                                             s ~= "nogc ";
@@ -5156,12 +5174,12 @@  extern (C++) final class TypeDelegate : TypeNext
         return t;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize * 2;
     }
 
-    override uint alignsize() const
+    override uint alignsize()
     {
         return target.ptrsize;
     }
@@ -5189,17 +5207,17 @@  extern (C++) final class TypeDelegate : TypeNext
         return MATCH.nomatch;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;
     }
 
-    override bool hasPointers() const
+    override bool hasPointers()
     {
         return true;
     }
@@ -5748,12 +5766,12 @@  extern (C++) final class TypeStruct : Type
         return assignable;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return false;
     }
 
-    override bool needsDestruction() const
+    override bool needsDestruction()
     {
         return sym.dtor !is null;
     }
@@ -5985,6 +6003,7 @@  extern (C++) final class TypeEnum : Type
     {
         return sym.getMemtype(loc);
     }
+
     override uint alignsize()
     {
         Type t = memType();
@@ -6143,7 +6162,7 @@  extern (C++) final class TypeClass : Type
         return "class";
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return target.ptrsize;
     }
@@ -6268,22 +6287,22 @@  extern (C++) final class TypeClass : Type
         return this;
     }
 
-    override bool isZeroInit(const ref Loc loc) const
+    override bool isZeroInit(const ref Loc loc)
     {
         return true;
     }
 
-    override bool isscope() const
+    override bool isscope()
     {
         return sym.stack;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;
     }
 
-    override bool hasPointers() const
+    override bool hasPointers()
     {
         return true;
     }
@@ -6538,12 +6557,12 @@  extern (C++) final class TypeNull : Type
         return true;
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return tvoidptr.size(loc);
     }
@@ -6597,12 +6616,12 @@  extern (C++) final class TypeNoreturn : Type
         return this.implicitConvTo(to);
     }
 
-    override bool isBoolean() const
+    override bool isBoolean()
     {
         return true;  // bottom type can be implicitly converted to any other type
     }
 
-    override uinteger_t size(const ref Loc loc) const
+    override uinteger_t size(const ref Loc loc)
     {
         return 0;
     }
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index d2b136443e8..3565913ed27 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -119,14 +119,6 @@  enum MODFlags
 };
 typedef unsigned char MOD;
 
-enum class Covariant
-{
-    distinct = 0,
-    yes = 1,
-    no = 2,
-    fwdref = 3,
-};
-
 enum VarArgValues
 {
     VARARGnone     = 0,  /// fixed number of arguments
@@ -221,13 +213,12 @@  public:
     virtual const char *kind();
     Type *copy() const;
     virtual Type *syntaxCopy();
-    bool equals(const RootObject *o) const;
+    bool equals(const RootObject *o) const override;
     bool equivalent(Type *t);
     // kludge for template.isType()
-    DYNCAST dyncast() const { return DYNCAST_TYPE; }
+    DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
     size_t getUniqueID() const;
-    Covariant covariant(Type *t, StorageClass *pstc = NULL);
-    const char *toChars() const;
+    const char *toChars() const override;
     char *toPrettyChars(bool QualifyTypes = false);
     static void _init();
 
@@ -306,7 +297,7 @@  public:
     virtual ClassDeclaration *isClassHandle();
     virtual structalign_t alignment();
     virtual Expression *defaultInitLiteral(const Loc &loc);
-    virtual bool isZeroInit(const Loc &loc = Loc());                // if initializer is 0
+    virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
     Identifier *getTypeInfoIdent();
     virtual int hasWild() const;
     virtual bool hasPointers();
@@ -349,18 +340,18 @@  public:
     TypeNoreturn *isTypeNoreturn();
     TypeTag *isTypeTag();
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeError : public Type
+class TypeError final : public Type
 {
 public:
-    const char *kind();
-    TypeError *syntaxCopy();
+    const char *kind() override;
+    TypeError *syntaxCopy() override;
 
-    uinteger_t size(const Loc &loc);
-    Expression *defaultInitLiteral(const Loc &loc);
-    void accept(Visitor *v) { v->visit(this); }
+    uinteger_t size(const Loc &loc) override;
+    Expression *defaultInitLiteral(const Loc &loc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeNext : public Type
@@ -368,164 +359,164 @@  class TypeNext : public Type
 public:
     Type *next;
 
-    void checkDeprecated(const Loc &loc, Scope *sc);
-    int hasWild() const;
-    Type *nextOf();
-    Type *makeConst();
-    Type *makeImmutable();
-    Type *makeShared();
-    Type *makeSharedConst();
-    Type *makeWild();
-    Type *makeWildConst();
-    Type *makeSharedWild();
-    Type *makeSharedWildConst();
-    Type *makeMutable();
-    MATCH constConv(Type *to);
-    unsigned char deduceWild(Type *t, bool isRef);
+    void checkDeprecated(const Loc &loc, Scope *sc) override final;
+    int hasWild() const override final;
+    Type *nextOf() override final;
+    Type *makeConst() override final;
+    Type *makeImmutable() override final;
+    Type *makeShared() override final;
+    Type *makeSharedConst() override final;
+    Type *makeWild() override final;
+    Type *makeWildConst() override final;
+    Type *makeSharedWild() override final;
+    Type *makeSharedWildConst() override final;
+    Type *makeMutable() override final;
+    MATCH constConv(Type *to) override;
+    unsigned char deduceWild(Type *t, bool isRef) override final;
     void transitive();
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeBasic : public Type
+class TypeBasic final : public Type
 {
 public:
     const char *dstring;
     unsigned flags;
 
-    const char *kind();
-    TypeBasic *syntaxCopy();
-    uinteger_t size(const Loc &loc) /*const*/;
-    unsigned alignsize();
-    bool isintegral();
-    bool isfloating() /*const*/;
-    bool isreal() /*const*/;
-    bool isimaginary() /*const*/;
-    bool iscomplex() /*const*/;
-    bool isscalar() /*const*/;
-    bool isunsigned() /*const*/;
-    MATCH implicitConvTo(Type *to);
-    bool isZeroInit(const Loc &loc) /*const*/;
+    const char *kind() override;
+    TypeBasic *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    bool isintegral() override;
+    bool isfloating() override;
+    bool isreal() override;
+    bool isimaginary() override;
+    bool iscomplex() override;
+    bool isscalar() override;
+    bool isunsigned() override;
+    MATCH implicitConvTo(Type *to) override;
+    bool isZeroInit(const Loc &loc) override;
 
     // For eliminating dynamic_cast
-    TypeBasic *isTypeBasic();
-    void accept(Visitor *v) { v->visit(this); }
+    TypeBasic *isTypeBasic() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeVector : public Type
+class TypeVector final : public Type
 {
 public:
     Type *basetype;
 
     static TypeVector *create(Type *basetype);
-    const char *kind();
-    TypeVector *syntaxCopy();
-    uinteger_t size(const Loc &loc);
-    unsigned alignsize();
-    bool isintegral();
-    bool isfloating();
-    bool isscalar();
-    bool isunsigned();
-    bool isBoolean() /*const*/;
-    MATCH implicitConvTo(Type *to);
-    Expression *defaultInitLiteral(const Loc &loc);
+    const char *kind() override;
+    TypeVector *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    bool isintegral() override;
+    bool isfloating() override;
+    bool isscalar() override;
+    bool isunsigned() override;
+    bool isBoolean() override;
+    MATCH implicitConvTo(Type *to) override;
+    Expression *defaultInitLiteral(const Loc &loc) override;
     TypeBasic *elementType();
-    bool isZeroInit(const Loc &loc);
+    bool isZeroInit(const Loc &loc) override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeArray : public TypeNext
 {
 public:
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Static array, one with a fixed dimension
-class TypeSArray : public TypeArray
+class TypeSArray final : public TypeArray
 {
 public:
     Expression *dim;
 
-    const char *kind();
-    TypeSArray *syntaxCopy();
+    const char *kind() override;
+    TypeSArray *syntaxCopy() override;
     bool isIncomplete();
-    uinteger_t size(const Loc &loc);
-    unsigned alignsize();
-    bool isString();
-    bool isZeroInit(const Loc &loc);
-    structalign_t alignment();
-    MATCH constConv(Type *to);
-    MATCH implicitConvTo(Type *to);
-    Expression *defaultInitLiteral(const Loc &loc);
-    bool hasPointers();
-    bool hasInvariant();
-    bool needsDestruction();
-    bool needsCopyOrPostblit();
-    bool needsNested();
-
-    void accept(Visitor *v) { v->visit(this); }
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    bool isString() override;
+    bool isZeroInit(const Loc &loc) override;
+    structalign_t alignment() override;
+    MATCH constConv(Type *to) override;
+    MATCH implicitConvTo(Type *to) override;
+    Expression *defaultInitLiteral(const Loc &loc) override;
+    bool hasPointers() override;
+    bool hasInvariant() override;
+    bool needsDestruction() override;
+    bool needsCopyOrPostblit() override;
+    bool needsNested() override;
+
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Dynamic array, no dimension
-class TypeDArray : public TypeArray
+class TypeDArray final : public TypeArray
 {
 public:
-    const char *kind();
-    TypeDArray *syntaxCopy();
-    uinteger_t size(const Loc &loc) /*const*/;
-    unsigned alignsize() /*const*/;
-    bool isString();
-    bool isZeroInit(const Loc &loc) /*const*/;
-    bool isBoolean() /*const*/;
-    MATCH implicitConvTo(Type *to);
-    bool hasPointers() /*const*/;
+    const char *kind() override;
+    TypeDArray *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    bool isString() override;
+    bool isZeroInit(const Loc &loc) override;
+    bool isBoolean() override;
+    MATCH implicitConvTo(Type *to) override;
+    bool hasPointers() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeAArray : public TypeArray
+class TypeAArray final : public TypeArray
 {
 public:
     Type *index;                // key type
     Loc loc;
 
     static TypeAArray *create(Type *t, Type *index);
-    const char *kind();
-    TypeAArray *syntaxCopy();
-    uinteger_t size(const Loc &loc);
-    bool isZeroInit(const Loc &loc) /*const*/;
-    bool isBoolean() /*const*/;
-    bool hasPointers() /*const*/;
-    MATCH implicitConvTo(Type *to);
-    MATCH constConv(Type *to);
+    const char *kind() override;
+    TypeAArray *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    bool isZeroInit(const Loc &loc) override;
+    bool isBoolean() override;
+    bool hasPointers() override;
+    MATCH implicitConvTo(Type *to) override;
+    MATCH constConv(Type *to) override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypePointer : public TypeNext
+class TypePointer final : public TypeNext
 {
 public:
     static TypePointer *create(Type *t);
-    const char *kind();
-    TypePointer *syntaxCopy();
-    uinteger_t size(const Loc &loc) /*const*/;
-    MATCH implicitConvTo(Type *to);
-    MATCH constConv(Type *to);
-    bool isscalar() /*const*/;
-    bool isZeroInit(const Loc &loc) /*const*/;
-    bool hasPointers() /*const*/;
+    const char *kind() override;
+    TypePointer *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    MATCH implicitConvTo(Type *to) override;
+    MATCH constConv(Type *to) override;
+    bool isscalar() override;
+    bool isZeroInit(const Loc &loc) override;
+    bool hasPointers() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeReference : public TypeNext
+class TypeReference final : public TypeNext
 {
 public:
-    const char *kind();
-    TypeReference *syntaxCopy();
-    uinteger_t size(const Loc &loc) /*const*/;
-    bool isZeroInit(const Loc &loc) /*const*/;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeReference *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    bool isZeroInit(const Loc &loc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 enum RET
@@ -556,7 +547,7 @@  enum class PURE : unsigned char
     const_ = 3,     // parameters are values or const
 };
 
-class Parameter : public ASTNode
+class Parameter final : public ASTNode
 {
 public:
     StorageClass storageClass;
@@ -570,12 +561,12 @@  public:
     Parameter *syntaxCopy();
     Type *isLazyArray();
     // kludge for template.isType()
-    DYNCAST dyncast() const { return DYNCAST_PARAMETER; }
-    void accept(Visitor *v) { v->visit(this); }
+    DYNCAST dyncast() const override { return DYNCAST_PARAMETER; }
+    void accept(Visitor *v) override { v->visit(this); }
 
     static size_t dim(Parameters *parameters);
     static Parameter *getNth(Parameters *parameters, d_size_t nth);
-    const char *toChars() const;
+    const char *toChars() const override;
     bool isCovariant(bool returnByRef, const Parameter *p, bool previewIn) const;
 };
 
@@ -590,7 +581,7 @@  struct ParameterList
     Parameter *operator[](size_t i) { return Parameter::getNth(parameters, i); }
 };
 
-class TypeFunction : public TypeNext
+class TypeFunction final : public TypeNext
 {
 public:
     // .next is the return type
@@ -604,16 +595,16 @@  public:
     Expressions *fargs;          // function arguments
 
     static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
-    const char *kind();
-    TypeFunction *syntaxCopy();
+    const char *kind() override;
+    TypeFunction *syntaxCopy() override;
     void purityLevel();
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
     StorageClass parameterStorageClass(Parameter *p);
-    Type *addStorageClass(StorageClass stc);
+    Type *addStorageClass(StorageClass stc) override;
 
-    Type *substWildTo(unsigned mod);
-    MATCH constConv(Type *to);
+    Type *substWildTo(unsigned mod) override;
+    MATCH constConv(Type *to) override;
 
     bool isnothrow() const;
     void isnothrow(bool v);
@@ -643,29 +634,29 @@  public:
     void isInOutQual(bool v);
     bool iswild() const;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeDelegate : public TypeNext
+class TypeDelegate final : public TypeNext
 {
 public:
     // .next is a TypeFunction
 
     static TypeDelegate *create(TypeFunction *t);
-    const char *kind();
-    TypeDelegate *syntaxCopy();
-    Type *addStorageClass(StorageClass stc);
-    uinteger_t size(const Loc &loc) /*const*/;
-    unsigned alignsize() /*const*/;
-    MATCH implicitConvTo(Type *to);
-    bool isZeroInit(const Loc &loc) /*const*/;
-    bool isBoolean() /*const*/;
-    bool hasPointers() /*const*/;
+    const char *kind() override;
+    TypeDelegate *syntaxCopy() override;
+    Type *addStorageClass(StorageClass stc) override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    MATCH implicitConvTo(Type *to) override;
+    bool isZeroInit(const Loc &loc) override;
+    bool isBoolean() override;
+    bool hasPointers() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeTraits : public Type
+class TypeTraits final : public Type
 {
     Loc loc;
     /// The expression to resolve as type or symbol.
@@ -673,23 +664,23 @@  class TypeTraits : public Type
     /// Cached type/symbol after semantic analysis.
     RootObject *obj;
 
-    const char *kind();
-    TypeTraits *syntaxCopy();
-    uinteger_t size(const Loc &loc);
-    Dsymbol *toDsymbol(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeTraits *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeMixin : public Type
+class TypeMixin final : public Type
 {
     Loc loc;
     Expressions *exps;
     RootObject *obj;
 
-    const char *kind();
-    TypeMixin *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeMixin *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeQualified : public Type
@@ -704,57 +695,57 @@  public:
     void addIdent(Identifier *ident);
     void addInst(TemplateInstance *inst);
     void addIndex(RootObject *expr);
-    uinteger_t size(const Loc &loc);
+    uinteger_t size(const Loc &loc) override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeIdentifier : public TypeQualified
+class TypeIdentifier final : public TypeQualified
 {
 public:
     Identifier *ident;
     Dsymbol *originalSymbol; // The symbol representing this identifier, before alias resolution
 
     static TypeIdentifier *create(const Loc &loc, Identifier *ident);
-    const char *kind();
-    TypeIdentifier *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeIdentifier *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Similar to TypeIdentifier, but with a TemplateInstance as the root
  */
-class TypeInstance : public TypeQualified
+class TypeInstance final : public TypeQualified
 {
 public:
     TemplateInstance *tempinst;
 
-    const char *kind();
-    TypeInstance *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeInstance *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeTypeof : public TypeQualified
+class TypeTypeof final : public TypeQualified
 {
 public:
     Expression *exp;
     int inuse;
 
-    const char *kind();
-    TypeTypeof *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    uinteger_t size(const Loc &loc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeTypeof *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    uinteger_t size(const Loc &loc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeReturn : public TypeQualified
+class TypeReturn final : public TypeQualified
 {
 public:
-    const char *kind();
-    TypeReturn *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeReturn *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // Whether alias this dependency is recursive or not.
@@ -769,7 +760,7 @@  enum AliasThisRec
     RECtracingDT = 0x8  // mark in progress of deduceType
 };
 
-class TypeStruct : public Type
+class TypeStruct final : public Type
 {
 public:
     StructDeclaration *sym;
@@ -777,91 +768,91 @@  public:
     bool inuse;
 
     static TypeStruct *create(StructDeclaration *sym);
-    const char *kind();
-    uinteger_t size(const Loc &loc);
-    unsigned alignsize();
-    TypeStruct *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    structalign_t alignment();
-    Expression *defaultInitLiteral(const Loc &loc);
-    bool isZeroInit(const Loc &loc);
-    bool isAssignable();
-    bool isBoolean() /*const*/;
-    bool needsDestruction() /*const*/;
-    bool needsCopyOrPostblit();
-    bool needsNested();
-    bool hasPointers();
-    bool hasVoidInitPointers();
-    bool hasInvariant();
-    MATCH implicitConvTo(Type *to);
-    MATCH constConv(Type *to);
-    unsigned char deduceWild(Type *t, bool isRef);
-    Type *toHeadMutable();
-
-    void accept(Visitor *v) { v->visit(this); }
-};
-
-class TypeEnum : public Type
+    const char *kind() override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
+    TypeStruct *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    structalign_t alignment() override;
+    Expression *defaultInitLiteral(const Loc &loc) override;
+    bool isZeroInit(const Loc &loc) override;
+    bool isAssignable() override;
+    bool isBoolean() override;
+    bool needsDestruction() override;
+    bool needsCopyOrPostblit() override;
+    bool needsNested() override;
+    bool hasPointers() override;
+    bool hasVoidInitPointers() override;
+    bool hasInvariant() override;
+    MATCH implicitConvTo(Type *to) override;
+    MATCH constConv(Type *to) override;
+    unsigned char deduceWild(Type *t, bool isRef) override;
+    Type *toHeadMutable() override;
+
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
+class TypeEnum final : public Type
 {
 public:
     EnumDeclaration *sym;
 
-    const char *kind();
-    TypeEnum *syntaxCopy();
-    uinteger_t size(const Loc &loc);
-    unsigned alignsize();
+    const char *kind() override;
+    TypeEnum *syntaxCopy() override;
+    uinteger_t size(const Loc &loc) override;
+    unsigned alignsize() override;
     Type *memType(const Loc &loc = Loc());
-    Dsymbol *toDsymbol(Scope *sc);
-    bool isintegral();
-    bool isfloating();
-    bool isreal();
-    bool isimaginary();
-    bool iscomplex();
-    bool isscalar();
-    bool isunsigned();
-    bool isBoolean();
-    bool isString();
-    bool isAssignable();
-    bool needsDestruction();
-    bool needsCopyOrPostblit();
-    bool needsNested();
-    MATCH implicitConvTo(Type *to);
-    MATCH constConv(Type *to);
-    bool isZeroInit(const Loc &loc);
-    bool hasPointers();
-    bool hasVoidInitPointers();
-    bool hasInvariant();
-    Type *nextOf();
-
-    void accept(Visitor *v) { v->visit(this); }
-};
-
-class TypeClass : public Type
+    Dsymbol *toDsymbol(Scope *sc) override;
+    bool isintegral() override;
+    bool isfloating() override;
+    bool isreal() override;
+    bool isimaginary() override;
+    bool iscomplex() override;
+    bool isscalar() override;
+    bool isunsigned() override;
+    bool isBoolean() override;
+    bool isString() override;
+    bool isAssignable() override;
+    bool needsDestruction() override;
+    bool needsCopyOrPostblit() override;
+    bool needsNested() override;
+    MATCH implicitConvTo(Type *to) override;
+    MATCH constConv(Type *to) override;
+    bool isZeroInit(const Loc &loc) override;
+    bool hasPointers() override;
+    bool hasVoidInitPointers() override;
+    bool hasInvariant() override;
+    Type *nextOf() override;
+
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
+class TypeClass final : public Type
 {
 public:
     ClassDeclaration *sym;
     AliasThisRec att;
     CPPMANGLE cppmangle;
 
-    const char *kind();
-    uinteger_t size(const Loc &loc) /*const*/;
-    TypeClass *syntaxCopy();
-    Dsymbol *toDsymbol(Scope *sc);
-    ClassDeclaration *isClassHandle();
-    bool isBaseOf(Type *t, int *poffset);
-    MATCH implicitConvTo(Type *to);
-    MATCH constConv(Type *to);
-    unsigned char deduceWild(Type *t, bool isRef);
-    Type *toHeadMutable();
-    bool isZeroInit(const Loc &loc) /*const*/;
-    bool isscope() /*const*/;
-    bool isBoolean() /*const*/;
-    bool hasPointers() /*const*/;
+    const char *kind() override;
+    uinteger_t size(const Loc &loc) override;
+    TypeClass *syntaxCopy() override;
+    Dsymbol *toDsymbol(Scope *sc) override;
+    ClassDeclaration *isClassHandle() override;
+    bool isBaseOf(Type *t, int *poffset) override;
+    MATCH implicitConvTo(Type *to) override;
+    MATCH constConv(Type *to) override;
+    unsigned char deduceWild(Type *t, bool isRef) override;
+    Type *toHeadMutable() override;
+    bool isZeroInit(const Loc &loc) override;
+    bool isscope() override;
+    bool isBoolean() override;
+    bool hasPointers() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeTuple : public Type
+class TypeTuple final : public Type
 {
 public:
     // 'logically immutable' cached global - don't modify (neither pointer nor pointee)!
@@ -873,56 +864,57 @@  public:
     static TypeTuple *create();
     static TypeTuple *create(Type *t1);
     static TypeTuple *create(Type *t1, Type *t2);
-    const char *kind();
-    TypeTuple *syntaxCopy();
-    bool equals(const RootObject *o) const;
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeTuple *syntaxCopy() override;
+    bool equals(const RootObject *o) const override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeSlice : public TypeNext
+class TypeSlice final : public TypeNext
 {
 public:
     Expression *lwr;
     Expression *upr;
 
-    const char *kind();
-    TypeSlice *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    const char *kind() override;
+    TypeSlice *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TypeNull : public Type
+class TypeNull final : public Type
 {
 public:
-    const char *kind();
+    const char *kind() override;
 
-    TypeNull *syntaxCopy();
-    MATCH implicitConvTo(Type *to);
-    bool isBoolean() /*const*/;
+    TypeNull *syntaxCopy() override;
+    MATCH implicitConvTo(Type *to) override;
+    bool hasPointers() override;
+    bool isBoolean() override;
 
-    uinteger_t size(const Loc &loc) /*const*/;
-    void accept(Visitor *v) { v->visit(this); }
+    uinteger_t size(const Loc &loc) override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeNoreturn final : public Type
 {
 public:
-    const char *kind();
-    TypeNoreturn *syntaxCopy();
-    MATCH implicitConvTo(Type* to);
-    MATCH constConv(Type* to);
-    bool isBoolean() /* const */;
-    uinteger_t size(const Loc& loc) /* const */;
-    unsigned alignsize();
+    const char *kind() override;
+    TypeNoreturn *syntaxCopy() override;
+    MATCH implicitConvTo(Type* to) override;
+    MATCH constConv(Type* to) override;
+    bool isBoolean() override;
+    uinteger_t size(const Loc& loc) override;
+    unsigned alignsize() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class TypeTag final : public Type
 {
 public:
-    TypeTag *syntaxCopy();
+    TypeTag *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /**************************************************************/
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index 7d6f65d5fa6..9dbbdf2fd0a 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -16,17 +16,17 @@ 
  * Implies extern(C++).
  */
 
-class Nspace : public ScopeDsymbol
+class Nspace final : public ScopeDsymbol
 {
   public:
     Expression *identExp;
-    Nspace *syntaxCopy(Dsymbol *s);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    void setScope(Scope *sc);
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
-    bool hasPointers();
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
-    const char *kind() const;
-    Nspace *isNspace() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    Nspace *syntaxCopy(Dsymbol *s) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    void setScope(Scope *sc) override;
+    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
+    bool hasPointers() override;
+    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
+    const char *kind() const override;
+    Nspace *isNspace() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
index 7d5e19da9ee..387b28c1532 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -272,6 +272,10 @@  public:
     void visit(AST.UshrAssignExp e) { visit(cast(AST.BinAssignExp)e); }
     void visit(AST.CatAssignExp e) { visit(cast(AST.BinAssignExp)e); }
 
+    // CatAssignExp
+    void visit(AST.CatElemAssignExp e) { visit(cast(AST.CatAssignExp)e); }
+    void visit(AST.CatDcharAssignExp e) { visit(cast(AST.CatAssignExp)e); }
+
     //===============================================================================
     // TemplateParameter
     void visit(AST.TemplateAliasParameter tp) { visit(cast(AST.TemplateParameter)tp); }
diff --git a/gcc/d/dmd/root/object.h b/gcc/d/dmd/root/object.h
index 609e7633cbe..0c92a9af54f 100644
--- a/gcc/d/dmd/root/object.h
+++ b/gcc/d/dmd/root/object.h
@@ -26,7 +26,9 @@  enum DYNCAST
     DYNCAST_TUPLE,
     DYNCAST_PARAMETER,
     DYNCAST_STATEMENT,
-    DYNCAST_TEMPLATEPARAMETER
+    DYNCAST_CONDITION,
+    DYNCAST_TEMPLATEPARAMETER,
+    DYNCAST_INITIALIZER
 };
 
 /*
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 1c5275b3b34..4446b5e66b0 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -26,7 +26,7 @@  import dmd.identifier;
 import dmd.mtype;
 import dmd.target;
 import dmd.tokens;
-
+import dmd.func : setUnsafe;
 
 /*************************************************************
  * Check for unsafe access in @safe code:
@@ -66,7 +66,7 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
         {
             if (v.overlapped)
             {
-                if (sc.func.setUnsafe(!printmsg, e.loc,
+                if (sc.setUnsafe(!printmsg, e.loc,
                     "field `%s.%s` cannot access pointers in `@safe` code that overlap other fields", ad, v))
                     return true;
             }
@@ -76,7 +76,7 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
         {
             if (v.overlapped)
             {
-                if (sc.func.setUnsafe(!printmsg, e.loc,
+                if (sc.setUnsafe(!printmsg, e.loc,
                     "field `%s.%s` cannot access structs with invariants in `@safe` code that overlap other fields",
                     ad, v))
                     return true;
@@ -91,7 +91,7 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
             if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
                  (v.offset & (target.ptrsize - 1))))
             {
-                if (sc.func.setUnsafe(!printmsg, e.loc,
+                if (sc.setUnsafe(!printmsg, e.loc,
                     "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v))
                     return true;
             }
@@ -99,7 +99,7 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
 
         if (v.overlapUnsafe)
         {
-            if (sc.func.setUnsafe(!printmsg, e.loc,
+            if (sc.setUnsafe(!printmsg, e.loc,
                 "field `%s.%s` cannot modify fields in `@safe` code that overlap fields with other storage classes",
                 ad, v))
             {
@@ -211,15 +211,12 @@  bool isSafeCast(Expression e, Type tfrom, Type tto)
  */
 bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
 {
-    if (!(flag & DotExpFlag.noDeref) && // this use is attempting a dereference
-        sc.func &&                      // inside a function
-        !sc.intypeof &&                 // allow unsafe code in typeof expressions
-        !(sc.flags & SCOPE.debug_))     // allow unsafe code in debug statements
+    if (!(flag & DotExpFlag.noDeref)) // this use is attempting a dereference
     {
         if (id == Id.ptr)
-            return sc.func.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
+            return sc.setUnsafe(false, e.loc, "`%s.ptr` cannot be used in `@safe` code, use `&%s[0]` instead", e, e);
         else
-            return sc.func.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
+            return sc.setUnsafe(false, e.loc, "`%s.%s` cannot be used in `@safe` code", e, id);
     }
     return false;
 }
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 5691f3b75b6..f7a3836961c 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -203,10 +203,9 @@  private bool lambdaHasSideEffect(Expression e, bool assumeImpureCalls = false)
                 Type t = ce.e1.type.toBasetype();
                 if (t.ty == Tdelegate)
                     t = (cast(TypeDelegate)t).next;
-                if (t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type)) > 0)
-                {
-                }
-                else
+
+                const level = t.ty == Tfunction && (ce.f ? callSideEffectLevel(ce.f) : callSideEffectLevel(ce.e1.type));
+                if (level == 0) // 0 means the function has a side effect
                     return true;
             }
             break;
@@ -251,8 +250,9 @@  bool discardValue(Expression e)
             }
             break; // complain
         }
+    // Assumption that error => no side effect
     case EXP.error:
-        return false;
+        return true;
     case EXP.variable:
         {
             VarDeclaration v = (cast(VarExp)e).var.isVarDeclaration();
@@ -356,6 +356,25 @@  bool discardValue(Expression e)
         if (!hasSideEffect(e))
             break;
         return false;
+    case EXP.identity, EXP.notIdentity:
+    case EXP.equal, EXP.notEqual:
+        /*
+            `[side effect] == 0`
+            Technically has a side effect but is clearly wrong;
+        */
+        BinExp tmp = e.isBinExp();
+        assert(tmp);
+
+        e.error("the result of the equality expression `%s` is discarded", e.toChars());
+        bool seenSideEffect = false;
+        foreach(expr; [tmp.e1, tmp.e2])
+        {
+            if (hasSideEffect(expr)) {
+                expr.errorSupplemental("note that `%s` may have a side effect", expr.toChars());
+                seenSideEffect |= true;
+            }
+        }
+        return !seenSideEffect;
     default:
         break;
     }
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index 71713249009..06546256d17 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -696,7 +696,7 @@  extern (C++) final class UnrolledLoopStatement : Statement
 
 /***********************************************************
  */
-extern (C++) class ScopeStatement : Statement
+extern (C++) final class ScopeStatement : Statement
 {
     Statement statement;
     Loc endloc;                 // location of closing curly bracket
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 66eddd8ab55..681b4816320 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -109,9 +109,11 @@  public:
     Loc loc;
     STMT stmt;
 
+    DYNCAST dyncast() const override final { return DYNCAST_STATEMENT; }
+
     virtual Statement *syntaxCopy();
 
-    const char *toChars() const;
+    const char *toChars() const override final;
 
     void error(const char *format, ...);
     void warning(const char *format, ...);
@@ -159,26 +161,26 @@  public:
     ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
     CompoundDeclarationStatement *isCompoundDeclarationStatement() { return stmt == STMTcompoundDeclaration ? (CompoundDeclarationStatement*)this : NULL; }
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /** Any Statement that fails semantic() or has a component that is an ErrorExp or
  * a TypeError should return an ErrorStatement from semantic().
  */
-class ErrorStatement : public Statement
+class ErrorStatement final : public Statement
 {
 public:
-    ErrorStatement *syntaxCopy();
+    ErrorStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PeelStatement : public Statement
+class PeelStatement final : public Statement
 {
 public:
     Statement *s;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class ExpStatement : public Statement
@@ -187,12 +189,12 @@  public:
     Expression *exp;
 
     static ExpStatement *create(const Loc &loc, Expression *exp);
-    ExpStatement *syntaxCopy();
+    ExpStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DtorExpStatement : public ExpStatement
+class DtorExpStatement final : public ExpStatement
 {
 public:
     /* Wraps an expression that is the destruction of 'var'
@@ -200,17 +202,17 @@  public:
 
     VarDeclaration *var;
 
-    DtorExpStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    DtorExpStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CompileStatement : public Statement
+class CompileStatement final : public Statement
 {
 public:
     Expressions *exps;
 
-    CompileStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    CompileStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 class CompoundStatement : public Statement
@@ -219,60 +221,60 @@  public:
     Statements *statements;
 
     static CompoundStatement *create(const Loc &loc, Statement *s1, Statement *s2);
-    CompoundStatement *syntaxCopy();
-    ReturnStatement *endsWithReturnStatement();
-    Statement *last();
+    CompoundStatement *syntaxCopy() override;
+    ReturnStatement *endsWithReturnStatement() override final;
+    Statement *last() override final;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CompoundDeclarationStatement : public CompoundStatement
+class CompoundDeclarationStatement final : public CompoundStatement
 {
 public:
-    CompoundDeclarationStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    CompoundDeclarationStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* The purpose of this is so that continue will go to the next
  * of the statements, and break will go to the end of the statements.
  */
-class UnrolledLoopStatement : public Statement
+class UnrolledLoopStatement final : public Statement
 {
 public:
     Statements *statements;
 
-    UnrolledLoopStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    UnrolledLoopStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ScopeStatement : public Statement
+class ScopeStatement final : public Statement
 {
 public:
     Statement *statement;
     Loc endloc;                 // location of closing curly bracket
 
-    ScopeStatement *syntaxCopy();
-    ReturnStatement *endsWithReturnStatement();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    ScopeStatement *syntaxCopy() override;
+    ReturnStatement *endsWithReturnStatement() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ForwardingStatement : public Statement
+class ForwardingStatement final : public Statement
 {
 public:
     ForwardingScopeDsymbol *sym;
     Statement *statement;
 
-    ForwardingStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    ForwardingStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class WhileStatement : public Statement
+class WhileStatement final : public Statement
 {
 public:
     Parameter *param;
@@ -280,28 +282,28 @@  public:
     Statement *_body;
     Loc endloc;                 // location of closing curly bracket
 
-    WhileStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    WhileStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DoStatement : public Statement
+class DoStatement final : public Statement
 {
 public:
     Statement *_body;
     Expression *condition;
     Loc endloc;                 // location of ';' after while
 
-    DoStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    DoStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ForStatement : public Statement
+class ForStatement final : public Statement
 {
 public:
     Statement *_init;
@@ -315,15 +317,15 @@  public:
     // treat that label as referring to this loop.
     Statement *relatedLabeled;
 
-    ForStatement *syntaxCopy();
-    Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
-    bool hasBreak() const;
-    bool hasContinue() const;
+    ForStatement *syntaxCopy() override;
+    Statement *getRelatedLabeled() override { return relatedLabeled ? relatedLabeled : this; }
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ForeachStatement : public Statement
+class ForeachStatement final : public Statement
 {
 public:
     TOK op;                     // TOKforeach or TOKforeach_reverse
@@ -340,14 +342,14 @@  public:
     Statements *cases;          // put breaks, continues, gotos and returns here
     ScopeStatements *gotos;     // forward referenced goto's go here
 
-    ForeachStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    ForeachStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ForeachRangeStatement : public Statement
+class ForeachRangeStatement final : public Statement
 {
 public:
     TOK op;                     // TOKforeach or TOKforeach_reverse
@@ -359,14 +361,14 @@  public:
 
     VarDeclaration *key;
 
-    ForeachRangeStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    ForeachRangeStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class IfStatement : public Statement
+class IfStatement final : public Statement
 {
 public:
     Parameter *prm;
@@ -376,56 +378,56 @@  public:
     VarDeclaration *match;      // for MatchExpression results
     Loc endloc;                 // location of closing curly bracket
 
-    IfStatement *syntaxCopy();
+    IfStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ConditionalStatement : public Statement
+class ConditionalStatement final : public Statement
 {
 public:
     Condition *condition;
     Statement *ifbody;
     Statement *elsebody;
 
-    ConditionalStatement *syntaxCopy();
+    ConditionalStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticForeachStatement : public Statement
+class StaticForeachStatement final : public Statement
 {
 public:
     StaticForeach *sfe;
 
-    StaticForeachStatement *syntaxCopy();
+    StaticForeachStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class PragmaStatement : public Statement
+class PragmaStatement final : public Statement
 {
 public:
     Identifier *ident;
     Expressions *args;          // array of Expression's
     Statement *_body;
 
-    PragmaStatement *syntaxCopy();
+    PragmaStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class StaticAssertStatement : public Statement
+class StaticAssertStatement final : public Statement
 {
 public:
     StaticAssert *sa;
 
-    StaticAssertStatement *syntaxCopy();
+    StaticAssertStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SwitchStatement : public Statement
+class SwitchStatement final : public Statement
 {
 public:
     Expression *condition;
@@ -441,13 +443,13 @@  public:
     int hasVars;                // !=0 if has variable case values
     VarDeclaration *lastVar;
 
-    SwitchStatement *syntaxCopy();
-    bool hasBreak() const;
+    SwitchStatement *syntaxCopy() override;
+    bool hasBreak() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class CaseStatement : public Statement
+class CaseStatement final : public Statement
 {
 public:
     Expression *exp;
@@ -457,110 +459,110 @@  public:
     VarDeclaration *lastVar;
     void* extra;            // for use by Statement_toIR()
 
-    CaseStatement *syntaxCopy();
+    CaseStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 
-class CaseRangeStatement : public Statement
+class CaseRangeStatement final : public Statement
 {
 public:
     Expression *first;
     Expression *last;
     Statement *statement;
 
-    CaseRangeStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    CaseRangeStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 
-class DefaultStatement : public Statement
+class DefaultStatement final : public Statement
 {
 public:
     Statement *statement;
     VarDeclaration *lastVar;
 
-    DefaultStatement *syntaxCopy();
+    DefaultStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class GotoDefaultStatement : public Statement
+class GotoDefaultStatement final : public Statement
 {
 public:
     SwitchStatement *sw;
 
-    GotoDefaultStatement *syntaxCopy();
+    GotoDefaultStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class GotoCaseStatement : public Statement
+class GotoCaseStatement final : public Statement
 {
 public:
     Expression *exp;            // NULL, or which case to goto
     CaseStatement *cs;          // case statement it resolves to
 
-    GotoCaseStatement *syntaxCopy();
+    GotoCaseStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SwitchErrorStatement : public Statement
+class SwitchErrorStatement final : public Statement
 {
 public:
     Expression *exp;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ReturnStatement : public Statement
+class ReturnStatement final : public Statement
 {
 public:
     Expression *exp;
     size_t caseDim;
 
-    ReturnStatement *syntaxCopy();
+    ReturnStatement *syntaxCopy() override;
 
-    ReturnStatement *endsWithReturnStatement() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    ReturnStatement *endsWithReturnStatement() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class BreakStatement : public Statement
+class BreakStatement final : public Statement
 {
 public:
     Identifier *ident;
 
-    BreakStatement *syntaxCopy();
+    BreakStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ContinueStatement : public Statement
+class ContinueStatement final : public Statement
 {
 public:
     Identifier *ident;
 
-    ContinueStatement *syntaxCopy();
+    ContinueStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class SynchronizedStatement : public Statement
+class SynchronizedStatement final : public Statement
 {
 public:
     Expression *exp;
     Statement *_body;
 
-    SynchronizedStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    SynchronizedStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class WithStatement : public Statement
+class WithStatement final : public Statement
 {
 public:
     Expression *exp;
@@ -568,12 +570,12 @@  public:
     VarDeclaration *wthis;
     Loc endloc;
 
-    WithStatement *syntaxCopy();
+    WithStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TryCatchStatement : public Statement
+class TryCatchStatement final : public Statement
 {
 public:
     Statement *_body;
@@ -581,13 +583,13 @@  public:
 
     Statement *tryBody;   /// set to enclosing TryCatchStatement or TryFinallyStatement if in _body portion
 
-    TryCatchStatement *syntaxCopy();
-    bool hasBreak() const;
+    TryCatchStatement *syntaxCopy() override;
+    bool hasBreak() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class Catch : public RootObject
+class Catch final : public RootObject
 {
 public:
     Loc loc;
@@ -606,7 +608,7 @@  public:
     Catch *syntaxCopy();
 };
 
-class TryFinallyStatement : public Statement
+class TryFinallyStatement final : public Statement
 {
 public:
     Statement *_body;
@@ -616,25 +618,25 @@  public:
     bool bodyFallsThru;   // true if _body falls through to finally
 
     static TryFinallyStatement *create(const Loc &loc, Statement *body, Statement *finalbody);
-    TryFinallyStatement *syntaxCopy();
-    bool hasBreak() const;
-    bool hasContinue() const;
+    TryFinallyStatement *syntaxCopy() override;
+    bool hasBreak() const override;
+    bool hasContinue() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ScopeGuardStatement : public Statement
+class ScopeGuardStatement final : public Statement
 {
 public:
     TOK tok;
     Statement *statement;
 
-    ScopeGuardStatement *syntaxCopy();
+    ScopeGuardStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ThrowStatement : public Statement
+class ThrowStatement final : public Statement
 {
 public:
     Expression *exp;
@@ -642,21 +644,21 @@  public:
     // wasn't present in source code
     bool internalThrow;
 
-    ThrowStatement *syntaxCopy();
+    ThrowStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class DebugStatement : public Statement
+class DebugStatement final : public Statement
 {
 public:
     Statement *statement;
 
-    DebugStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    DebugStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class GotoStatement : public Statement
+class GotoStatement final : public Statement
 {
 public:
     Identifier *ident;
@@ -666,12 +668,12 @@  public:
     ScopeGuardStatement *os;
     VarDeclaration *lastVar;
 
-    GotoStatement *syntaxCopy();
+    GotoStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class LabelStatement : public Statement
+class LabelStatement final : public Statement
 {
 public:
     Identifier *ident;
@@ -684,12 +686,12 @@  public:
     void* extra;                // used by Statement_toIR()
     bool breaks;                // someone did a 'break ident'
 
-    LabelStatement *syntaxCopy();
+    LabelStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class LabelDsymbol : public Dsymbol
+class LabelDsymbol final : public Dsymbol
 {
 public:
     LabelStatement *statement;
@@ -698,8 +700,8 @@  public:
     bool iasm;              // set if used by inline assembler
 
     static LabelDsymbol *create(Identifier *ident);
-    LabelDsymbol *isLabel();
-    void accept(Visitor *v) { v->visit(this); }
+    LabelDsymbol *isLabel() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 Statement* asmSemantic(AsmStatement *s, Scope *sc);
@@ -709,11 +711,11 @@  class AsmStatement : public Statement
 public:
     Token *tokens;
 
-    AsmStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    AsmStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class InlineAsmStatement : public AsmStatement
+class InlineAsmStatement final : public AsmStatement
 {
 public:
     code *asmcode;
@@ -722,12 +724,12 @@  public:
     bool refparam;              // true if function parameter is referenced
     bool naked;                 // true if function is to be naked
 
-    InlineAsmStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    InlineAsmStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // A GCC asm statement - assembler instructions with D expression operands
-class GccAsmStatement : public AsmStatement
+class GccAsmStatement final : public AsmStatement
 {
 public:
     StorageClass stc;           // attributes of the asm {} block
@@ -740,27 +742,27 @@  public:
     Identifiers *labels;        // list of goto labels
     GotoStatements *gotos;      // of the goto labels, the equivalent statements they represent
 
-    GccAsmStatement *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    GccAsmStatement *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 // a complete asm {} block
-class CompoundAsmStatement : public CompoundStatement
+class CompoundAsmStatement final : public CompoundStatement
 {
 public:
     StorageClass stc; // postfix attributes like nothrow/pure/@trusted
 
-    CompoundAsmStatement *syntaxCopy();
+    CompoundAsmStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class ImportStatement : public Statement
+class ImportStatement final : public Statement
 {
 public:
     Dsymbols *imports;          // Array of Import's
 
-    ImportStatement *syntaxCopy();
+    ImportStatement *syntaxCopy() override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index a7ad84f8504..ed47b916c0a 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -1616,9 +1616,8 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
     static FuncExp foreachBodyToFunction(Scope* sc, ForeachStatement fs, TypeFunction tfld)
     {
         auto params = new Parameters();
-        foreach (i; 0 .. fs.parameters.dim)
+        foreach (i, p; *fs.parameters)
         {
-            Parameter p = (*fs.parameters)[i];
             StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
             Identifier id;
 
@@ -3929,7 +3928,7 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             cas.error("`asm` statement is assumed to use the GC - mark it with `@nogc` if it does not");
         if (!(cas.stc & (STC.trusted | STC.safe)))
         {
-            sc.func.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
+            sc.setUnsafe(false, cas.loc, "`asm` statement is assumed to be `@system` - mark it with `@trusted` if it is not");
         }
 
         sc.pop();
@@ -4034,9 +4033,9 @@  void catchSemantic(Catch c, Scope* sc)
             error(c.loc, "catching C++ class objects not supported for this target");
             c.errors = true;
         }
-        if (sc.func && !sc.intypeof && !c.internalCatch)
+        if (!c.internalCatch)
         {
-            if (sc.func.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
+            if (sc.setUnsafe(false, c.loc, "cannot catch C++ class objects in `@safe` code"))
                 c.errors = true;
         }
     }
@@ -4045,9 +4044,9 @@  void catchSemantic(Catch c, Scope* sc)
         error(c.loc, "can only catch class objects derived from `Throwable`, not `%s`", c.type.toChars());
         c.errors = true;
     }
-    else if (sc.func && !sc.intypeof && !c.internalCatch && ClassDeclaration.exception &&
+    else if (!c.internalCatch && ClassDeclaration.exception &&
             cd != ClassDeclaration.exception && !ClassDeclaration.exception.isBaseOf(cd, null) &&
-            sc.func.setUnsafe(false, c.loc,
+            sc.setUnsafe(false, c.loc,
                 "can only catch class objects derived from `Exception` in `@safe` code, not `%s`", c.type))
     {
         c.errors = true;
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
index 38142bc6efc..d9389901469 100644
--- a/gcc/d/dmd/staticassert.h
+++ b/gcc/d/dmd/staticassert.h
@@ -20,10 +20,10 @@  public:
     Expression *exp;
     Expression *msg;
 
-    StaticAssert *syntaxCopy(Dsymbol *s);
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    const char *kind() const;
-    StaticAssert *isStaticAssert() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    StaticAssert *syntaxCopy(Dsymbol *s) override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    const char *kind() const override;
+    StaticAssert *isStaticAssert() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 86863769141..9ad027a8647 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -28,15 +28,15 @@  class Expression;
 class FuncDeclaration;
 class Parameter;
 
-class Tuple : public RootObject
+class Tuple final : public RootObject
 {
 public:
     Objects objects;
 
     // kludge for template.isType()
-    DYNCAST dyncast() const { return DYNCAST_TUPLE; }
+    DYNCAST dyncast() const override { return DYNCAST_TUPLE; }
 
-    const char *toChars() const { return objects.toChars(); }
+    const char *toChars() const override { return objects.toChars(); }
 };
 
 struct TemplatePrevious
@@ -46,7 +46,7 @@  struct TemplatePrevious
     Objects *dedargs;
 };
 
-class TemplateDeclaration : public ScopeDsymbol
+class TemplateDeclaration final : public ScopeDsymbol
 {
 public:
     TemplateParameters *parameters;     // array of TemplateParameter's
@@ -74,24 +74,24 @@  public:
 
     TemplatePrevious *previous;         // threaded list of previous instantiation attempts on stack
 
-    TemplateDeclaration *syntaxCopy(Dsymbol *);
-    bool overloadInsert(Dsymbol *s);
-    bool hasStaticCtorOrDtor();
-    const char *kind() const;
-    const char *toChars() const;
+    TemplateDeclaration *syntaxCopy(Dsymbol *) override;
+    bool overloadInsert(Dsymbol *s) override;
+    bool hasStaticCtorOrDtor() override;
+    const char *kind() const override;
+    const char *toChars() const override;
 
-    Visibility visible();
+    Visibility visible() override;
 
     MATCH leastAsSpecialized(Scope *sc, TemplateDeclaration *td2, Expressions *fargs);
     RootObject *declareParameter(Scope *sc, TemplateParameter *tp, RootObject *o);
 
-    TemplateDeclaration *isTemplateDeclaration() { return this; }
+    TemplateDeclaration *isTemplateDeclaration() override { return this; }
 
     TemplateTupleParameter *isVariadic();
-    bool isDeprecated() const;
-    bool isOverloadable() const;
+    bool isDeprecated() const override;
+    bool isOverloadable() const override;
 
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* For type-parameter:
@@ -134,10 +134,12 @@  public:
     virtual RootObject *defaultArg(const Loc &instLoc, Scope *sc) = 0;
     virtual bool hasDefaultArg() = 0;
 
+    DYNCAST dyncast() const override { return DYNCAST_TEMPLATEPARAMETER; }
+
     /* Create dummy argument based on parameter.
      */
     virtual RootObject *dummyArg() = 0;
-    void accept(Visitor *v) { v->visit(this); }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Syntax:
@@ -149,85 +151,85 @@  public:
     Type *specType;     // type parameter: if !=NULL, this is the type specialization
     Type *defaultType;
 
-    TemplateTypeParameter *isTemplateTypeParameter();
-    TemplateTypeParameter *syntaxCopy();
-    bool declareParameter(Scope *sc);
-    void print(RootObject *oarg, RootObject *oded);
-    RootObject *specialization();
-    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
-    bool hasDefaultArg();
-    RootObject *dummyArg();
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateTypeParameter *isTemplateTypeParameter() override final;
+    TemplateTypeParameter *syntaxCopy() override;
+    bool declareParameter(Scope *sc) override final;
+    void print(RootObject *oarg, RootObject *oded) override final;
+    RootObject *specialization() override final;
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc) override final;
+    bool hasDefaultArg() override final;
+    RootObject *dummyArg() override final;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Syntax:
  *  this ident : specType = defaultType
  */
-class TemplateThisParameter : public TemplateTypeParameter
+class TemplateThisParameter final : public TemplateTypeParameter
 {
 public:
-    TemplateThisParameter *isTemplateThisParameter();
-    TemplateThisParameter *syntaxCopy();
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateThisParameter *isTemplateThisParameter() override;
+    TemplateThisParameter *syntaxCopy() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Syntax:
  *  valType ident : specValue = defaultValue
  */
-class TemplateValueParameter : public TemplateParameter
+class TemplateValueParameter final : public TemplateParameter
 {
 public:
     Type *valType;
     Expression *specValue;
     Expression *defaultValue;
 
-    TemplateValueParameter *isTemplateValueParameter();
-    TemplateValueParameter *syntaxCopy();
-    bool declareParameter(Scope *sc);
-    void print(RootObject *oarg, RootObject *oded);
-    RootObject *specialization();
-    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
-    bool hasDefaultArg();
-    RootObject *dummyArg();
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateValueParameter *isTemplateValueParameter() override;
+    TemplateValueParameter *syntaxCopy() override;
+    bool declareParameter(Scope *sc) override;
+    void print(RootObject *oarg, RootObject *oded) override;
+    RootObject *specialization() override;
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+    bool hasDefaultArg() override;
+    RootObject *dummyArg() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Syntax:
  *  specType ident : specAlias = defaultAlias
  */
-class TemplateAliasParameter : public TemplateParameter
+class TemplateAliasParameter final : public TemplateParameter
 {
 public:
     Type *specType;
     RootObject *specAlias;
     RootObject *defaultAlias;
 
-    TemplateAliasParameter *isTemplateAliasParameter();
-    TemplateAliasParameter *syntaxCopy();
-    bool declareParameter(Scope *sc);
-    void print(RootObject *oarg, RootObject *oded);
-    RootObject *specialization();
-    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
-    bool hasDefaultArg();
-    RootObject *dummyArg();
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateAliasParameter *isTemplateAliasParameter() override;
+    TemplateAliasParameter *syntaxCopy() override;
+    bool declareParameter(Scope *sc) override;
+    void print(RootObject *oarg, RootObject *oded) override;
+    RootObject *specialization() override;
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+    bool hasDefaultArg() override;
+    RootObject *dummyArg() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Syntax:
  *  ident ...
  */
-class TemplateTupleParameter : public TemplateParameter
+class TemplateTupleParameter final : public TemplateParameter
 {
 public:
-    TemplateTupleParameter *isTemplateTupleParameter();
-    TemplateTupleParameter *syntaxCopy();
-    bool declareParameter(Scope *sc);
-    void print(RootObject *oarg, RootObject *oded);
-    RootObject *specialization();
-    RootObject *defaultArg(const Loc &instLoc, Scope *sc);
-    bool hasDefaultArg();
-    RootObject *dummyArg();
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateTupleParameter *isTemplateTupleParameter() override;
+    TemplateTupleParameter *syntaxCopy() override;
+    bool declareParameter(Scope *sc) override;
+    void print(RootObject *oarg, RootObject *oded) override;
+    RootObject *specialization() override;
+    RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
+    bool hasDefaultArg() override;
+    RootObject *dummyArg() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 /* Given:
@@ -275,36 +277,36 @@  private:
 public:
     unsigned char inuse;                 // for recursive expansion detection
 
-    TemplateInstance *syntaxCopy(Dsymbol *);
-    Dsymbol *toAlias();                 // resolve real symbol
-    const char *kind() const;
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    const char *toChars() const;
-    const char* toPrettyCharsHelper();
-    Identifier *getIdent();
+    TemplateInstance *syntaxCopy(Dsymbol *) override;
+    Dsymbol *toAlias() override final;   // resolve real symbol
+    const char *kind() const override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    const char *toChars() const override;
+    const char* toPrettyCharsHelper() override final;
+    Identifier *getIdent() override final;
     hash_t toHash();
 
     bool isDiscardable();
     bool needsCodegen();
 
-    TemplateInstance *isTemplateInstance() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateInstance *isTemplateInstance() override final { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class TemplateMixin : public TemplateInstance
+class TemplateMixin final : public TemplateInstance
 {
 public:
     TypeQualified *tqual;
 
-    TemplateMixin *syntaxCopy(Dsymbol *s);
-    const char *kind() const;
-    bool oneMember(Dsymbol **ps, Identifier *ident);
-    bool hasPointers();
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
-    const char *toChars() const;
+    TemplateMixin *syntaxCopy(Dsymbol *s) override;
+    const char *kind() const override;
+    bool oneMember(Dsymbol **ps, Identifier *ident) override;
+    bool hasPointers() override;
+    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
+    const char *toChars() const override;
 
-    TemplateMixin *isTemplateMixin() { return this; }
-    void accept(Visitor *v) { v->visit(this); }
+    TemplateMixin *isTemplateMixin() override { return this; }
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
 Expression *isExpression(RootObject *o);
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 0acad6ae14a..25dee7f4185 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -423,12 +423,20 @@  package mixin template ParseVisitMethods(AST)
         //printf("Visiting TypeQualified\n");
         foreach (id; t.idents)
         {
-            if (id.dyncast() == DYNCAST.dsymbol)
+            switch(id.dyncast()) with(DYNCAST)
+            {
+            case dsymbol:
                 (cast(AST.TemplateInstance)id).accept(this);
-            else if (id.dyncast() == DYNCAST.expression)
+                break;
+            case expression:
                 (cast(AST.Expression)id).accept(this);
-            else if (id.dyncast() == DYNCAST.type)
+                break;
+            case type:
                 (cast(AST.Type)id).accept(this);
+                break;
+            default:
+                break;
+            }
         }
     }
 
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index ac4c23b0605..4c9ca28f2fc 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -239,9 +239,10 @@  private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
     for (size_t i = 0; i < mt.idents.dim; i++)
     {
         RootObject id = mt.idents[i];
-        if (id.dyncast() == DYNCAST.expression ||
-            id.dyncast() == DYNCAST.type)
+        switch (id.dyncast()) with (DYNCAST)
         {
+        case expression:
+        case type:
             Type tx;
             Expression ex;
             Dsymbol sx;
@@ -259,6 +260,8 @@  private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
             ex = ex.expressionSemantic(sc);
             resolveExp(ex, pt, pe, ps);
             return;
+        default:
+            break;
         }
 
         Type t = s.getType(); // type symbol, type alias, or type tuple?
@@ -2799,21 +2802,20 @@  void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
                 }
 
                 RootObject o = (*tup.objects)[cast(size_t)d];
-                if (o.dyncast() == DYNCAST.dsymbol)
+                switch (o.dyncast()) with (DYNCAST)
                 {
+                case dsymbol:
                     return returnSymbol(cast(Dsymbol)o);
-                }
-                if (o.dyncast() == DYNCAST.expression)
-                {
+                case expression:
                     Expression e = cast(Expression)o;
                     if (e.op == EXP.dSymbol)
                         return returnSymbol(e.isDsymbolExp().s);
                     else
                         return returnExp(e);
-                }
-                if (o.dyncast() == DYNCAST.type)
-                {
+                case type:
                     return returnType((cast(Type)o).addMod(mt.mod));
+                default:
+                    break;
                 }
 
                 /* Create a new TupleDeclaration which
diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h
index afc455784aa..b76393bc1ec 100644
--- a/gcc/d/dmd/version.h
+++ b/gcc/d/dmd/version.h
@@ -12,30 +12,30 @@ 
 
 #include "dsymbol.h"
 
-class DebugSymbol : public Dsymbol
+class DebugSymbol final : public Dsymbol
 {
 public:
     unsigned level;
 
-    DebugSymbol *syntaxCopy(Dsymbol *);
+    DebugSymbol *syntaxCopy(Dsymbol *) override;
 
-    const char *toChars() const;
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    const char *kind() const;
-    DebugSymbol *isDebugSymbol();
-    void accept(Visitor *v) { v->visit(this); }
+    const char *toChars() const override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    const char *kind() const override;
+    DebugSymbol *isDebugSymbol() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
 
-class VersionSymbol : public Dsymbol
+class VersionSymbol final : public Dsymbol
 {
 public:
     unsigned level;
 
-    VersionSymbol *syntaxCopy(Dsymbol *);
+    VersionSymbol *syntaxCopy(Dsymbol *) override;
 
-    const char *toChars() const;
-    void addMember(Scope *sc, ScopeDsymbol *sds);
-    const char *kind() const;
-    VersionSymbol *isVersionSymbol();
-    void accept(Visitor *v) { v->visit(this); }
+    const char *toChars() const override;
+    void addMember(Scope *sc, ScopeDsymbol *sds) override;
+    const char *kind() const override;
+    VersionSymbol *isVersionSymbol() override;
+    void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 5d6b94ccd02..b45ef790de3 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -265,6 +265,8 @@  class ShlAssignExp;
 class ShrAssignExp;
 class UshrAssignExp;
 class CatAssignExp;
+class CatElemAssignExp;
+class CatDcharAssignExp;
 class AddExp;
 class MinExp;
 class CatExp;
@@ -564,6 +566,10 @@  public:
     virtual void visit(UshrAssignExp *e) { visit((BinAssignExp *)e); }
     virtual void visit(CatAssignExp *e) { visit((BinAssignExp *)e); }
 
+    // CatAssignExp
+    virtual void visit(CatElemAssignExp *e) { visit((CatAssignExp *)e); }
+    virtual void visit(CatDcharAssignExp *e) { visit((CatAssignExp *)e); }
+
     // TemplateParameter
     virtual void visit(TemplateAliasParameter *tp) { visit((TemplateParameter *)tp); }
     virtual void visit(TemplateTypeParameter *tp) { visit((TemplateParameter *)tp); }
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index c2635827ad3..954eb9a22f1 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -372,6 +372,10 @@  fpreview=fixaliasthis
 D RejectNegative
 When a symbol is resolved, check `alias this' scope before going to upper scopes.
 
+fpreview=fiximmutableconv
+D RejectNegative
+Disallow unsound immutable conversions that were formerly incorrectly permitted.
+
 fpreview=in
 D RejectNegative
 Implement 'in' parameters to mean scope const.
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index 534f8661b3e..1ad0369a75d 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -145,10 +145,6 @@  DEF_D_RUNTIME (ARRAYAPPENDCD, "_d_arrayappendcd", RT(ARRAY_VOID),
 DEF_D_RUNTIME (ARRAYAPPENDWD, "_d_arrayappendwd", RT(ARRAY_VOID),
 	       P2(ARRAYPTR_BYTE, DCHAR), 0)
 
-/* Used for appending an existing array to another.  */
-DEF_D_RUNTIME (ARRAYAPPENDT, "_d_arrayappendT", RT(ARRAY_VOID),
-	       P3(TYPEINFO, ARRAYPTR_BYTE, ARRAY_BYTE), 0)
-
 /* Used for allocating a new associative array.  */
 DEF_D_RUNTIME (ASSOCARRAYLITERALTX, "_d_assocarrayliteralTX", RT(VOIDPTR),
 	       P3(CONST_TYPEINFO, ARRAY_VOID, ARRAY_VOID), 0)
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
index de4c7ba4247..169b7b15364 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_ClassDeclaration.d
@@ -142,8 +142,8 @@  class B : public A, public I1, public I2
 {
 public:
     using A::bar;
-    void foo();
-    void bar();
+    void foo() final override;
+    void bar() override;
 };
 
 class Parent
@@ -157,7 +157,7 @@  public:
 class Child final : public Parent
 {
 public:
-    void foo() /* const */;
+    void foo() override;
 };
 
 class VisitorBase
@@ -289,7 +289,7 @@  interface I2 : I1
 class B : A, I1, I2
 {
     alias bar = A.bar;
-    override void foo() {}
+    override final void foo() {}
     override void bar() {}
 }
 
@@ -303,7 +303,7 @@  class Parent
 final class Child : Parent
 {
     extern(D) override void over() {}
-    override void foo() const {}
+    override void foo() {}
 }
 
 class VisitorBase
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
index 35c4ed7e03f..1e2be909e75 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
@@ -160,7 +160,7 @@  class Child final : public Parent<T >
 {
 public:
     T childMember;
-    void parentVirtual();
+    void parentVirtual() override;
     T childFinal();
 };
 
diff --git a/gcc/testsuite/gdc.test/compilable/test22865.d b/gcc/testsuite/gdc.test/compilable/test22865.d
new file mode 100644
index 00000000000..0f4026279e0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22865.d
@@ -0,0 +1,35 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22865
+
+// Test that safety errors inside speculative scopes don't affect attribute inference
+
+void main() @safe
+{
+    foo();
+}
+
+__gshared int g;
+
+auto foo()
+{
+    alias x0 = typeof(g++);
+    alias x1 = typeof(cast(int*) 0);
+
+    auto x2 = __traits(compiles, g++);
+    enum x3 = __traits(compiles, (cast(int*) 0));
+
+    debug
+    {
+        g++;
+        const x4 = cast(int*) 0;
+        asm { }
+    }
+}
+
+// Test that safety violations still occur if the function is inside the __traits(compiles)
+
+static assert(!__traits(compiles, {
+    void f() @safe
+    {
+        g++;
+    }
+}));
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
new file mode 100644
index 00000000000..bf51363c07e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
@@ -0,0 +1,59 @@ 
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/dip1000_deprecation.d(20): Deprecation: `@safe` function `main` calling `inferred`
+fail_compilation/dip1000_deprecation.d(28):        which would be `@system` because of:
+fail_compilation/dip1000_deprecation.d(28):        scope variable `x0` may not be returned
+fail_compilation/dip1000_deprecation.d(22): Deprecation: `@safe` function `main` calling `inferredC`
+fail_compilation/dip1000_deprecation.d(39):        which calls `dip1000_deprecation.inferred`
+fail_compilation/dip1000_deprecation.d(28):        which would be `@system` because of:
+fail_compilation/dip1000_deprecation.d(28):        scope variable `x0` may not be returned
+fail_compilation/dip1000_deprecation.d(54): Deprecation: escaping reference to stack allocated value returned by `S(null)`
+fail_compilation/dip1000_deprecation.d(55): Deprecation: escaping reference to stack allocated value returned by `createS()`
+fail_compilation/dip1000_deprecation.d(58): Deprecation: returning `s.incorrectReturnRef()` escapes a reference to local variable `s`
+---
+*/
+
+void main() @safe
+{
+    inferred();
+    inferredB(); // no deprecation, trusted
+    inferredC(); // nested deprecation
+}
+
+auto inferred()
+{
+    scope int* x0;
+    return x0;
+}
+
+auto inferredB() @trusted
+{
+    scope int* x1;
+    return x1;
+}
+
+auto inferredC()
+{
+    return inferred(); // no deprecation, inferredC is not explicit `@safe`
+}
+
+@safe:
+
+struct S
+{
+    int* ptr;
+    int* incorrectReturnRef() scope return @trusted {return ptr;}
+}
+
+S createS() { return S.init; }
+
+int* escape()
+{
+    return S().incorrectReturnRef();
+    return createS().incorrectReturnRef();
+
+    S s;
+    return s.incorrectReturnRef();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip25.d b/gcc/testsuite/gdc.test/fail_compilation/dip25.d
index 41bfe49e484..02f31407754 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dip25.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dip25.d
@@ -19,7 +19,7 @@  struct Data
 }
 
 ref int identity(return ref int x) @safe { return x; }
-ref int fun(return int x) { return identity(x); }
+ref int fun(return int x) @safe { return identity(x); }
 ref int fun2(ref int x) @safe { return identity(x); }
 
 void main()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
index dd28163adb7..5c852a1ac91 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12390.d
@@ -1,7 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail12390.d(14): Error: `fun().i == 4` has no effect
+fail_compilation/fail12390.d(15): Error: the result of the equality expression `fun().i == 4` is discarded
+fail_compilation/fail12390.d(15):        note that `fun().i` may have a side effect
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22351.d b/gcc/testsuite/gdc.test/fail_compilation/fail22351.d
new file mode 100644
index 00000000000..405ab557d75
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22351.d
@@ -0,0 +1,20 @@ 
+/* https://issues.dlang.org/show_bug.cgi?id=22351
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/fail22351.d(18): Deprecation: overriding `extern(C++)` function `fail22351.C22351.func(int*)` with `const` qualified function `fail22351.Fail22351.func(const(int*))` is deprecated
+fail_compilation/fail22351.d(18):        Either remove `override`, or adjust the `const` qualifiers of the overriding function parameters
+fail_compilation/fail22351.d(19): Error: function `extern (C++) void fail22351.Fail22351.func(const(int*)**)` does not override any function, did you mean to override `extern (C++) void fail22351.C22351.func(int*)`?
+---
+*/
+extern(C++) class C22351
+{
+    void func(int*) { }
+    void func(int***) { }
+}
+
+extern(C++) final class Fail22351 : C22351
+{
+    override void func(const int*) { }
+    override void func(const(int*)**) { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23135.d b/gcc/testsuite/gdc.test/fail_compilation/fail23135.d
new file mode 100644
index 00000000000..d32c6aeef51
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23135.d
@@ -0,0 +1,17 @@ 
+/* https://issues.dlang.org/show_bug.cgi?id=23135
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/fail23135.d(16): Deprecation: overriding `extern(C++)` function `fail23135.C23135.func()` with `const` qualified function `fail23135.Fail23135.func() const` is deprecated
+fail_compilation/fail23135.d(16):        Either remove `override`, or adjust the `const` qualifiers of the overriding function type
+---
+*/
+extern(C++) class C23135
+{
+    void func() { }
+}
+
+extern(C++) final class Fail23135 : C23135
+{
+    override void func() const { }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
index 153e90b034a..3e7637ff667 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
@@ -13,7 +13,7 @@  fail_compilation/fail_scope.d(82): Error: returning `& string` escapes a referen
 fail_compilation/fail_scope.d(92): Error: returning `cast(int[])a` escapes a reference to local variable `a`
 fail_compilation/fail_scope.d(100): Error: returning `cast(int[])a` escapes a reference to local variable `a`
 fail_compilation/fail_scope.d(108): Deprecation: escaping reference to outer local variable `x`
-fail_compilation/fail_scope.d(127): Error: returning `s.bar()` escapes a reference to local variable `s`
+fail_compilation/fail_scope.d(127): Deprecation: returning `s.bar()` escapes a reference to local variable `s`
 fail_compilation/fail_scope.d(137): Error: returning `foo16226(i)` escapes a reference to local variable `i`
 ---
 //fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix22108.d b/gcc/testsuite/gdc.test/fail_compilation/fix22108.d
new file mode 100644
index 00000000000..149bebae0ea
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix22108.d
@@ -0,0 +1,13 @@ 
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fix22108.d(12): Error: scope variable `p` may not be returned
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=22108
+
+@safe ref int test(ref scope return int* p)
+{
+    return *p;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fix23138.d b/gcc/testsuite/gdc.test/fail_compilation/fix23138.d
new file mode 100644
index 00000000000..58766c86b7b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fix23138.d
@@ -0,0 +1,16 @@ 
+/* TEST_OUTPUT:
+---
+fail_compilation/fix23138.d(14): Error: function `fix23138.C2.foo` cannot override `@safe` method `fix23138.C1.foo` with a `@system` attribute
+---
+ */
+
+class C1 {
+    void foo() @safe
+    {}
+}
+
+class C2 : C1
+{
+    override void foo() @system
+    {}
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15660.d b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
index be244d78e71..ae573b2af2a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15660.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
@@ -1,4 +1,4 @@ 
-/* REQUIRED_ARGS: -preview=dip1000
+/* REQUIRED_ARGS: -preview=fixImmutableConv
 TEST_OUTPUT:
 ---
 fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18484.d b/gcc/testsuite/gdc.test/fail_compilation/test18484.d
index d604f380a18..e51647b3491 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test18484.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18484.d
@@ -19,7 +19,7 @@  int* test1() @safe
     auto x = S(); return x.bar();  // error
 }
 
-int* test2()
+int* test2() @safe
 {
     return S().bar();  // error
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20881.d b/gcc/testsuite/gdc.test/fail_compilation/test20881.d
index 72826352af2..d4c5f07bea5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test20881.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20881.d
@@ -2,6 +2,7 @@ 
 REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
+fail_compilation/test20881.d(20): Error: scope variable `this` may not be returned
 fail_compilation/test20881.d(27): Error: address of variable `s` assigned to `global` with longer lifetime
 fail_compilation/test20881.d(28): Error: address of variable `s` assigned to `global` with longer lifetime
 fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `global` with longer lifetime
@@ -10,7 +11,6 @@  fail_compilation/test20881.d(29): Error: address of variable `s` assigned to `gl
 @safe:
 
 // https://issues.dlang.org/show_bug.cgi?id=20881
-
 struct S
 {
     int* ptr;
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp
new file mode 100644
index 00000000000..ad70d0a01d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test22351.cpp
@@ -0,0 +1,46 @@ 
+#include <assert.h>
+
+class A22351
+{
+public:
+    virtual int f();
+    virtual int g(int *);
+    virtual int h();
+    virtual int h() const;
+};
+
+class B22351 : public A22351
+{
+public:
+    virtual int f() const;
+    virtual int g(const int *);
+    int h() const override;
+};
+
+B22351 *createB();
+
+int main()
+{
+    // mutable A calls functions in A vtable
+    A22351 *a = createB();
+    assert(a->f() == 1);
+    assert(a->g(0) == 3);
+    assert(a->h() == 5);
+
+    // cast to B calls functions in B vtable
+    B22351 *b = (B22351 *)a;
+    assert(b->f() == 2);
+    assert(b->g(0) == 4);
+    assert(b->h() == 6);
+
+    // cast to const calls B override function
+    const A22351 *ca = a;
+    assert(ca->h() == 6);
+
+    // const B calls functions in B vtable
+    const B22351 *cb = createB();
+    assert(cb->f() == 2);
+    assert(cb->h() == 6);
+
+    return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp
new file mode 100644
index 00000000000..d4193c95669
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/test23135.cpp
@@ -0,0 +1,52 @@ 
+class Mutable
+{
+public:
+    virtual ~Mutable();
+    virtual void func();
+};
+
+Mutable::~Mutable()
+{
+}
+
+class DeriveMutable final : public Mutable
+{
+public:
+    virtual ~DeriveMutable();
+    void func() override;
+};
+
+DeriveMutable::~DeriveMutable()
+{
+}
+
+class Const
+{
+public:
+    virtual ~Const();
+    virtual void func() const;
+};
+
+Const::~Const()
+{
+}
+
+class DeriveConst final : public Const
+{
+public:
+    virtual ~DeriveConst();
+    void func() const override;
+};
+
+DeriveConst::~DeriveConst()
+{
+}
+
+void test23135()
+{
+    DeriveMutable mut;
+    mut.func();
+
+    DeriveConst cst;
+    cst.func();
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test22351.d b/gcc/testsuite/gdc.test/runnable_cxx/test22351.d
new file mode 100644
index 00000000000..1c930b6ea82
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test22351.d
@@ -0,0 +1,55 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22351
+// EXTRA_CPP_SOURCES: test22351.cpp
+// REQUIRED_ARGS: -extern-std=c++11
+// CXXFLAGS: -std=c++11
+// DISABLED: win32
+
+extern(C++) class A22351
+{
+    int f()
+    {
+        return 1;
+    }
+
+    int g(int*)
+    {
+        return 3;
+    }
+
+    int h()
+    {
+        return 5;
+    }
+
+    int h() const
+    {
+        return 7;
+    }
+}
+
+extern(C++) class B22351 : A22351
+{
+    alias f = A22351.f;
+    alias g = A22351.g;
+    alias h = A22351.h;
+
+    int f() const
+    {
+        return 2;
+    }
+
+    int g(const(int)*)
+    {
+        return 4;
+    }
+
+    override int h() const
+    {
+        return 6;
+    }
+}
+
+extern(C++) B22351 createB()
+{
+    return new B22351;
+}
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/test23135.d b/gcc/testsuite/gdc.test/runnable_cxx/test23135.d
new file mode 100644
index 00000000000..4a184bb7924
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/test23135.d
@@ -0,0 +1,38 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=23135
+// EXTRA_CPP_SOURCES: test23135.cpp
+// REQUIRED_ARGS: -extern-std=c++11
+// CXXFLAGS: -std=c++11
+// DISABLED: win32
+
+void main()
+{
+    test23135();
+}
+
+extern(C++):
+
+void test23135();
+
+class Mutable
+{
+    ~this();
+    void func() { }
+}
+
+final class DeriveMutable : Mutable
+{
+    ~this();
+    override void func() { }
+}
+
+class Const
+{
+    ~this();
+    void func() const { }
+}
+
+final class DeriveConst : Const
+{
+    ~this();
+    override void func() const { }
+}
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 1a9faf9be04..d503bae835c 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-94bd5bcb448405d90bc50113d1cfd45a0880a50d
+f89da31331ef5df50d3bc7a26efd1b7acdefde8c
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d
index 5d4f3b498f9..d416efe1c50 100644
--- a/libphobos/libdruntime/core/internal/array/appending.d
+++ b/libphobos/libdruntime/core/internal/array/appending.d
@@ -85,20 +85,35 @@  ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @
     import core.internal.traits : hasElaborateCopyConstructor, Unqual;
     import core.lifetime : copyEmplace;
 
+    enum hasPostblit = __traits(hasPostblit, T);
     auto length = x.length;
 
     _d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length);
 
-    static if (hasElaborateCopyConstructor!T)
+    // Only call `copyEmplace` if `T` has a copy ctor and no postblit.
+    static if (hasElaborateCopyConstructor!T && !hasPostblit)
     {
         foreach (i, ref elem; y)
             copyEmplace(elem, x[length + i]);
     }
     else
     {
-        // blit all elements at once
         if (y.length)
-            memcpy(cast(Unqual!T *)&x[length], cast(Unqual!T *)&y[0], y.length * T.sizeof);
+        {
+            // blit all elements at once
+            auto xptr = cast(Unqual!T *)&x[length];
+            immutable size = T.sizeof;
+
+            memcpy(xptr, cast(Unqual!T *)&y[0], y.length * size);
+
+            // call postblits if they exist
+            static if (hasPostblit)
+            {
+                auto eptr = xptr + y.length;
+                for (auto ptr = xptr; ptr < eptr; ptr++)
+                    ptr.__xpostblit();
+            }
+        }
     }
 
     return x;
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index b63b11100c1..7d1356af0be 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -38,7 +38,7 @@ 
  *
  * Notes_to_implementors:
  * $(UL
- * $(LI On POSIX systems, the signals SIGUSR1 and SIGUSR2 are reserved
+ * $(LI On POSIX systems, the signals `SIGRTMIN` and `SIGRTMIN + 1` are reserved
  *   by this module for use in the garbage collector implementation.
  *   Typically, they will be used to stop and resume other threads
  *   when performing a collection, but an implementation may choose
diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d
index bd53eed2d10..efbad7d6b74 100644
--- a/libphobos/libdruntime/core/thread/fiber.d
+++ b/libphobos/libdruntime/core/thread/fiber.d
@@ -653,14 +653,9 @@  class Fiber
      */
     this( void delegate() dg, size_t sz = PAGESIZE * defaultStackPages,
           size_t guardPageSize = PAGESIZE ) nothrow
-    in
-    {
-        assert( dg );
-    }
-    do
     {
         allocStack( sz, guardPageSize );
-        reset( dg );
+        reset( cast(void delegate() const) dg );
     }
 
 
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 1bbce3f858d..ef073a93324 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -1251,7 +1251,7 @@  version (CoreDdoc)
 {
     /**
      * Instruct the thread module, when initialized, to use a different set of
-     * signals besides SIGUSR1 and SIGUSR2 for suspension and resumption of threads.
+     * signals besides SIGRTMIN and SIGRTMIN + 1 for suspension and resumption of threads.
      * This function should be called at most once, prior to thread_init().
      * This function is Posix-only.
      */
@@ -1281,8 +1281,8 @@  else version (Posix)
 
 version (Posix)
 {
-    private __gshared int suspendSignalNumber = SIGUSR1;
-    private __gshared int resumeSignalNumber  = SIGUSR2;
+    private __gshared int suspendSignalNumber;
+    private __gshared int resumeSignalNumber;
 }
 
 private extern (D) ThreadBase attachThread(ThreadBase _thisThread) @nogc nothrow
@@ -2115,11 +2115,6 @@  extern (C) void thread_init() @nogc
     initLowlevelThreads();
     Thread.initLocks();
 
-    // The Android VM runtime intercepts SIGUSR1 and apparently doesn't allow
-    // its signal handler to run, so swap the two signals on Android, since
-    // thread_resumeHandler does nothing.
-    version (Android) thread_setGCSignals(SIGUSR2, SIGUSR1);
-
     version (Darwin)
     {
         // thread id different in forked child process
@@ -2135,6 +2130,16 @@  extern (C) void thread_init() @nogc
     }
     else version (Posix)
     {
+        if ( suspendSignalNumber == 0 )
+        {
+            suspendSignalNumber = SIGRTMIN;
+        }
+
+        if ( resumeSignalNumber == 0 )
+        {
+            resumeSignalNumber = SIGRTMIN + 1;
+            assert(resumeSignalNumber <= SIGRTMAX);
+        }
         int         status;
         sigaction_t suspend = void;
         sigaction_t resume = void;
diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d
index 9042a365242..505be000c56 100644
--- a/libphobos/libdruntime/core/thread/threadbase.d
+++ b/libphobos/libdruntime/core/thread/threadbase.d
@@ -108,8 +108,8 @@  class ThreadBase
         m_call = fn;
     }
 
-    this(void delegate() dg, size_t sz = 0) @safe pure nothrow @nogc
-    in(dg)
+    this(void delegate() dg, size_t sz = 0) @trusted pure nothrow @nogc
+    in( cast(void delegate() const) dg)
     {
         this(sz);
         m_call = dg;
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index 3a88552f302..fe65c0973e1 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -1481,7 +1481,7 @@  class TypeInfo_Delegate : TypeInfo
 
     override size_t getHash(scope const void* p) @trusted const
     {
-        return hashOf(*cast(void delegate()*)p);
+        return hashOf(*cast(const void delegate() *)p);
     }
 
     override bool equals(in void* p1, in void* p2) const
@@ -4428,7 +4428,7 @@  nothrow @safe @nogc unittest
     }
 }
 
-private extern (C) void rt_finalize(void *data, bool det=true) nothrow;
+private extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true) nothrow;
 
 /// ditto
 void destroy(bool initialize = true, T)(T obj) if (is(T == class))
@@ -4448,7 +4448,7 @@  void destroy(bool initialize = true, T)(T obj) if (is(T == class))
     {
         // Bypass overloaded opCast
         auto ptr = (() @trusted => *cast(void**) &obj)();
-        rt_finalize(ptr);
+        rt_finalize2(ptr, true, initialize);
     }
 }
 
@@ -4723,6 +4723,25 @@  nothrow unittest
     destroy(B.init);
 }
 
+// make sure destroy!false skips re-initialization
+unittest
+{
+    static struct S { int x; }
+    static class C { int x; }
+    static extern(C++) class Cpp { int x; }
+
+    static void test(T)(T inst)
+    {
+        inst.x = 123;
+        destroy!false(inst);
+        assert(inst.x == 123, T.stringof);
+    }
+
+    test(S());
+    test(new C());
+    test(new Cpp());
+}
+
 /// ditto
 void destroy(bool initialize = true, T)(ref T obj)
 if (__traits(isStaticArray, T))
diff --git a/libphobos/libdruntime/rt/arrayassign.d b/libphobos/libdruntime/rt/arrayassign.d
index 21d50b0413a..9a34ec750f1 100644
--- a/libphobos/libdruntime/rt/arrayassign.d
+++ b/libphobos/libdruntime/rt/arrayassign.d
@@ -162,45 +162,6 @@  extern (C) void[] _d_arrayassign_r(TypeInfo ti, void[] src, void[] dst, void* pt
     return dst;
 }
 
-/**
- * Does array initialization (not assignment) from another
- * array of the same element type.
- * ti is the element type.
- */
-extern (C) void[] _d_arrayctor(TypeInfo ti, void[] from, void[] to)
-{
-    debug(PRINTF) printf("_d_arrayctor(from = %p,%d, to = %p,%d) size = %d\n", from.ptr, from.length, to.ptr, to.length, ti.tsize);
-
-
-    auto element_size = ti.tsize;
-
-    enforceRawArraysConformable("initialization", element_size, from, to);
-
-    size_t i;
-    try
-    {
-        for (i = 0; i < to.length; i++)
-        {
-            // Copy construction is defined as bit copy followed by postblit.
-            memcpy(to.ptr + i * element_size, from.ptr + i * element_size, element_size);
-            ti.postblit(to.ptr + i * element_size);
-        }
-    }
-    catch (Throwable o)
-    {
-        /* Destroy, in reverse order, what we've constructed so far
-         */
-        while (i--)
-        {
-            ti.destroy(to.ptr + i * element_size);
-        }
-
-        throw o;
-    }
-    return to;
-}
-
-
 /**
  * Do assignment to an array.
  *      p[0 .. count] = value;
@@ -227,36 +188,3 @@  extern (C) void* _d_arraysetassign(void* p, void* value, int count, TypeInfo ti)
         free(ptmp);
     return pstart;
 }
-
-/**
- * Do construction of an array.
- *      ti[count] p = value;
- */
-extern (C) void* _d_arraysetctor(void* p, void* value, int count, TypeInfo ti)
-{
-    void* pstart = p;
-    auto element_size = ti.tsize;
-
-    try
-    {
-        foreach (i; 0 .. count)
-        {
-            // Copy construction is defined as bit copy followed by postblit.
-            memcpy(p, value, element_size);
-            ti.postblit(p);
-            p += element_size;
-        }
-    }
-    catch (Throwable o)
-    {
-        // Destroy, in reverse order, what we've constructed so far
-        while (p > pstart)
-        {
-            p -= element_size;
-            ti.destroy(p);
-        }
-
-        throw o;
-    }
-    return pstart;
-}
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 96d9a804d7c..5a18968f6ee 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -163,23 +163,6 @@  extern (C) void _d_delclass(Object* p) @weak
     }
 }
 
-/**
- * This is called for a delete statement where the value
- * being deleted is a pointer to a struct with a destructor
- * but doesn't have an overloaded delete operator.
- */
-extern (C) void _d_delstruct(void** p, TypeInfo_Struct inf) @weak
-{
-    if (*p)
-    {
-        debug(PRINTF) printf("_d_delstruct(%p, %p)\n", *p, cast(void*)inf);
-
-        inf.destroy(*p);
-        GC.free(*p);
-        *p = null;
-    }
-}
-
 // strip const/immutable/shared/inout from type info
 inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc
 {
@@ -1872,23 +1855,6 @@  do
     return *p;
 }
 
-/**
- * Append y[] to array x[]
- */
-extern (C) void[] _d_arrayappendT(const TypeInfo ti, ref byte[] x, byte[] y) @weak
-{
-    import core.stdc.string;
-    auto length = x.length;
-    auto tinext = unqualify(ti.next);
-    auto sizeelem = tinext.tsize;              // array element size
-    _d_arrayappendcTX(ti, x, y.length);
-    memcpy(x.ptr + length * sizeelem, y.ptr, y.length * sizeelem);
-
-    // do postblit
-    __doPostblit(x.ptr + length * sizeelem, y.length * sizeelem, tinext);
-    return x;
-}
-
 
 /**
  *
@@ -2606,11 +2572,6 @@  deprecated unittest
         }
     }
 
-    dtorCount = 0;
-    S1* s1 = new S1;
-    _d_delstruct(cast(void**)&s1, typeid(typeof(*s1))); // delete s1;
-    assert(dtorCount == 1);
-
     dtorCount = 0;
     S1[] arr1 = new S1[7];
     _d_delarray_t(cast(void[]*)&arr1, typeid(typeof(arr1[0]))); // delete arr1;
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 3de142fe009..ddf730ef333 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-3a1cd9a01479155958c7799e573e55a93dd189a0
+d46814c86392007ebb4fb73cb684ef9e8caa605a
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/package.d b/libphobos/src/std/package.d
index a1d04444d62..bfb135b1885 100644
--- a/libphobos/src/std/package.d
+++ b/libphobos/src/std/package.d
@@ -35,6 +35,7 @@  public import
  std.base64,
  std.bigint,
  std.bitmanip,
+ std.checkedint,
  std.compiler,
  std.complex,
  std.concurrency,
@@ -50,6 +51,7 @@  public import
  std.format,
  std.functional,
  std.getopt,
+ std.int128,
  std.json,
  std.math,
  std.mathspecial,
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 28bfb049c2b..d4fe8a1c7e8 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -613,7 +613,7 @@  private:
  * writefln("Current process ID: %d", thisProcessID);
  * ---
  */
-@property int thisProcessID() @trusted nothrow //TODO: @safe
+@property int thisProcessID() @trusted nothrow @nogc //TODO: @safe
 {
     version (Windows)    return GetCurrentProcessId();
     else version (Posix) return core.sys.posix.unistd.getpid();
@@ -632,7 +632,7 @@  private:
  * writefln("Current thread ID: %s", thisThreadID);
  * ---
  */
-@property ThreadID thisThreadID() @trusted nothrow //TODO: @safe
+@property ThreadID thisThreadID() @trusted nothrow @nogc //TODO: @safe
 {
     version (Windows)
         return GetCurrentThreadId();
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index f0200ce7052..d22dac8b15d 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -4275,10 +4275,10 @@  private int impureVariable;
  *                            UseReplacementDchar.no means throw `UTFException` for invalid UTF
  *
  * Throws:
- *      `UTFException` if invalid UTF sequence and `useReplacementDchar` is set to `UseReplacementDchar.yes`
+ *      `UTFException` if invalid UTF sequence and `useReplacementDchar` is set to `UseReplacementDchar.no`
  *
  * GC:
- *      Does not use GC if `useReplacementDchar` is set to `UseReplacementDchar.no`
+ *      Does not use GC if `useReplacementDchar` is set to `UseReplacementDchar.yes`
  *
  * Returns:
  *      A bidirectional range if `R` is a bidirectional range and not auto-decodable,