[gcc r12-7306] d: Merge upstream dmd cb49e99f8, druntime 55528bd1, phobos 1a3e80ec2.

Iain Buclaw ibuclaw@gcc.gnu.org
Sun Feb 20 22:38:16 GMT 2022


https://gcc.gnu.org/g:6384eff56dba1fac071c1b525f7e49cf03f2737f

commit r12-7306-g6384eff56dba1fac071c1b525f7e49cf03f2737f
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Sun Feb 20 20:02:23 2022 +0100

    d: Merge upstream dmd cb49e99f8, druntime 55528bd1, phobos 1a3e80ec2.
    
    D front-end changes:
    
        - Import dmd v2.099.0-beta.1.
        - It's now an error to use `alias this' for partial assignment.
        - The `delete' keyword has been removed from the language.
        - Using `this' and `super' as types has been removed from the
          language, the parser no longer specially handles this wrong code
          with an informative error.
    
    D Runtime changes:
    
        - Import druntime v2.099.0-beta.1.
    
    Phobos changes:
    
        - Import phobos v2.099.0-beta.1.
    
    gcc/d/ChangeLog:
    
            * dmd/MERGE: Merge upstream dmd cb49e99f8.
            * dmd/VERSION: Update version to v2.099.0-beta.1.
            * decl.cc (layout_class_initializer): Update call to NewExp::create.
            * expr.cc (ExprVisitor::visit (DeleteExp *)): Remove handling of
            deleting arrays and pointers.
            (ExprVisitor::visit (DotVarExp *)): Convert complex types to the
            front-end library type representing them.
            (ExprVisitor::visit (StringExp *)): Use getCodeUnit instead of charAt
            to get the value of each index in a string expression.
            * runtime.def (DELMEMORY): Remove.
            (DELARRAYT): Remove.
            * types.cc (TypeVisitor::visit (TypeEnum *)): Handle anonymous enums.
    
    libphobos/ChangeLog:
    
            * libdruntime/MERGE: Merge upstream druntime 55528bd1.
            * src/MERGE: Merge upstream phobos 1a3e80ec2.
            * testsuite/libphobos.hash/test_hash.d: Update.
            * testsuite/libphobos.betterc/test19933.d: New test.

Diff:
---
 gcc/d/decl.cc                                      |    2 +-
 gcc/d/dmd/MERGE                                    |    2 +-
 gcc/d/dmd/VERSION                                  |    2 +-
 gcc/d/dmd/apply.d                                  |    4 +-
 gcc/d/dmd/canthrow.d                               |   12 +-
 gcc/d/dmd/clone.d                                  |   37 +-
 gcc/d/dmd/constfold.d                              |    6 +-
 gcc/d/dmd/cparse.d                                 |   27 +-
 gcc/d/dmd/ctfeexpr.d                               |    2 +-
 gcc/d/dmd/dcast.d                                  | 4267 ++++++++++----------
 gcc/d/dmd/declaration.d                            |    5 +-
 gcc/d/dmd/declaration.h                            |    1 -
 gcc/d/dmd/dinterpret.d                             |  106 +-
 gcc/d/dmd/dmangle.d                                |    3 +-
 gcc/d/dmd/dmodule.d                                |   78 +-
 gcc/d/dmd/dscope.d                                 |    2 +-
 gcc/d/dmd/dsymbol.d                                |   11 +-
 gcc/d/dmd/dsymbol.h                                |    2 +
 gcc/d/dmd/dsymbolsem.d                             |  184 +-
 gcc/d/dmd/dtemplate.d                              |   52 +-
 gcc/d/dmd/dtoh.d                                   |   24 +-
 gcc/d/dmd/escape.d                                 |    2 +-
 gcc/d/dmd/expression.d                             |  115 +-
 gcc/d/dmd/expression.h                             |   17 +-
 gcc/d/dmd/expressionsem.d                          |  304 +-
 gcc/d/dmd/func.d                                   |    3 +-
 gcc/d/dmd/hdrgen.d                                 |   70 +-
 gcc/d/dmd/iasmgcc.d                                |    2 +-
 gcc/d/dmd/id.d                                     |    4 -
 gcc/d/dmd/importc.d                                |   47 +
 gcc/d/dmd/initsem.d                                |    4 +
 gcc/d/dmd/lexer.d                                  |  444 +-
 gcc/d/dmd/mtype.d                                  |   45 +-
 gcc/d/dmd/nogc.d                                   |   42 +-
 gcc/d/dmd/opover.d                                 |  342 +-
 gcc/d/dmd/optimize.d                               |    7 -
 gcc/d/dmd/parse.d                                  |  794 ++--
 gcc/d/dmd/printast.d                               |   10 +
 gcc/d/dmd/semantic2.d                              |    2 +-
 gcc/d/dmd/semantic3.d                              |   22 +-
 gcc/d/dmd/statementsem.d                           |  206 +-
 gcc/d/dmd/staticassert.d                           |    5 +
 gcc/d/dmd/staticassert.h                           |    1 +
 gcc/d/dmd/tokens.d                                 |  120 +-
 gcc/d/dmd/tokens.h                                 |   13 +-
 gcc/d/dmd/transitivevisitor.d                      |    4 -
 gcc/d/dmd/typesem.d                                |   80 +-
 gcc/d/expr.cc                                      |   46 +-
 gcc/d/runtime.def                                  |    7 -
 gcc/d/types.cc                                     |   14 +-
 gcc/testsuite/gdc.dg/special1.d                    |   12 +
 gcc/testsuite/gdc.test/compilable/99bottles.d      |  212 +-
 gcc/testsuite/gdc.test/compilable/b18242.d         |    6 +-
 gcc/testsuite/gdc.test/compilable/b19294.d         |   10 +-
 gcc/testsuite/gdc.test/compilable/b20938.d         |    6 +-
 gcc/testsuite/gdc.test/compilable/b21285.d         |   10 +-
 gcc/testsuite/gdc.test/compilable/commontype.d     |    9 +-
 gcc/testsuite/gdc.test/compilable/ddoc10.d         |    2 +-
 gcc/testsuite/gdc.test/compilable/ddoc11.d         |    2 +-
 gcc/testsuite/gdc.test/compilable/ddoc14.d         |    2 +-
 gcc/testsuite/gdc.test/compilable/ddoc3.d          |    2 +-
 gcc/testsuite/gdc.test/compilable/ddoc5.d          |    4 +-
 gcc/testsuite/gdc.test/compilable/ddoc5446.d       |   22 +-
 gcc/testsuite/gdc.test/compilable/ddoc9155.d       |   10 +-
 gcc/testsuite/gdc.test/compilable/debugInference.d |    6 +-
 gcc/testsuite/gdc.test/compilable/defa.d           |    2 +-
 gcc/testsuite/gdc.test/compilable/dlangui_crash.d  |   34 +
 .../gdc.test/compilable/enumbasearithmetic.d       |   20 +
 gcc/testsuite/gdc.test/compilable/header18364.d    |    2 +-
 gcc/testsuite/gdc.test/compilable/imports/b33a.d   |    4 +-
 .../gdc.test/compilable/imports/imp22734.c         |    3 +
 .../gdc.test/compilable/imports/test22714a.d       |    3 +
 .../gdc.test/compilable/imports/test22714b.d       |   12 +
 gcc/testsuite/gdc.test/compilable/issue16472.d     |   42 +
 gcc/testsuite/gdc.test/compilable/issue21340.d     |    4 +-
 gcc/testsuite/gdc.test/compilable/issue21813b.d    |    2 +-
 gcc/testsuite/gdc.test/compilable/minimal.d        |    2 +-
 gcc/testsuite/gdc.test/compilable/test10993.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test16107.d      |    6 +-
 gcc/testsuite/gdc.test/compilable/test17545.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test17906.d      |    7 -
 gcc/testsuite/gdc.test/compilable/test18030.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test19014.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test19315.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test19557.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test19609.d      |    4 +-
 gcc/testsuite/gdc.test/compilable/test21177.d      |   76 +
 gcc/testsuite/gdc.test/compilable/test21196.d      |   71 +
 gcc/testsuite/gdc.test/compilable/test22224.d      |    2 +-
 gcc/testsuite/gdc.test/compilable/test22632.d      |    4 +
 gcc/testsuite/gdc.test/compilable/test22714.d      |    3 +
 gcc/testsuite/gdc.test/compilable/test22734.d      |    6 +
 gcc/testsuite/gdc.test/compilable/test4375.d       |    6 +-
 gcc/testsuite/gdc.test/compilable/test7172.d       |    2 +-
 gcc/testsuite/gdc.test/compilable/test8296.d       |    4 +-
 gcc/testsuite/gdc.test/compilable/test8513.d       |    8 +-
 gcc/testsuite/gdc.test/compilable/testpostblit.d   |    2 +-
 gcc/testsuite/gdc.test/compilable/testsctreturn.d  |   16 +
 gcc/testsuite/gdc.test/compilable/typeid_name.d    |    2 +-
 gcc/testsuite/gdc.test/compilable/vgc1.d           |   17 +-
 gcc/testsuite/gdc.test/fail_compilation/b20011.d   |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/b3841.d    |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/bug16165.d |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/bug8150a.d |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/bug8150b.d |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/ccast.d    |    2 +-
 .../gdc.test/fail_compilation/ctfe14731.d          |    2 +-
 .../gdc.test/fail_compilation/diag10319.d          |    2 +-
 .../gdc.test/fail_compilation/diag10805.d          |    2 +-
 .../gdc.test/fail_compilation/diag13281.d          |    6 +-
 .../gdc.test/fail_compilation/diag15713.d          |    4 +-
 .../gdc.test/fail_compilation/diag16977.d          |    4 +-
 .../gdc.test/fail_compilation/dtor_attributes.d    |    2 +-
 .../gdc.test/fail_compilation/fail10964.d          |    2 +-
 .../gdc.test/fail_compilation/fail11375.d          |    2 +-
 .../gdc.test/fail_compilation/fail11542.d          |    8 +-
 .../gdc.test/fail_compilation/fail12809.d          |    8 +-
 .../gdc.test/fail_compilation/fail14277.d          |   10 +
 .../gdc.test/fail_compilation/fail14486.d          |   45 +-
 .../gdc.test/fail_compilation/fail14554.d          |    4 +-
 .../gdc.test/fail_compilation/fail15089.d          |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail160.d  |    2 +-
 .../gdc.test/fail_compilation/fail17906.d          |   12 +
 .../gdc.test/fail_compilation/fail17969.d          |    2 +-
 .../gdc.test/fail_compilation/fail18228.d          |    6 +-
 .../gdc.test/fail_compilation/fail19441.d          |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail196.d  |   10 +-
 .../gdc.test/fail_compilation/fail19897.d          |    2 +-
 .../gdc.test/fail_compilation/fail19911b.d         |    2 +-
 .../gdc.test/fail_compilation/fail19911c.d         |    2 +-
 .../gdc.test/fail_compilation/fail19922.d          |    2 +-
 .../gdc.test/fail_compilation/fail19923.d          |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail20.d   |    2 +-
 .../gdc.test/fail_compilation/fail20800.d          |    2 +-
 .../gdc.test/fail_compilation/fail22127.d          |   11 +
 .../gdc.test/fail_compilation/fail22634.d          |   12 +
 .../gdc.test/fail_compilation/fail22780.d          |   12 +
 gcc/testsuite/gdc.test/fail_compilation/fail2361.d |    3 +-
 gcc/testsuite/gdc.test/fail_compilation/fail258.d  |   12 +-
 gcc/testsuite/gdc.test/fail_compilation/fail332.d  |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail349.d  |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail354.d  |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail4082.d |    4 +-
 .../gdc.test/fail_compilation/fail4269a.d          |    2 +-
 .../gdc.test/fail_compilation/fail4269b.d          |    2 +-
 .../gdc.test/fail_compilation/fail4269c.d          |    2 +-
 .../gdc.test/fail_compilation/fail4375d.d          |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail6968.d |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail7848.d |    4 +-
 .../gdc.test/fail_compilation/fail80_m32.d         |    2 +-
 .../gdc.test/fail_compilation/fail80_m64.d         |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/fail8724.d |    2 +-
 .../gdc.test/fail_compilation/fail_arrayop2.d      |    6 +-
 .../gdc.test/fail_compilation/fail_typeof.d        |   82 +
 .../gdc.test/fail_compilation/faildeleteaa.d       |    3 +-
 .../gdc.test/fail_compilation/ice10727a.d          |    2 +
 .../gdc.test/fail_compilation/ice10727b.d          |    2 +
 gcc/testsuite/gdc.test/fail_compilation/ice11968.d |    3 +-
 gcc/testsuite/gdc.test/fail_compilation/ice18753.d |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/lexer1.d   |    4 +-
 .../gdc.test/fail_compilation/no_Throwable.d       |    2 +-
 .../gdc.test/fail_compilation/no_TypeInfo.d        |    2 +-
 gcc/testsuite/gdc.test/fail_compilation/nogc1.d    |    9 +-
 .../gdc.test/fail_compilation/noreturn2.d          |    2 +-
 .../gdc.test/fail_compilation/scope_type.d         |    2 +-
 .../gdc.test/fail_compilation/test12228.d          |    6 +-
 .../gdc.test/fail_compilation/test16195.d          |    3 +-
 .../gdc.test/fail_compilation/test17307.d          |    2 +-
 .../gdc.test/fail_compilation/test20245.d          |   53 +-
 .../gdc.test/fail_compilation/test22145.d          |   28 +
 .../gdc.test/fail_compilation/test22686.d          |   21 +
 gcc/testsuite/gdc.test/runnable/b18034.d           |   10 +-
 gcc/testsuite/gdc.test/runnable/imports/a15079.d   |    2 +-
 gcc/testsuite/gdc.test/runnable/imports/a19a.d     |    2 +-
 .../gdc.test/runnable/imports/link12144a.d         |    2 +-
 .../gdc.test/runnable/imports/test11745b.d         |   12 +-
 gcc/testsuite/gdc.test/runnable/imports/test46c.d  |    2 +-
 gcc/testsuite/gdc.test/runnable/inline7625.d       |  185 +
 gcc/testsuite/gdc.test/runnable/interface.d        |   12 +-
 gcc/testsuite/gdc.test/runnable/interface2.d       |   11 +-
 gcc/testsuite/gdc.test/runnable/interpret.d        |   91 +-
 gcc/testsuite/gdc.test/runnable/link12144.d        |    6 -
 gcc/testsuite/gdc.test/runnable/link15017.d        |    8 +-
 gcc/testsuite/gdc.test/runnable/mixin1.d           |    7 +-
 gcc/testsuite/gdc.test/runnable/newdel.d           |    8 +-
 gcc/testsuite/gdc.test/runnable/sdtor.d            |   26 +-
 gcc/testsuite/gdc.test/runnable/test11934.d        |    2 +-
 gcc/testsuite/gdc.test/runnable/test17684.d        |   20 +-
 gcc/testsuite/gdc.test/runnable/test17899.d        |    2 +-
 gcc/testsuite/gdc.test/runnable/test20.d           |    8 +-
 gcc/testsuite/gdc.test/runnable/test22136.d        |   25 +
 gcc/testsuite/gdc.test/runnable/test22163.d        |   13 +
 gcc/testsuite/gdc.test/runnable/test22717.d        |   31 +
 gcc/testsuite/gdc.test/runnable/test4.d            |    8 +-
 gcc/testsuite/gdc.test/runnable/testappend.d       |   16 +-
 gcc/testsuite/gdc.test/runnable/testconst.d        |    4 +-
 gcc/testsuite/gdc.test/runnable/testdstress.d      |    8 +-
 gcc/testsuite/gdc.test/runnable/testptrref.d       |   10 +-
 gcc/testsuite/gdc.test/runnable/xpostblit.d        |    2 +-
 gcc/testsuite/gdc.test/runnable_cxx/cppa.d         |    2 +-
 libphobos/libdruntime/MERGE                        |    2 +-
 libphobos/libdruntime/__builtins.di                |   65 +
 libphobos/libdruntime/core/attribute.d             |   49 +
 libphobos/libdruntime/core/bitop.d                 |   13 -
 libphobos/libdruntime/core/int128.d                |    2 +
 .../libdruntime/core/internal/array/appending.d    |    8 +-
 .../libdruntime/core/internal/array/comparison.d   |   33 +-
 libphobos/libdruntime/core/internal/convert.d      |   22 -
 libphobos/libdruntime/core/lifetime.d              |    4 +-
 libphobos/libdruntime/core/math.d                  |    1 +
 libphobos/libdruntime/core/runtime.d               |    2 +-
 libphobos/libdruntime/core/stdc/stdio.d            |   17 +-
 libphobos/libdruntime/core/sys/linux/config.d      |    3 +
 libphobos/libdruntime/core/sys/linux/dlfcn.d       |   22 +-
 libphobos/libdruntime/core/sys/linux/errno.d       |    2 +-
 libphobos/libdruntime/core/sys/linux/netinet/in_.d |   10 +-
 libphobos/libdruntime/core/sys/linux/string.d      |    2 +-
 libphobos/libdruntime/core/sys/linux/sys/mman.d    |   72 +-
 libphobos/libdruntime/core/sys/posix/aio.d         |  132 +-
 libphobos/libdruntime/core/sys/posix/config.d      |   58 +-
 libphobos/libdruntime/core/sys/posix/spawn.d       |   12 +-
 libphobos/libdruntime/core/sys/posix/sys/ipc.d     |   65 +-
 libphobos/libdruntime/core/sys/posix/sys/mman.d    |    4 +-
 libphobos/libdruntime/core/sys/posix/sys/shm.d     |   12 +
 libphobos/libdruntime/core/sys/posix/sys/socket.d  |   32 +-
 libphobos/libdruntime/core/sys/posix/sys/stat.d    |   24 +-
 libphobos/libdruntime/core/sys/posix/sys/statvfs.d |    2 +-
 libphobos/libdruntime/core/sys/posix/sys/types.d   |    2 +-
 libphobos/libdruntime/object.d                     |    4 +-
 libphobos/libdruntime/rt/util/typeinfo.d           |  289 +-
 libphobos/src/MERGE                                |    2 +-
 libphobos/src/std/algorithm/internal.d             |    2 +
 libphobos/src/std/bigint.d                         |   16 +-
 libphobos/src/std/container/rbtree.d               |   16 +-
 libphobos/src/std/conv.d                           |    2 +-
 libphobos/src/std/file.d                           |   27 +-
 libphobos/src/std/functional.d                     |    9 +-
 libphobos/src/std/internal/math/biguintcore.d      |    6 +-
 libphobos/src/std/socket.d                         |   17 +-
 libphobos/src/std/sumtype.d                        |   20 +
 libphobos/src/std/typecons.d                       |   42 +-
 libphobos/src/std/uni/package.d                    |    2 +-
 libphobos/src/std/zip.d                            |   35 +-
 libphobos/testsuite/libphobos.betterc/test19933.d  |   11 +
 libphobos/testsuite/libphobos.hash/test_hash.d     |    2 +-
 245 files changed, 5541 insertions(+), 4939 deletions(-)

diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index b08d797c851..7ec0caf1bc0 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -2235,7 +2235,7 @@ aggregate_initializer_decl (AggregateDeclaration *decl)
 tree
 layout_class_initializer (ClassDeclaration *cd)
 {
-  NewExp *ne = NewExp::create (cd->loc, NULL, NULL, cd->type, NULL);
+  NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
   ne->type = cd->type;
 
   Expression *e = ne->ctfeInterpret ();
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 91cdc9f0692..b92f3760e88 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-52844d4b1e9d6714bfd2e535f25a72074a046209
+cb49e99f80e8111c71035b88fe47fe7d855c300f
 
 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/VERSION b/gcc/d/dmd/VERSION
index 0aa03f4b61a..12042fff7ec 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.098.1
+v2.099.0-beta.1
diff --git a/gcc/d/dmd/apply.d b/gcc/d/dmd/apply.d
index 75b4af1f1d8..ac2c80ef64e 100644
--- a/gcc/d/dmd/apply.d
+++ b/gcc/d/dmd/apply.d
@@ -110,13 +110,13 @@ public:
     override void visit(NewExp e)
     {
         //printf("NewExp::apply(): %s\n", toChars());
-        doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
+        doCond(e.thisexp) || doCond(e.arguments) || applyTo(e);
     }
 
     override void visit(NewAnonClassExp e)
     {
         //printf("NewAnonClassExp::apply(): %s\n", toChars());
-        doCond(e.thisexp) || doCond(e.newargs) || doCond(e.arguments) || applyTo(e);
+        doCond(e.thisexp) || doCond(e.arguments) || applyTo(e);
     }
 
     override void visit(TypeidExp e)
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index faf427d6735..745e552a8e2 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -114,9 +114,7 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
                         import dmd.id : Id;
 
                         auto sd = ts.sym;
-                        if (sd.dtor && ce.f.ident == Id._d_delstruct)
-                            checkFuncThrows(ce, sd.dtor);
-                        else if (sd.postblit &&
+                        if (sd.postblit &&
                             (ce.f.ident == Id._d_arrayctor || ce.f.ident == Id._d_arraysetctor))
                         {
                             checkFuncThrows(ce, sd.postblit);
@@ -175,14 +173,6 @@ extern (C++) /* CT */ BE canThrow(Expression e, FuncDeclaration func, bool mustN
                 ad = tb.isTypeClass().sym;
                 break;
 
-            case Tpointer:
-            case Tarray:
-                auto ts = tb.nextOf().baseElemOf().isTypeStruct();
-                if (!ts)
-                    return;
-                ad = ts.sym;
-                break;
-
             default:
                 assert(0);  // error should have been detected by semantic()
             }
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 1a143cb8c7f..a6dbd8e281a 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -521,9 +521,9 @@ FuncDeclaration buildOpEquals(StructDeclaration sd, Scope* sc)
 
 /******************************************
  * Build __xopEquals for TypeInfo_Struct
- *      static bool __xopEquals(ref const S p, ref const S q)
+ *      bool __xopEquals(ref const S p) const
  *      {
- *          return p == q;
+ *          return this == p;
  *      }
  *
  * This is called by TypeInfo.equals(p1, p2). If the struct does not support
@@ -570,14 +570,15 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
     Loc declLoc; // loc is unnecessary so __xopEquals is never called directly
     Loc loc; // loc is unnecessary so errors are gagged
     auto parameters = new Parameters();
-    parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null))
-              .push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
-    auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d);
+    parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
+    auto tf = new TypeFunction(ParameterList(parameters), Type.tbool, LINK.d, STC.const_);
+    tf = tf.addSTC(STC.const_).toTypeFunction();
     Identifier id = Id.xopEquals;
-    auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
+    auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
     fop.generated = true;
-    Expression e1 = new IdentifierExp(loc, Id.p);
-    Expression e2 = new IdentifierExp(loc, Id.q);
+    fop.parent = sd;
+    Expression e1 = new IdentifierExp(loc, Id.This);
+    Expression e2 = new IdentifierExp(loc, Id.p);
     Expression e = new EqualExp(EXP.equal, loc, e1, e2);
     fop.fbody = new ReturnStatement(loc, e);
     uint errors = global.startGagging(); // Do not report errors
@@ -594,9 +595,9 @@ FuncDeclaration buildXopEquals(StructDeclaration sd, Scope* sc)
 
 /******************************************
  * Build __xopCmp for TypeInfo_Struct
- *      static bool __xopCmp(ref const S p, ref const S q)
+ *      int __xopCmp(ref const S p) const
  *      {
- *          return p.opCmp(q);
+ *          return this.opCmp(p);
  *      }
  *
  * This is called by TypeInfo.compare(p1, p2). If the struct does not support
@@ -691,17 +692,15 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
     Loc loc; // loc is unnecessary so errors are gagged
     auto parameters = new Parameters();
     parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.p, null, null));
-    parameters.push(new Parameter(STC.ref_ | STC.const_, sd.type, Id.q, null, null));
-    auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d);
+    auto tf = new TypeFunction(ParameterList(parameters), Type.tint32, LINK.d, STC.const_);
+    tf = tf.addSTC(STC.const_).toTypeFunction();
     Identifier id = Id.xopCmp;
-    auto fop = new FuncDeclaration(declLoc, Loc.initial, id, STC.static_, tf);
+    auto fop = new FuncDeclaration(declLoc, Loc.initial, id, 0, tf);
     fop.generated = true;
-    Expression e1 = new IdentifierExp(loc, Id.p);
-    Expression e2 = new IdentifierExp(loc, Id.q);
-    version (IN_GCC)
-        Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
-    else
-        Expression e = new CallExp(loc, new DotIdExp(loc, e2, Id.cmp), e1);
+    fop.parent = sd;
+    Expression e1 = new IdentifierExp(loc, Id.This);
+    Expression e2 = new IdentifierExp(loc, Id.p);
+    Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
     fop.fbody = new ReturnStatement(loc, e);
     uint errors = global.startGagging(); // Do not report errors
     Scope* sc2 = sc.push();
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 16f7b2f4019..7bc890f9ae2 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -827,9 +827,9 @@ UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e
         else
         {
             cmp = 1; // if dim1 winds up being 0
-            for (size_t i = 0; i < dim1; i++)
+            foreach (i; 0 .. dim1)
             {
-                uinteger_t c = es1.charAt(i);
+                uinteger_t c = es1.getCodeUnit(i);
                 auto ee2 = es2[i];
                 if (ee2.isConst() != 1)
                 {
@@ -1247,7 +1247,7 @@ UnionExp Index(Type type, Expression e1, Expression e2)
         }
         else
         {
-            emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
+            emplaceExp!(IntegerExp)(&ue, loc, es1.getCodeUnit(cast(size_t) i), type);
         }
     }
     else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 38a78a0b013..0fe645906b7 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -197,6 +197,7 @@ final class CParser(AST) : Parser!AST
             }
             break;
 
+        case TOK.charLiteral:
         case TOK.int32Literal:
         case TOK.uns32Literal:
         case TOK.int64Literal:
@@ -264,6 +265,7 @@ final class CParser(AST) : Parser!AST
         case TOK.const_:
         case TOK.volatile:
         case TOK.restrict:
+        case TOK.__stdcall:
 
         // alignment-specifier
         case TOK._Alignas:
@@ -635,6 +637,7 @@ final class CParser(AST) : Parser!AST
             nextToken();
             break;
 
+        case TOK.charLiteral:
         case TOK.int32Literal:
             e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tint32);
             nextToken();
@@ -1585,7 +1588,7 @@ final class CParser(AST) : Parser!AST
         if (tspec && specifier.mod & MOD.xconst)
         {
             tspec = toConst(tspec);
-            specifier.mod = MOD.xnone;          // 'used' it
+            specifier.mod &= ~MOD.xnone;          // 'used' it
         }
 
         bool first = true;
@@ -1708,7 +1711,7 @@ final class CParser(AST) : Parser!AST
                         symbols.push(stag);
                         if (tt.tok == TOK.enum_)
                         {
-                            if (!tt.members)
+                            if (!stag.members)
                                 error(tt.loc, "`enum %s` has no members", stag.toChars());
                             isalias = false;
                             s = new AST.AliasDeclaration(token.loc, id, stag);
@@ -1842,8 +1845,8 @@ final class CParser(AST) : Parser!AST
             /* Since there were declarations, the parameter-list must have been
              * an identifier-list.
              */
+            ft.parameterList.hasIdentifierList = true;        // semantic needs to know to adjust parameter types
             auto pl = ft.parameterList;
-            pl.hasIdentifierList = true;        // semantic needs to know to adjust parameter types
             if (pl.varargs != AST.VarArg.none && pl.length)
                 error("function identifier-list cannot end with `...`");
             ft.parameterList.varargs = AST.VarArg.variadic;     // but C11 allows extra arguments
@@ -2071,6 +2074,7 @@ final class CParser(AST) : Parser!AST
                 case TOK.const_:     modx = MOD.xconst;     break;
                 case TOK.volatile:   modx = MOD.xvolatile;  break;
                 case TOK.restrict:   modx = MOD.xrestrict;  break;
+                case TOK.__stdcall:  modx = MOD.x__stdcall; break;
 
                 // Type specifiers
                 case TOK.char_:      tkwx = TKW.xchar;      break;
@@ -2409,6 +2413,13 @@ final class CParser(AST) : Parser!AST
                      *       T ((*fp))();
                      */
                     nextToken();
+
+                    if (token.value == TOK.__stdcall) // T (__stdcall*fp)();
+                    {
+                        specifier.mod |= MOD.x__stdcall;
+                        nextToken();
+                    }
+
                     ts = parseDecl(t);
                     check(TOK.rightParenthesis);
                     break;
@@ -2544,7 +2555,8 @@ final class CParser(AST) : Parser!AST
                         this.symbols = null;
 
                         auto parameterList = cparseParameterList();
-                        AST.Type tf = new AST.TypeFunction(parameterList, t, linkage, 0);
+                        const lkg = specifier.mod & MOD.x__stdcall ? LINK.windows : linkage;
+                        AST.Type tf = new AST.TypeFunction(parameterList, t, lkg, 0);
     //                  tf = tf.addSTC(storageClass);  // TODO
                         insertTx(ts, tf, t);  // ts -> ... -> tf -> t
 
@@ -2612,6 +2624,7 @@ final class CParser(AST) : Parser!AST
      *    restrict
      *    volatile
      *    _Atomic
+     *    __stdcall
      */
     MOD cparseTypeQualifierList()
     {
@@ -2624,6 +2637,7 @@ final class CParser(AST) : Parser!AST
                 case TOK.volatile:   mod |= MOD.xvolatile;  break;
                 case TOK.restrict:   mod |= MOD.xrestrict;  break;
                 case TOK._Atomic:    mod |= MOD.x_Atomic;   break;
+                case TOK.__stdcall:  mod |= MOD.x__stdcall; break;
 
                 default:
                     return mod;
@@ -3708,6 +3722,7 @@ final class CParser(AST) : Parser!AST
                 case TOK.const_:
                 case TOK.volatile:
                 case TOK.restrict:
+                case TOK.__stdcall:
                     t = peek(t);
                     any = true;
                     continue;
@@ -3948,6 +3963,7 @@ final class CParser(AST) : Parser!AST
                 case TOK.restrict:
                 case TOK.volatile:
                 case TOK._Atomic:
+                case TOK.__stdcall:
                     t = peek(t);
                     continue;
 
@@ -4000,6 +4016,7 @@ final class CParser(AST) : Parser!AST
                 case TOK.const_:
                 case TOK.restrict:
                 case TOK.volatile:
+                case TOK.__stdcall:
 
                 // Type Specifiers
                 case TOK.char_:
@@ -4202,6 +4219,7 @@ final class CParser(AST) : Parser!AST
         switch (t.value)
         {
             case TOK.identifier:
+            case TOK.charLiteral:
             case TOK.int32Literal:
             case TOK.uns32Literal:
             case TOK.int64Literal:
@@ -4283,6 +4301,7 @@ final class CParser(AST) : Parser!AST
         xvolatile = 2,
         xrestrict = 4,
         x_Atomic  = 8,
+        x__stdcall = 0x10, // Windows linkage extension
     }
 
     /**********************************
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 43dce4ba6d2..9bc453de189 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -1565,7 +1565,7 @@ Expression ctfeIndex(UnionExp* pue, const ref Loc loc, Type type, Expression e1,
             error(loc, "string index %llu is out of bounds `[0 .. %llu]`", indx, cast(ulong)es1.len);
             return CTFEExp.cantexp;
         }
-        emplaceExp!IntegerExp(pue, loc, es1.charAt(indx), type);
+        emplaceExp!IntegerExp(pue, loc, es1.getCodeUnit(cast(size_t) indx), type);
         return pue.exp();
     }
 
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 91b38618e23..f1afa76e53b 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -64,160 +64,151 @@ enum LOG = false;
  */
 Expression implicitCastTo(Expression e, Scope* sc, Type t)
 {
-    extern (C++) final class ImplicitCastTo : Visitor
+    Expression visit(Expression e)
     {
-        alias visit = Visitor.visit;
-    public:
-        Type t;
-        Scope* sc;
-        Expression result;
+        //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
 
-        extern (D) this(Scope* sc, Type t)
+        if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
         {
-            this.sc = sc;
-            this.t = t;
-        }
-
-        override void visit(Expression e)
-        {
-            //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+            if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t)))
+            {
+                /* Do not emit CastExp for const conversions and
+                 * unique conversions on rvalue.
+                 */
+                auto result = e.copy();
+                result.type = t;
+                return result;
+            }
 
-            if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
+            auto ad = isAggregate(e.type);
+            if (ad && ad.aliasthis)
             {
-                if (match == MATCH.constant && (e.type.constConv(t) || !e.isLvalue() && e.type.equivalent(t)))
-                {
-                    /* Do not emit CastExp for const conversions and
-                     * unique conversions on rvalue.
-                     */
-                    result = e.copy();
-                    result.type = t;
-                    return;
-                }
+                auto ts = ad.type.isTypeStruct();
+                const adMatch = ts
+                    ? ts.implicitConvToWithoutAliasThis(t)
+                    : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t);
 
-                auto ad = isAggregate(e.type);
-                if (ad && ad.aliasthis)
+                if (!adMatch)
                 {
-                    auto ts = ad.type.isTypeStruct();
-                    const adMatch = ts
-                        ? ts.implicitConvToWithoutAliasThis(t)
-                        : ad.type.isTypeClass().implicitConvToWithoutAliasThis(t);
-
-                    if (!adMatch)
+                    Type tob = t.toBasetype();
+                    Type t1b = e.type.toBasetype();
+                    if (ad != isAggregate(tob))
                     {
-                        Type tob = t.toBasetype();
-                        Type t1b = e.type.toBasetype();
-                        if (ad != isAggregate(tob))
+                        if (t1b.ty == Tclass && tob.ty == Tclass)
                         {
-                            if (t1b.ty == Tclass && tob.ty == Tclass)
+                            ClassDeclaration t1cd = t1b.isClassHandle();
+                            ClassDeclaration tocd = tob.isClassHandle();
+                            int offset;
+                            if (tocd.isBaseOf(t1cd, &offset))
                             {
-                                ClassDeclaration t1cd = t1b.isClassHandle();
-                                ClassDeclaration tocd = tob.isClassHandle();
-                                int offset;
-                                if (tocd.isBaseOf(t1cd, &offset))
-                                {
-                                    result = new CastExp(e.loc, e, t);
-                                    result.type = t;
-                                    return;
-                                }
+                                auto result = new CastExp(e.loc, e, t);
+                                result.type = t;
+                                return result;
                             }
+                        }
 
-                            /* Forward the cast to our alias this member, rewrite to:
-                             *   cast(to)e1.aliasthis
-                             */
-                            result = resolveAliasThis(sc, e);
-                            result = result.castTo(sc, t);
-                            return;
-                       }
-                    }
+                        /* Forward the cast to our alias this member, rewrite to:
+                         *   cast(to)e1.aliasthis
+                         */
+                        auto result = resolveAliasThis(sc, e);
+                        return result.castTo(sc, t);
+                   }
                 }
-
-                result = e.castTo(sc, t);
-                return;
             }
 
-            result = e.optimize(WANTvalue);
-            if (result != e)
-            {
-                result.accept(this);
-                return;
-            }
+            return e.castTo(sc, t);
+        }
 
-            if (t.ty != Terror && e.type.ty != Terror)
-            {
-                if (!t.deco)
-                {
-                    e.error("forward reference to type `%s`", t.toChars());
-                }
-                else
-                {
-                    //printf("type %p ty %d deco %p\n", type, type.ty, type.deco);
-                    //type = type.typeSemantic(loc, sc);
-                    //printf("type %s t %s\n", type.deco, t.deco);
-                    auto ts = toAutoQualChars(e.type, t);
-                    e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
-                        e.toChars(), ts[0], ts[1]);
-                }
-            }
-            result = ErrorExp.get();
+        auto result = e.optimize(WANTvalue);
+        if (result != e)
+        {
+            return implicitCastTo(result, sc, t);
         }
 
-        override void visit(StringExp e)
+        if (t.ty != Terror && e.type.ty != Terror)
         {
-            //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
-            visit(cast(Expression)e);
-            if (auto se = result.isStringExp())
+            if (!t.deco)
+            {
+                e.error("forward reference to type `%s`", t.toChars());
+            }
+            else
             {
-                // Retain polysemous nature if it started out that way
-                se.committed = e.committed;
+                //printf("type %p ty %d deco %p\n", type, type.ty, type.deco);
+                //type = type.typeSemantic(loc, sc);
+                //printf("type %s t %s\n", type.deco, t.deco);
+                auto ts = toAutoQualChars(e.type, t);
+                e.error("cannot implicitly convert expression `%s` of type `%s` to `%s`",
+                    e.toChars(), ts[0], ts[1]);
             }
         }
+        return ErrorExp.get();
+    }
 
-        override void visit(ErrorExp e)
+    Expression visitString(StringExp e)
+    {
+        //printf("StringExp::implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
+        auto result = visit(e);
+        if (auto se = result.isStringExp())
         {
-            result = e;
+            // Retain polysemous nature if it started out that way
+            se.committed = e.committed;
         }
+        return result;
+    }
+
+    Expression visitError(ErrorExp e)
+    {
+        return e;
+    }
 
-        override void visit(FuncExp e)
+    Expression visitFunc(FuncExp e)
+    {
+        //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
+        FuncExp fe;
+        if (e.matchType(t, sc, &fe) > MATCH.nomatch)
         {
-            //printf("FuncExp::implicitCastTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
-            FuncExp fe;
-            if (e.matchType(t, sc, &fe) > MATCH.nomatch)
-            {
-                result = fe;
-                return;
-            }
-            visit(cast(Expression)e);
+            return fe;
         }
+        return visit(e);
+    }
 
-        override void visit(ArrayLiteralExp e)
-        {
-            visit(cast(Expression)e);
+    Expression visitArrayLiteral(ArrayLiteralExp e)
+    {
+        auto result = visit(e);
 
-            Type tb = result.type.toBasetype();
-            if (auto ta = tb.isTypeDArray())
-                if (global.params.useTypeInfo && Type.dtypeinfo)
-                    semanticTypeInfo(sc, ta.next);
-        }
+        Type tb = result.type.toBasetype();
+        if (auto ta = tb.isTypeDArray())
+            if (global.params.useTypeInfo && Type.dtypeinfo)
+                semanticTypeInfo(sc, ta.next);
+        return result;
+    }
 
-        override void visit(SliceExp e)
-        {
-            visit(cast(Expression)e);
+    Expression visitSlice(SliceExp e)
+    {
+        auto result = visit(e);
 
-            if (auto se = result.isSliceExp())
-                if (auto ale = se.e1.isArrayLiteralExp())
-                {
-                    Type tb = t.toBasetype();
-                    Type tx = (tb.ty == Tsarray)
-                        ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0)
-                        : tb.nextOf().arrayOf();
-                    se.e1 = ale.implicitCastTo(sc, tx);
-                }
-        }
+        if (auto se = result.isSliceExp())
+            if (auto ale = se.e1.isArrayLiteralExp())
+            {
+                Type tb = t.toBasetype();
+                Type tx = (tb.ty == Tsarray)
+                    ? tb.nextOf().sarrayOf(ale.elements ? ale.elements.dim : 0)
+                    : tb.nextOf().arrayOf();
+                se.e1 = ale.implicitCastTo(sc, tx);
+            }
+
+        return result;
     }
 
-    scope ImplicitCastTo v = new ImplicitCastTo(sc, t);
-    e.accept(v);
-    return v.result;
+    switch (e.op)
+    {
+        default              : return visit            (e);
+        case EXP.string_     : return visitString      (e.isStringExp());
+        case EXP.error       : return visitError       (e.isErrorExp());
+        case EXP.function_   : return visitFunc        (e.isFuncExp());
+        case EXP.arrayLiteral: return visitArrayLiteral(e.isArrayLiteralExp());
+        case EXP.slice       : return visitSlice       (e.isSliceExp());
+    }
 }
 
 /**
@@ -236,1242 +227,1244 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
  */
 MATCH implicitConvTo(Expression e, Type t)
 {
-    extern (C++) final class ImplicitConvTo : Visitor
+    MATCH visit(Expression e)
     {
-        alias visit = Visitor.visit;
-    public:
-        Type t;
-        MATCH result;
+        version (none)
+        {
+            printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        //static int nest; if (++nest == 10) assert(0);
+        if (t == Type.terror)
+            return MATCH.nomatch;
+        if (!e.type)
+        {
+            e.error("`%s` is not an expression", e.toChars());
+            e.type = Type.terror;
+        }
 
-        extern (D) this(Type t)
+        Expression ex = e.optimize(WANTvalue);
+        if (ex.type.equals(t))
+        {
+            return MATCH.exact;
+        }
+        if (ex != e)
         {
-            this.t = t;
-            result = MATCH.nomatch;
+            //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars());
+            return ex.implicitConvTo(t);
         }
 
-        override void visit(Expression e)
+        MATCH match = e.type.implicitConvTo(t);
+        if (match != MATCH.nomatch)
         {
-            version (none)
-            {
-                printf("Expression::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            //static int nest; if (++nest == 10) assert(0);
-            if (t == Type.terror)
-                return;
-            if (!e.type)
-            {
-                e.error("`%s` is not an expression", e.toChars());
-                e.type = Type.terror;
-            }
+            return match;
+        }
 
-            Expression ex = e.optimize(WANTvalue);
-            if (ex.type.equals(t))
-            {
-                result = MATCH.exact;
-                return;
-            }
-            if (ex != e)
+        /* See if we can do integral narrowing conversions
+         */
+        if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic())
+        {
+            IntRange src = getIntRange(e);
+            IntRange target = IntRange.fromType(t);
+            if (target.contains(src))
             {
-                //printf("\toptimized to %s of type %s\n", e.toChars(), e.type.toChars());
-                result = ex.implicitConvTo(t);
-                return;
+                return MATCH.convert;
             }
+        }
+        return MATCH.nomatch;
+    }
 
-            MATCH match = e.type.implicitConvTo(t);
-            if (match != MATCH.nomatch)
-            {
-                result = match;
-                return;
-            }
+    /******
+     * Given expression e of type t, see if we can implicitly convert e
+     * to type tprime, where tprime is type t with mod bits added.
+     * Returns:
+     *      match level
+     */
+    static MATCH implicitMod(Expression e, Type t, MOD mod)
+    {
+        Type tprime;
+        if (t.ty == Tpointer)
+            tprime = t.nextOf().castMod(mod).pointerTo();
+        else if (t.ty == Tarray)
+            tprime = t.nextOf().castMod(mod).arrayOf();
+        else if (t.ty == Tsarray)
+            tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size());
+        else
+            tprime = t.castMod(mod);
 
-            /* See if we can do integral narrowing conversions
-             */
-            if (e.type.isintegral() && t.isintegral() && e.type.isTypeBasic() && t.isTypeBasic())
-            {
-                IntRange src = getIntRange(e);
-                IntRange target = IntRange.fromType(t);
-                if (target.contains(src))
-                {
-                    result = MATCH.convert;
-                    return;
-                }
-            }
-        }
+        return e.implicitConvTo(tprime);
+    }
 
-        /******
-         * Given expression e of type t, see if we can implicitly convert e
-         * to type tprime, where tprime is type t with mod bits added.
-         * Returns:
-         *      match level
+    static MATCH implicitConvToAddMin(BinExp e, Type t)
+    {
+        /* Is this (ptr +- offset)? If so, then ask ptr
+         * if the conversion can be done.
+         * This is to support doing things like implicitly converting a mutable unique
+         * pointer to an immutable pointer.
          */
-        static MATCH implicitMod(Expression e, Type t, MOD mod)
-        {
-            Type tprime;
-            if (t.ty == Tpointer)
-                tprime = t.nextOf().castMod(mod).pointerTo();
-            else if (t.ty == Tarray)
-                tprime = t.nextOf().castMod(mod).arrayOf();
-            else if (t.ty == Tsarray)
-                tprime = t.nextOf().castMod(mod).sarrayOf(t.size() / t.nextOf().size());
-            else
-                tprime = t.castMod(mod);
 
-            return e.implicitConvTo(tprime);
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
+
+        if (typeb.ty != Tpointer || tb.ty != Tpointer)
+            return MATCH.nomatch;
+
+        Type t1b = e.e1.type.toBasetype();
+        Type t2b = e.e2.type.toBasetype();
+        if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb))
+        {
+            // ptr + offset
+            // ptr - offset
+            MATCH m = e.e1.implicitConvTo(t);
+            return (m > MATCH.constant) ? MATCH.constant : m;
         }
+        if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb))
+        {
+            // offset + ptr
+            MATCH m = e.e2.implicitConvTo(t);
+            return (m > MATCH.constant) ? MATCH.constant : m;
+        }
+
+        return MATCH.nomatch;
+    }
 
-        static MATCH implicitConvToAddMin(BinExp e, Type t)
+    MATCH visitAdd(AddExp e)
+    {
+        version (none)
         {
-            /* Is this (ptr +- offset)? If so, then ask ptr
-             * if the conversion can be done.
-             * This is to support doing things like implicitly converting a mutable unique
-             * pointer to an immutable pointer.
-             */
+            printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        auto result = visit(e);
+        if (result == MATCH.nomatch)
+            result = implicitConvToAddMin(e, t);
+        return result;
+    }
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+    MATCH visitMin(MinExp e)
+    {
+        version (none)
+        {
+            printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        auto result = visit(e);
+        if (result == MATCH.nomatch)
+            result = implicitConvToAddMin(e, t);
+        return result;
+    }
 
-            if (typeb.ty != Tpointer || tb.ty != Tpointer)
-                return MATCH.nomatch;
+    MATCH visitInteger(IntegerExp e)
+    {
+        version (none)
+        {
+            printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        MATCH m = e.type.implicitConvTo(t);
+        if (m >= MATCH.constant)
+        {
+            return m;
+        }
 
-            Type t1b = e.e1.type.toBasetype();
-            Type t2b = e.e2.type.toBasetype();
-            if (t1b.ty == Tpointer && t2b.isintegral() && t1b.equivalent(tb))
-            {
-                // ptr + offset
-                // ptr - offset
-                MATCH m = e.e1.implicitConvTo(t);
-                return (m > MATCH.constant) ? MATCH.constant : m;
-            }
-            if (t2b.ty == Tpointer && t1b.isintegral() && t2b.equivalent(tb))
-            {
-                // offset + ptr
-                MATCH m = e.e2.implicitConvTo(t);
-                return (m > MATCH.constant) ? MATCH.constant : m;
-            }
+        TY ty = e.type.toBasetype().ty;
+        TY toty = t.toBasetype().ty;
+        TY oldty = ty;
 
+        if (m == MATCH.nomatch && t.ty == Tenum)
             return MATCH.nomatch;
-        }
 
-        override void visit(AddExp e)
+        if (auto tv = t.isTypeVector())
         {
-            version (none)
-            {
-                printf("AddExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            visit(cast(Expression)e);
-            if (result == MATCH.nomatch)
-                result = implicitConvToAddMin(e, t);
+            TypeBasic tb = tv.elementType();
+            if (tb.ty == Tvoid)
+                return MATCH.nomatch;
+            toty = tb.ty;
         }
 
-        override void visit(MinExp e)
+        switch (ty)
         {
-            version (none)
-            {
-                printf("MinExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            visit(cast(Expression)e);
-            if (result == MATCH.nomatch)
-                result = implicitConvToAddMin(e, t);
+        case Tbool:
+        case Tint8:
+        case Tchar:
+        case Tuns8:
+        case Tint16:
+        case Tuns16:
+        case Twchar:
+            ty = Tint32;
+            break;
+
+        case Tdchar:
+            ty = Tuns32;
+            break;
+
+        default:
+            break;
         }
 
-        override void visit(IntegerExp e)
+        // Only allow conversion if no change in value
+        immutable dinteger_t value = e.toInteger();
+
+        bool isLosslesslyConvertibleToFP(T)()
         {
-            version (none)
+            if (e.type.isunsigned())
             {
-                printf("IntegerExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            MATCH m = e.type.implicitConvTo(t);
-            if (m >= MATCH.constant)
-            {
-                result = m;
-                return;
+                const f = cast(T) value;
+                return cast(dinteger_t) f == value;
             }
 
-            TY ty = e.type.toBasetype().ty;
-            TY toty = t.toBasetype().ty;
-            TY oldty = ty;
-
-            if (m == MATCH.nomatch && t.ty == Tenum)
-                return;
+            const f = cast(T) cast(sinteger_t) value;
+            return cast(sinteger_t) f == cast(sinteger_t) value;
+        }
 
-            if (auto tv = t.isTypeVector())
-            {
-                TypeBasic tb = tv.elementType();
-                if (tb.ty == Tvoid)
-                    return;
-                toty = tb.ty;
-            }
+        switch (toty)
+        {
+        case Tbool:
+            if ((value & 1) != value)
+                return MATCH.nomatch;
+            break;
 
-            switch (ty)
-            {
-            case Tbool:
-            case Tint8:
-            case Tchar:
-            case Tuns8:
-            case Tint16:
-            case Tuns16:
-            case Twchar:
-                ty = Tint32;
-                break;
+        case Tint8:
+            if (ty == Tuns64 && value & ~0x7FU)
+                return MATCH.nomatch;
+            else if (cast(byte)value != value)
+                return MATCH.nomatch;
+            break;
 
-            case Tdchar:
-                ty = Tuns32;
-                break;
+        case Tchar:
+            if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
+                return MATCH.nomatch;
+            goto case Tuns8;
+        case Tuns8:
+            //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
+            if (cast(ubyte)value != value)
+                return MATCH.nomatch;
+            break;
 
-            default:
-                break;
-            }
+        case Tint16:
+            if (ty == Tuns64 && value & ~0x7FFFU)
+                return MATCH.nomatch;
+            else if (cast(short)value != value)
+                return MATCH.nomatch;
+            break;
 
-            // Only allow conversion if no change in value
-            immutable dinteger_t value = e.toInteger();
+        case Twchar:
+            if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
+                return MATCH.nomatch;
+            goto case Tuns16;
+        case Tuns16:
+            if (cast(ushort)value != value)
+                return MATCH.nomatch;
+            break;
 
-            bool isLosslesslyConvertibleToFP(T)()
+        case Tint32:
+            if (ty == Tuns32)
             {
-                if (e.type.isunsigned())
-                {
-                    const f = cast(T) value;
-                    return cast(dinteger_t) f == value;
-                }
-
-                const f = cast(T) cast(sinteger_t) value;
-                return cast(sinteger_t) f == cast(sinteger_t) value;
             }
+            else if (ty == Tuns64 && value & ~0x7FFFFFFFU)
+                return MATCH.nomatch;
+            else if (cast(int)value != value)
+                return MATCH.nomatch;
+            break;
 
-            switch (toty)
+        case Tuns32:
+            if (ty == Tint32)
             {
-            case Tbool:
-                if ((value & 1) != value)
-                    return;
-                break;
-
-            case Tint8:
-                if (ty == Tuns64 && value & ~0x7FU)
-                    return;
-                else if (cast(byte)value != value)
-                    return;
-                break;
-
-            case Tchar:
-                if ((oldty == Twchar || oldty == Tdchar) && value > 0x7F)
-                    return;
-                goto case Tuns8;
-            case Tuns8:
-                //printf("value = %llu %llu\n", (dinteger_t)(unsigned char)value, value);
-                if (cast(ubyte)value != value)
-                    return;
-                break;
-
-            case Tint16:
-                if (ty == Tuns64 && value & ~0x7FFFU)
-                    return;
-                else if (cast(short)value != value)
-                    return;
-                break;
-
-            case Twchar:
-                if (oldty == Tdchar && value > 0xD7FF && value < 0xE000)
-                    return;
-                goto case Tuns16;
-            case Tuns16:
-                if (cast(ushort)value != value)
-                    return;
-                break;
+            }
+            else if (cast(uint)value != value)
+                return MATCH.nomatch;
+            break;
 
-            case Tint32:
-                if (ty == Tuns32)
-                {
-                }
-                else if (ty == Tuns64 && value & ~0x7FFFFFFFU)
-                    return;
-                else if (cast(int)value != value)
-                    return;
-                break;
+        case Tdchar:
+            if (value > 0x10FFFFU)
+                return MATCH.nomatch;
+            break;
 
-            case Tuns32:
-                if (ty == Tint32)
-                {
-                }
-                else if (cast(uint)value != value)
-                    return;
-                break;
+        case Tfloat32:
+            if (!isLosslesslyConvertibleToFP!float)
+                return MATCH.nomatch;
+            break;
 
-            case Tdchar:
-                if (value > 0x10FFFFU)
-                    return;
-                break;
+        case Tfloat64:
+            if (!isLosslesslyConvertibleToFP!double)
+                return MATCH.nomatch;
+            break;
 
-            case Tfloat32:
-                if (!isLosslesslyConvertibleToFP!float)
-                    return;
-                break;
+        case Tfloat80:
+            if (!isLosslesslyConvertibleToFP!real_t)
+                return MATCH.nomatch;
+            break;
 
-            case Tfloat64:
-                if (!isLosslesslyConvertibleToFP!double)
-                    return;
+        case Tpointer:
+            //printf("type = %s\n", type.toBasetype()->toChars());
+            //printf("t = %s\n", t.toBasetype()->toChars());
+            if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
+            {
+                /* Allow things like:
+                 *      const char* P = cast(char *)3;
+                 *      char* q = P;
+                 */
                 break;
+            }
+            goto default;
 
-            case Tfloat80:
-                if (!isLosslesslyConvertibleToFP!real_t)
-                    return;
-                break;
+        default:
+            return visit(e);
+        }
 
-            case Tpointer:
-                //printf("type = %s\n", type.toBasetype()->toChars());
-                //printf("t = %s\n", t.toBasetype()->toChars());
-                if (ty == Tpointer && e.type.toBasetype().nextOf().ty == t.toBasetype().nextOf().ty)
-                {
-                    /* Allow things like:
-                     *      const char* P = cast(char *)3;
-                     *      char* q = P;
-                     */
-                    break;
-                }
-                goto default;
+        //printf("MATCH.convert\n");
+        return MATCH.convert;
+    }
 
-            default:
-                visit(cast(Expression)e);
-                return;
-            }
+    MATCH visitError(ErrorExp e)
+    {
+        return MATCH.nomatch;
+    }
 
-            //printf("MATCH.convert\n");
-            result = MATCH.convert;
+    MATCH visitNull(NullExp e)
+    {
+        version (none)
+        {
+            printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
-
-        override void visit(ErrorExp e)
+        if (e.type.equals(t))
         {
-            // no match
+            return MATCH.exact;
         }
 
-        override void visit(NullExp e)
+        /* Allow implicit conversions from immutable to mutable|const,
+         * and mutable to immutable. It works because, after all, a null
+         * doesn't actually point to anything.
+         */
+        if (t.equivalent(e.type))
         {
-            version (none)
-            {
-                printf("NullExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            if (e.type.equals(t))
-            {
-                result = MATCH.exact;
-                return;
-            }
+            return MATCH.constant;
+        }
 
-            /* Allow implicit conversions from immutable to mutable|const,
-             * and mutable to immutable. It works because, after all, a null
-             * doesn't actually point to anything.
-             */
-            if (t.equivalent(e.type))
-            {
-                result = MATCH.constant;
-                return;
-            }
+        return visit(e);
+    }
 
-            visit(cast(Expression)e);
+    MATCH visitStructLiteral(StructLiteralExp e)
+    {
+        version (none)
+        {
+            printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
-
-        override void visit(StructLiteralExp e)
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
+        if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym)
         {
-            version (none)
-            {
-                printf("StructLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
-            if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym)
+            result = MATCH.constant;
+            foreach (i, el; (*e.elements)[])
             {
-                result = MATCH.constant;
-                foreach (i, el; (*e.elements)[])
-                {
-                    if (!el)
-                        continue;
-                    Type te = e.sd.fields[i].type.addMod(t.mod);
-                    MATCH m2 = el.implicitConvTo(te);
-                    //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2);
-                    if (m2 < result)
-                        result = m2;
-                }
+                if (!el)
+                    continue;
+                Type te = e.sd.fields[i].type.addMod(t.mod);
+                MATCH m2 = el.implicitConvTo(te);
+                //printf("\t%s => %s, match = %d\n", el.toChars(), te.toChars(), m2);
+                if (m2 < result)
+                    result = m2;
             }
         }
+        return result;
+    }
 
-        override void visit(StringExp e)
+    MATCH visitString(StringExp e)
+    {
+        version (none)
         {
-            version (none)
-            {
-                printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars());
-            }
-            if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
-                return;
+            printf("StringExp::implicitConvTo(this=%s, committed=%d, type=%s, t=%s)\n", e.toChars(), e.committed, e.type.toChars(), t.toChars());
+        }
+        if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid)
+            return MATCH.nomatch;
 
-            if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer))
-                return visit(cast(Expression)e);
+        if (!(e.type.ty == Tsarray || e.type.ty == Tarray || e.type.ty == Tpointer))
+            return visit(e);
 
-            TY tyn = e.type.nextOf().ty;
+        TY tyn = e.type.nextOf().ty;
 
-            if (!tyn.isSomeChar)
-                return visit(cast(Expression)e);
+        if (!tyn.isSomeChar)
+            return visit(e);
 
-            switch (t.ty)
+        switch (t.ty)
+        {
+        case Tsarray:
+            if (e.type.ty == Tsarray)
             {
-            case Tsarray:
-                if (e.type.ty == Tsarray)
+                TY tynto = t.nextOf().ty;
+                if (tynto == tyn)
                 {
-                    TY tynto = t.nextOf().ty;
-                    if (tynto == tyn)
-                    {
-                        if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger())
-                        {
-                            result = MATCH.exact;
-                        }
-                        return;
-                    }
-                    if (tynto.isSomeChar)
-                    {
-                        if (e.committed && tynto != tyn)
-                            return;
-                        size_t fromlen = e.numberOfCodeUnits(tynto);
-                        size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
-                        if (tolen < fromlen)
-                            return;
-                        if (tolen != fromlen)
-                        {
-                            // implicit length extending
-                            result = MATCH.convert;
-                            return;
-                        }
-                    }
-                    if (!e.committed && tynto.isSomeChar)
+                    if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger())
                     {
-                        result = MATCH.exact;
-                        return;
+                        return MATCH.exact;
                     }
+                    return MATCH.nomatch;
                 }
-                else if (e.type.ty == Tarray)
+                if (tynto.isSomeChar)
                 {
-                    TY tynto = t.nextOf().ty;
-                    if (tynto.isSomeChar)
-                    {
-                        if (e.committed && tynto != tyn)
-                            return;
-                        size_t fromlen = e.numberOfCodeUnits(tynto);
-                        size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
-                        if (tolen < fromlen)
-                            return;
-                        if (tolen != fromlen)
-                        {
-                            // implicit length extending
-                            result = MATCH.convert;
-                            return;
-                        }
-                    }
-                    if (tynto == tyn)
+                    if (e.committed && tynto != tyn)
+                        return MATCH.nomatch;
+                    size_t fromlen = e.numberOfCodeUnits(tynto);
+                    size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
+                    if (tolen < fromlen)
+                        return MATCH.nomatch;
+                    if (tolen != fromlen)
                     {
-                        result = MATCH.exact;
-                        return;
+                        // implicit length extending
+                        return MATCH.convert;
                     }
-                    if (!e.committed && tynto.isSomeChar)
+                }
+                if (!e.committed && tynto.isSomeChar)
+                {
+                    return MATCH.exact;
+                }
+            }
+            else if (e.type.ty == Tarray)
+            {
+                TY tynto = t.nextOf().ty;
+                if (tynto.isSomeChar)
+                {
+                    if (e.committed && tynto != tyn)
+                        return MATCH.nomatch;
+                    size_t fromlen = e.numberOfCodeUnits(tynto);
+                    size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
+                    if (tolen < fromlen)
+                        return MATCH.nomatch;
+                    if (tolen != fromlen)
                     {
-                        result = MATCH.exact;
-                        return;
+                        // implicit length extending
+                        return MATCH.convert;
                     }
                 }
-                goto case; /+ fall through +/
-            case Tarray:
-            case Tpointer:
-                Type tn = t.nextOf();
-                MATCH m = MATCH.exact;
-                if (e.type.nextOf().mod != tn.mod)
+                if (tynto == tyn)
                 {
-                    // https://issues.dlang.org/show_bug.cgi?id=16183
-                    if (!tn.isConst() && !tn.isImmutable())
-                        return;
-                    m = MATCH.constant;
+                    return MATCH.exact;
                 }
-                if (!e.committed)
+                if (!e.committed && tynto.isSomeChar)
                 {
-                    switch (tn.ty)
+                    return MATCH.exact;
+                }
+            }
+            goto case; /+ fall through +/
+        case Tarray:
+        case Tpointer:
+            Type tn = t.nextOf();
+            MATCH m = MATCH.exact;
+            if (e.type.nextOf().mod != tn.mod)
+            {
+                // https://issues.dlang.org/show_bug.cgi?id=16183
+                if (!tn.isConst() && !tn.isImmutable())
+                    return MATCH.nomatch;
+                m = MATCH.constant;
+            }
+            if (!e.committed)
+            {
+                switch (tn.ty)
+                {
+                case Tchar:
+                    if (e.postfix == 'w' || e.postfix == 'd')
+                        m = MATCH.convert;
+                    return m;
+                case Twchar:
+                    if (e.postfix != 'w')
+                        m = MATCH.convert;
+                    return m;
+                case Tdchar:
+                    if (e.postfix != 'd')
+                        m = MATCH.convert;
+                    return m;
+                case Tenum:
+                    if (tn.isTypeEnum().sym.isSpecial())
                     {
-                    case Tchar:
-                        if (e.postfix == 'w' || e.postfix == 'd')
-                            m = MATCH.convert;
-                        result = m;
-                        return;
-                    case Twchar:
-                        if (e.postfix != 'w')
-                            m = MATCH.convert;
-                        result = m;
-                        return;
-                    case Tdchar:
-                        if (e.postfix != 'd')
-                            m = MATCH.convert;
-                        result = m;
-                        return;
-                    case Tenum:
-                        if (tn.isTypeEnum().sym.isSpecial())
-                        {
-                            /* Allow string literal -> const(wchar_t)[]
-                             */
-                            if (TypeBasic tob = tn.toBasetype().isTypeBasic())
-                            result = tn.implicitConvTo(tob);
-                            return;
-                        }
-                        break;
-                    default:
-                        break;
+                        /* Allow string literal -> const(wchar_t)[]
+                         */
+                        if (TypeBasic tob = tn.toBasetype().isTypeBasic())
+                        return tn.implicitConvTo(tob);
                     }
+                    break;
+                default:
+                    break;
                 }
-                break;
-
-            default:
-                break;
             }
+            break;
 
-            visit(cast(Expression)e);
+        default:
+            break;
         }
 
-        override void visit(ArrayLiteralExp e)
+        return visit(e);
+    }
+
+    MATCH visitArrayLiteral(ArrayLiteralExp e)
+    {
+        version (none)
         {
-            version (none)
+            printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
+
+        auto result = MATCH.nomatch;
+        if ((tb.ty == Tarray || tb.ty == Tsarray) &&
+            (typeb.ty == Tarray || typeb.ty == Tsarray))
+        {
+            result = MATCH.exact;
+            Type typen = typeb.nextOf().toBasetype();
+
+            if (auto tsa = tb.isTypeSArray())
             {
-                printf("ArrayLiteralExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+                if (e.elements.dim != tsa.dim.toInteger())
+                    result = MATCH.nomatch;
             }
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
 
-            if ((tb.ty == Tarray || tb.ty == Tsarray) &&
-                (typeb.ty == Tarray || typeb.ty == Tsarray))
+            Type telement = tb.nextOf();
+            if (!e.elements.dim)
             {
-                result = MATCH.exact;
-                Type typen = typeb.nextOf().toBasetype();
-
-                if (auto tsa = tb.isTypeSArray())
-                {
-                    if (e.elements.dim != tsa.dim.toInteger())
-                        result = MATCH.nomatch;
-                }
-
-                Type telement = tb.nextOf();
-                if (!e.elements.dim)
-                {
-                    if (typen.ty != Tvoid)
-                        result = typen.implicitConvTo(telement);
-                }
-                else
-                {
-                    if (e.basis)
-                    {
-                        MATCH m = e.basis.implicitConvTo(telement);
-                        if (m < result)
-                            result = m;
-                    }
-                    for (size_t i = 0; i < e.elements.dim; i++)
-                    {
-                        Expression el = (*e.elements)[i];
-                        if (result == MATCH.nomatch)
-                            break;
-                        if (!el)
-                            continue;
-                        MATCH m = el.implicitConvTo(telement);
-                        if (m < result)
-                            result = m; // remember worst match
-                    }
-                }
-
-                if (!result)
-                    result = e.type.implicitConvTo(t);
-
-                return;
+                if (typen.ty != Tvoid)
+                    result = typen.implicitConvTo(telement);
             }
-            else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
+            else
             {
-                result = MATCH.exact;
-                // Convert array literal to vector type
-                TypeVector tv = tb.isTypeVector();
-                TypeSArray tbase = tv.basetype.isTypeSArray();
-                assert(tbase);
-                const edim = e.elements.dim;
-                const tbasedim = tbase.dim.toInteger();
-                if (edim > tbasedim)
-                {
-                    result = MATCH.nomatch;
-                    return;
-                }
-
-                Type telement = tv.elementType();
-                if (edim < tbasedim)
+                if (e.basis)
                 {
-                    Expression el = typeb.nextOf.defaultInitLiteral(e.loc);
-                    MATCH m = el.implicitConvTo(telement);
+                    MATCH m = e.basis.implicitConvTo(telement);
                     if (m < result)
-                        result = m; // remember worst match
+                        result = m;
                 }
-                foreach (el; (*e.elements)[])
+                for (size_t i = 0; i < e.elements.dim; i++)
                 {
+                    Expression el = (*e.elements)[i];
+                    if (result == MATCH.nomatch)
+                        break;
+                    if (!el)
+                        continue;
                     MATCH m = el.implicitConvTo(telement);
                     if (m < result)
                         result = m; // remember worst match
-                    if (result == MATCH.nomatch)
-                        break; // no need to check for worse
                 }
-                return;
             }
 
-            visit(cast(Expression)e);
-        }
+            if (!result)
+                result = e.type.implicitConvTo(t);
 
-        override void visit(AssocArrayLiteralExp e)
+            return result;
+        }
+        else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
         {
-            auto taa = t.toBasetype().isTypeAArray();
-            Type typeb = e.type.toBasetype();
-
-            if (!(taa && typeb.ty == Taarray))
-                return visit(cast(Expression)e);
-
             result = MATCH.exact;
-            foreach (i, el; (*e.keys)[])
+            // Convert array literal to vector type
+            TypeVector tv = tb.isTypeVector();
+            TypeSArray tbase = tv.basetype.isTypeSArray();
+            assert(tbase);
+            const edim = e.elements.dim;
+            const tbasedim = tbase.dim.toInteger();
+            if (edim > tbasedim)
+            {
+                return MATCH.nomatch;
+            }
+
+            Type telement = tv.elementType();
+            if (edim < tbasedim)
             {
-                MATCH m = el.implicitConvTo(taa.index);
+                Expression el = typeb.nextOf.defaultInitLiteral(e.loc);
+                MATCH m = el.implicitConvTo(telement);
                 if (m < result)
                     result = m; // remember worst match
-                if (result == MATCH.nomatch)
-                    break; // no need to check for worse
-                el = (*e.values)[i];
-                m = el.implicitConvTo(taa.nextOf());
+            }
+            foreach (el; (*e.elements)[])
+            {
+                MATCH m = el.implicitConvTo(telement);
                 if (m < result)
                     result = m; // remember worst match
                 if (result == MATCH.nomatch)
                     break; // no need to check for worse
             }
+            return result;
         }
 
-        override void visit(CallExp e)
+        return visit(e);
+    }
+
+    MATCH visitAssocArrayLiteral(AssocArrayLiteralExp e)
+    {
+        auto taa = t.toBasetype().isTypeAArray();
+        Type typeb = e.type.toBasetype();
+
+        if (!(taa && typeb.ty == Taarray))
+            return visit(e);
+
+        auto result = MATCH.exact;
+        foreach (i, el; (*e.keys)[])
         {
-            enum LOG = false;
-            static if (LOG)
-            {
-                printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
+            MATCH m = el.implicitConvTo(taa.index);
+            if (m < result)
+                result = m; // remember worst match
+            if (result == MATCH.nomatch)
+                break; // no need to check for worse
+            el = (*e.values)[i];
+            m = el.implicitConvTo(taa.nextOf());
+            if (m < result)
+                result = m; // remember worst match
+            if (result == MATCH.nomatch)
+                break; // no need to check for worse
+        }
+        return result;
+    }
 
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+    MATCH visitCall(CallExp e)
+    {
+        enum LOG = false;
+        static if (LOG)
+        {
+            printf("CallExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
 
-            /* Allow the result of strongly pure functions to
-             * 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.
-               )
-            {
-                result = e.type.immutableOf().implicitConvTo(t);
-                if (result > MATCH.constant) // Match level is MATCH.constant at best.
-                    result = MATCH.constant;
-                return;
-            }
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-            /* Conversion is 'const' conversion if:
-             * 1. function is pure (weakly pure is ok)
-             * 2. implicit conversion only fails because of mod bits
-             * 3. each function parameter can be implicitly converted to the mod bits
-             */
-            auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction();
-            if (!tf)
-                return;
+        /* Allow the result of strongly pure functions to
+         * 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.
+           )
+        {
+            result = e.type.immutableOf().implicitConvTo(t);
+            if (result > MATCH.constant) // Match level is MATCH.constant at best.
+                result = MATCH.constant;
+            return result;
+        }
 
-            if (tf.purity == PURE.impure)
-                return;
-            if (e.f && e.f.isNested())
-                return;
+        /* Conversion is 'const' conversion if:
+         * 1. function is pure (weakly pure is ok)
+         * 2. implicit conversion only fails because of mod bits
+         * 3. each function parameter can be implicitly converted to the mod bits
+         */
+        auto tf = (e.f ? e.f.type : e.e1.type).toBasetype().isTypeFunction();
+        if (!tf)
+            return result;
+
+        if (tf.purity == PURE.impure)
+            return result;
+        if (e.f && e.f.isNested())
+            return result;
+
+        /* See if fail only because of mod bits.
+         *
+         * https://issues.dlang.org/show_bug.cgi?id=14155
+         * All pure functions can access global immutable data.
+         * So the returned pointer may refer an immutable global data,
+         * and then the returned pointer that points non-mutable object
+         * cannot be unique pointer.
+         *
+         * Example:
+         *  immutable g;
+         *  static this() { g = 1; }
+         *  const(int*) foo() pure { return &g; }
+         *  void test() {
+         *    immutable(int*) ip = foo(); // OK
+         *    int* mp = foo();            // should be disallowed
+         *  }
+         */
+        if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
+        {
+            return result;
+        }
+        // Allow a conversion to immutable type, or
+        // conversions of mutable types between thread-local and shared.
 
-            /* See if fail only because of mod bits.
-             *
-             * https://issues.dlang.org/show_bug.cgi?id=14155
-             * All pure functions can access global immutable data.
-             * So the returned pointer may refer an immutable global data,
-             * and then the returned pointer that points non-mutable object
-             * cannot be unique pointer.
-             *
-             * Example:
-             *  immutable g;
-             *  static this() { g = 1; }
-             *  const(int*) foo() pure { return &g; }
-             *  void test() {
-             *    immutable(int*) ip = foo(); // OK
-             *    int* mp = foo();            // should be disallowed
-             *  }
-             */
-            if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
-            {
-                return;
-            }
-            // Allow a conversion to immutable type, or
-            // conversions of mutable types between thread-local and shared.
+        /* Get mod bits of what we're converting to
+         */
+        Type tb = t.toBasetype();
+        MOD mod = tb.mod;
+        if (tf.isref)
+        {
+        }
+        else
+        {
+            if (Type ti = getIndirection(t))
+                mod = ti.mod;
+        }
+        static if (LOG)
+        {
+            printf("mod = x%x\n", mod);
+        }
+        if (mod & MODFlags.wild)
+            return result; // not sure what to do with this
 
-            /* Get mod bits of what we're converting to
-             */
-            Type tb = t.toBasetype();
-            MOD mod = tb.mod;
-            if (tf.isref)
-            {
-            }
-            else
-            {
-                if (Type ti = getIndirection(t))
-                    mod = ti.mod;
-            }
-            static if (LOG)
-            {
-                printf("mod = x%x\n", mod);
-            }
-            if (mod & MODFlags.wild)
-                return; // not sure what to do with this
+        /* Apply mod bits to each function parameter,
+         * and see if we can convert the function argument to the modded type
+         */
 
-            /* Apply mod bits to each function parameter,
-             * and see if we can convert the function argument to the modded type
+        size_t nparams = tf.parameterList.length;
+        size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
+        if (auto dve = e.e1.isDotVarExp())
+        {
+            /* Treat 'this' as just another function argument
              */
-
-            size_t nparams = tf.parameterList.length;
-            size_t j = tf.isDstyleVariadic(); // if TypeInfoArray was prepended
-            if (auto dve = e.e1.isDotVarExp())
+            Type targ = dve.e1.type;
+            if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
+                return result;
+        }
+        foreach (const i; j .. e.arguments.dim)
+        {
+            Expression earg = (*e.arguments)[i];
+            Type targ = earg.type.toBasetype();
+            static if (LOG)
             {
-                /* Treat 'this' as just another function argument
-                 */
-                Type targ = dve.e1.type;
-                if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
-                    return;
+                printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
             }
-            foreach (const i; j .. e.arguments.dim)
+            if (i - j < nparams)
             {
-                Expression earg = (*e.arguments)[i];
-                Type targ = earg.type.toBasetype();
-                static if (LOG)
+                Parameter fparam = tf.parameterList[i - j];
+                if (fparam.storageClass & STC.lazy_)
+                    return result; // not sure what to do with this
+                Type tparam = fparam.type;
+                if (!tparam)
+                    continue;
+                if (fparam.isReference())
                 {
-                    printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
+                    if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
+                        return result;
+                    continue;
                 }
-                if (i - j < nparams)
-                {
-                    Parameter fparam = tf.parameterList[i - j];
-                    if (fparam.storageClass & STC.lazy_)
-                        return; // not sure what to do with this
-                    Type tparam = fparam.type;
-                    if (!tparam)
-                        continue;
-                    if (fparam.isReference())
-                    {
-                        if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
-                            return;
-                        continue;
-                    }
-                }
-                static if (LOG)
-                {
-                    printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
-                }
-                if (implicitMod(earg, targ, mod) == MATCH.nomatch)
-                    return;
             }
-
-            /* Success
-             */
-            result = MATCH.constant;
+            static if (LOG)
+            {
+                printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+            }
+            if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+                return result;
         }
 
-        override void visit(AddrExp e)
+        /* Success
+         */
+        return MATCH.constant;
+    }
+
+    MATCH visitAddr(AddrExp e)
+    {
+        version (none)
         {
-            version (none)
-            {
-                printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            result = e.type.implicitConvTo(t);
-            //printf("\tresult = %d\n", result);
+            printf("AddrExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        auto result = e.type.implicitConvTo(t);
+        //printf("\tresult = %d\n", result);
 
-            if (result != MATCH.nomatch)
-                return;
+        if (result != MATCH.nomatch)
+            return result;
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            // Look for pointers to functions where the functions are overloaded.
-            if (e.e1.op == EXP.overloadSet &&
-                (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        // Look for pointers to functions where the functions are overloaded.
+        if (e.e1.op == EXP.overloadSet &&
+            (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        {
+            OverExp eo = e.e1.isOverExp();
+            FuncDeclaration f = null;
+            foreach (s; eo.vars.a[])
             {
-                OverExp eo = e.e1.isOverExp();
-                FuncDeclaration f = null;
-                foreach (s; eo.vars.a[])
+                FuncDeclaration f2 = s.isFuncDeclaration();
+                assert(f2);
+                if (f2.overloadExactMatch(tb.nextOf()))
                 {
-                    FuncDeclaration f2 = s.isFuncDeclaration();
-                    assert(f2);
-                    if (f2.overloadExactMatch(tb.nextOf()))
+                    if (f)
                     {
-                        if (f)
-                        {
-                            /* Error if match in more than one overload set,
-                             * even if one is a 'better' match than the other.
-                             */
-                            ScopeDsymbol.multiplyDefined(e.loc, f, f2);
-                        }
-                        else
-                            f = f2;
-                        result = MATCH.exact;
+                        /* Error if match in more than one overload set,
+                         * even if one is a 'better' match than the other.
+                         */
+                        ScopeDsymbol.multiplyDefined(e.loc, f, f2);
                     }
+                    else
+                        f = f2;
+                    result = MATCH.exact;
                 }
             }
+        }
 
-            if (e.e1.op == EXP.variable &&
-                typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
-                tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
-            {
-                /* I don't think this can ever happen -
-                 * it should have been
-                 * converted to a SymOffExp.
-                 */
-                assert(0);
-            }
-
-            //printf("\tresult = %d\n", result);
+        if (e.e1.op == EXP.variable &&
+            typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+            tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
+        {
+            /* I don't think this can ever happen -
+             * it should have been
+             * converted to a SymOffExp.
+             */
+            assert(0);
         }
 
-        override void visit(SymOffExp e)
+        //printf("\tresult = %d\n", result);
+        return result;
+    }
+
+    MATCH visitSymOff(SymOffExp e)
+    {
+        version (none)
         {
-            version (none)
-            {
-                printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            result = e.type.implicitConvTo(t);
-            //printf("\tresult = %d\n", result);
-            if (result != MATCH.nomatch)
-                return;
+            printf("SymOffExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        auto result = e.type.implicitConvTo(t);
+        //printf("\tresult = %d\n", result);
+        if (result != MATCH.nomatch)
+            return result;
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            // Look for pointers to functions where the functions are overloaded.
-            if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
-                (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        // Look for pointers to functions where the functions are overloaded.
+        if (typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+            (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        {
+            if (FuncDeclaration f = e.var.isFuncDeclaration())
             {
-                if (FuncDeclaration f = e.var.isFuncDeclaration())
+                f = f.overloadExactMatch(tb.nextOf());
+                if (f)
                 {
-                    f = f.overloadExactMatch(tb.nextOf());
-                    if (f)
+                    if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) ||
+                        (tb.ty == Tpointer && !(f.needThis() || f.isNested())))
                     {
-                        if ((tb.ty == Tdelegate && (f.needThis() || f.isNested())) ||
-                            (tb.ty == Tpointer && !(f.needThis() || f.isNested())))
-                        {
-                            result = MATCH.exact;
-                        }
+                        result = MATCH.exact;
                     }
                 }
             }
-            //printf("\tresult = %d\n", result);
         }
+        //printf("\tresult = %d\n", result);
+        return result;
+    }
 
-        override void visit(DelegateExp e)
+    MATCH visitDelegate(DelegateExp e)
+    {
+        version (none)
         {
-            version (none)
-            {
-                printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            result = e.type.implicitConvTo(t);
-            if (result != MATCH.nomatch)
-                return;
+            printf("DelegateExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        auto result = e.type.implicitConvTo(t);
+        if (result != MATCH.nomatch)
+            return result;
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            // Look for pointers to functions where the functions are overloaded.
-            if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
-            {
-                if (e.func && e.func.overloadExactMatch(tb.nextOf()))
-                    result = MATCH.exact;
-            }
+        // Look for pointers to functions where the functions are overloaded.
+        if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
+        {
+            if (e.func && e.func.overloadExactMatch(tb.nextOf()))
+                result = MATCH.exact;
         }
+        return result;
+    }
 
-        override void visit(FuncExp e)
+    MATCH visitFunc(FuncExp e)
+    {
+        //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
+        MATCH m = e.matchType(t, null, null, 1);
+        if (m > MATCH.nomatch)
         {
-            //printf("FuncExp::implicitConvTo type = %p %s, t = %s\n", e.type, e.type ? e.type.toChars() : NULL, t.toChars());
-            MATCH m = e.matchType(t, null, null, 1);
-            if (m > MATCH.nomatch)
-            {
-                result = m;
-                return;
-            }
-            visit(cast(Expression)e);
+            return m;
         }
+        return visit(e);
+    }
 
-        override void visit(AndExp e)
-        {
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+    MATCH visitAnd(AndExp e)
+    {
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-            MATCH m1 = e.e1.implicitConvTo(t);
-            MATCH m2 = e.e2.implicitConvTo(t);
+        MATCH m1 = e.e1.implicitConvTo(t);
+        MATCH m2 = e.e2.implicitConvTo(t);
 
-            // Pick the worst match
-            result = (m1 < m2) ? m1 : m2;
-        }
+        // Pick the worst match
+        return (m1 < m2) ? m1 : m2;
+    }
 
-        override void visit(OrExp e)
-        {
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+    MATCH visitOr(OrExp e)
+    {
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-            MATCH m1 = e.e1.implicitConvTo(t);
-            MATCH m2 = e.e2.implicitConvTo(t);
+        MATCH m1 = e.e1.implicitConvTo(t);
+        MATCH m2 = e.e2.implicitConvTo(t);
 
-            // Pick the worst match
-            result = (m1 < m2) ? m1 : m2;
-        }
+        // Pick the worst match
+        return (m1 < m2) ? m1 : m2;
+    }
 
-        override void visit(XorExp e)
-        {
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+    MATCH visitXor(XorExp e)
+    {
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-            MATCH m1 = e.e1.implicitConvTo(t);
-            MATCH m2 = e.e2.implicitConvTo(t);
+        MATCH m1 = e.e1.implicitConvTo(t);
+        MATCH m2 = e.e2.implicitConvTo(t);
 
-            // Pick the worst match
-            result = (m1 < m2) ? m1 : m2;
-        }
+        // Pick the worst match
+        return (m1 < m2) ? m1 : m2;
+    }
 
-        override void visit(CondExp e)
-        {
-            MATCH m1 = e.e1.implicitConvTo(t);
-            MATCH m2 = e.e2.implicitConvTo(t);
-            //printf("CondExp: m1 %d m2 %d\n", m1, m2);
+    MATCH visitCond(CondExp e)
+    {
+        MATCH m1 = e.e1.implicitConvTo(t);
+        MATCH m2 = e.e2.implicitConvTo(t);
+        //printf("CondExp: m1 %d m2 %d\n", m1, m2);
 
-            // Pick the worst match
-            result = (m1 < m2) ? m1 : m2;
-        }
+        // Pick the worst match
+        return (m1 < m2) ? m1 : m2;
+    }
 
-        override void visit(CommaExp e)
+    MATCH visitComma(CommaExp e)
+    {
+        return e.e2.implicitConvTo(t);
+    }
+
+    MATCH visitCast(CastExp e)
+    {
+        version (none)
         {
-            e.e2.accept(this);
+            printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
+        auto result = e.type.implicitConvTo(t);
+        if (result != MATCH.nomatch)
+            return result;
 
-        override void visit(CastExp e)
-        {
-            version (none)
-            {
-                printf("CastExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            result = e.type.implicitConvTo(t);
-            if (result != MATCH.nomatch)
-                return;
+        if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
+            result = MATCH.convert;
+        else
+            result = visit(e);
+        return result;
+    }
 
-            if (t.isintegral() && e.e1.type.isintegral() && e.e1.implicitConvTo(t) != MATCH.nomatch)
-                result = MATCH.convert;
-            else
-                visit(cast(Expression)e);
+    MATCH visitNew(NewExp e)
+    {
+        version (none)
+        {
+            printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-        override void visit(NewExp e)
-        {
-            version (none)
-            {
-                printf("NewExp::implicitConvTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+        /* Calling new() is like calling a pure function. We can implicitly convert the
+         * return from new() to t using the same algorithm as in CallExp, with the function
+         * 'arguments' being:
+         *    thisexp
+         *    arguments
+         *    .init
+         * 'member' need to be pure.
+         */
 
-            /* Calling new() is like calling a pure function. We can implicitly convert the
-             * return from new() to t using the same algorithm as in CallExp, with the function
-             * 'arguments' being:
-             *    thisexp
-             *    newargs
-             *    arguments
-             *    .init
-             * 'member' need to be pure.
-             */
+        /* See if fail only because of mod bits
+         */
+        if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch)
+            return MATCH.nomatch;
 
-            /* See if fail only because of mod bits
-             */
-            if (e.type.immutableOf().implicitConvTo(t.immutableOf()) == MATCH.nomatch)
-                return;
+        /* Get mod bits of what we're converting to
+         */
+        Type tb = t.toBasetype();
+        MOD mod = tb.mod;
+        if (Type ti = getIndirection(t))
+            mod = ti.mod;
+        static if (LOG)
+        {
+            printf("mod = x%x\n", mod);
+        }
+        if (mod & MODFlags.wild)
+            return MATCH.nomatch; // not sure what to do with this
 
-            /* Get mod bits of what we're converting to
-             */
-            Type tb = t.toBasetype();
-            MOD mod = tb.mod;
-            if (Type ti = getIndirection(t))
-                mod = ti.mod;
-            static if (LOG)
-            {
-                printf("mod = x%x\n", mod);
-            }
-            if (mod & MODFlags.wild)
-                return; // not sure what to do with this
+        /* Apply mod bits to each argument,
+         * and see if we can convert the argument to the modded type
+         */
 
-            /* Apply mod bits to each argument,
-             * and see if we can convert the argument to the modded type
+        if (e.thisexp)
+        {
+            /* Treat 'this' as just another function argument
              */
+            Type targ = e.thisexp.type;
+            if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
+                return MATCH.nomatch;
+        }
 
-            if (e.thisexp)
+        /* Check call to 'member'
+         */
+        if (e.member)
+        {
+            FuncDeclaration fd = e.member;
+            if (fd.errors || fd.type.ty != Tfunction)
+                return MATCH.nomatch; // error
+            TypeFunction tf = fd.type.isTypeFunction();
+            if (tf.purity == PURE.impure)
+                return MATCH.nomatch; // impure
+
+            if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
             {
-                /* Treat 'this' as just another function argument
-                 */
-                Type targ = e.thisexp.type;
-                if (targ.constConv(targ.castMod(mod)) == MATCH.nomatch)
-                    return;
+                return MATCH.nomatch;
             }
+            // Allow a conversion to immutable type, or
+            // conversions of mutable types between thread-local and shared.
 
-            /* Check call to 'member'
-             */
-            if (e.member)
-            {
-                FuncDeclaration fd = e.member;
-                if (fd.errors || fd.type.ty != Tfunction)
-                    return; // error
-                TypeFunction tf = fd.type.isTypeFunction();
-                if (tf.purity == PURE.impure)
-                    return; // impure
+            Expressions* args = e.arguments;
 
-                if (e.type.immutableOf().implicitConvTo(t) < MATCH.constant && e.type.addMod(MODFlags.shared_).implicitConvTo(t) < MATCH.constant && e.type.implicitConvTo(t.addMod(MODFlags.shared_)) < MATCH.constant)
+            size_t nparams = tf.parameterList.length;
+            // if TypeInfoArray was prepended
+            size_t j = tf.isDstyleVariadic();
+            for (size_t i = j; i < e.arguments.dim; ++i)
+            {
+                Expression earg = (*args)[i];
+                Type targ = earg.type.toBasetype();
+                static if (LOG)
                 {
-                    return;
+                    printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
                 }
-                // Allow a conversion to immutable type, or
-                // conversions of mutable types between thread-local and shared.
-
-                Expressions* args = e.arguments;
-
-                size_t nparams = tf.parameterList.length;
-                // if TypeInfoArray was prepended
-                size_t j = tf.isDstyleVariadic();
-                for (size_t i = j; i < e.arguments.dim; ++i)
+                if (i - j < nparams)
                 {
-                    Expression earg = (*args)[i];
-                    Type targ = earg.type.toBasetype();
-                    static if (LOG)
-                    {
-                        printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
-                    }
-                    if (i - j < nparams)
-                    {
-                        Parameter fparam = tf.parameterList[i - j];
-                        if (fparam.storageClass & STC.lazy_)
-                            return; // not sure what to do with this
-                        Type tparam = fparam.type;
-                        if (!tparam)
-                            continue;
-                        if (fparam.isReference())
-                        {
-                            if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
-                                return;
-                            continue;
-                        }
-                    }
-                    static if (LOG)
+                    Parameter fparam = tf.parameterList[i - j];
+                    if (fparam.storageClass & STC.lazy_)
+                        return MATCH.nomatch; // not sure what to do with this
+                    Type tparam = fparam.type;
+                    if (!tparam)
+                        continue;
+                    if (fparam.isReference())
                     {
-                        printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+                        if (targ.constConv(tparam.castMod(mod)) == MATCH.nomatch)
+                            return MATCH.nomatch;
+                        continue;
                     }
-                    if (implicitMod(earg, targ, mod) == MATCH.nomatch)
-                        return;
                 }
+                static if (LOG)
+                {
+                    printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
+                }
+                if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+                    return MATCH.nomatch;
             }
+        }
 
-            /* If no 'member', then construction is by simple assignment,
-             * and just straight check 'arguments'
-             */
-            if (!e.member && e.arguments)
+        /* If no 'member', then construction is by simple assignment,
+         * and just straight check 'arguments'
+         */
+        if (!e.member && e.arguments)
+        {
+            for (size_t i = 0; i < e.arguments.dim; ++i)
             {
-                for (size_t i = 0; i < e.arguments.dim; ++i)
+                Expression earg = (*e.arguments)[i];
+                if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853
+                           // if it's on overlapped field
+                    continue;
+                Type targ = earg.type.toBasetype();
+                static if (LOG)
                 {
-                    Expression earg = (*e.arguments)[i];
-                    if (!earg) // https://issues.dlang.org/show_bug.cgi?id=14853
-                               // if it's on overlapped field
-                        continue;
-                    Type targ = earg.type.toBasetype();
-                    static if (LOG)
-                    {
-                        printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
-                        printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
-                    }
-                    if (implicitMod(earg, targ, mod) == MATCH.nomatch)
-                        return;
+                    printf("[%d] earg: %s, targ: %s\n", cast(int)i, earg.toChars(), targ.toChars());
+                    printf("[%d] earg: %s, targm: %s\n", cast(int)i, earg.toChars(), targ.addMod(mod).toChars());
                 }
+                if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+                    return MATCH.nomatch;
             }
+        }
 
-            /* Consider the .init expression as an argument
+        /* Consider the .init expression as an argument
+         */
+        Type ntb = e.newtype.toBasetype();
+        if (ntb.ty == Tarray)
+            ntb = ntb.nextOf().toBasetype();
+        if (auto ts = ntb.isTypeStruct())
+        {
+            // Don't allow nested structs - uplevel reference may not be convertible
+            StructDeclaration sd = ts.sym;
+            sd.size(e.loc); // resolve any forward references
+            if (sd.isNested())
+                return MATCH.nomatch;
+        }
+        if (ntb.isZeroInit(e.loc))
+        {
+            /* Zeros are implicitly convertible, except for special cases.
              */
-            Type ntb = e.newtype.toBasetype();
-            if (ntb.ty == Tarray)
-                ntb = ntb.nextOf().toBasetype();
-            if (auto ts = ntb.isTypeStruct())
+            if (auto tc = ntb.isTypeClass())
             {
-                // Don't allow nested structs - uplevel reference may not be convertible
-                StructDeclaration sd = ts.sym;
-                sd.size(e.loc); // resolve any forward references
-                if (sd.isNested())
-                    return;
-            }
-            if (ntb.isZeroInit(e.loc))
-            {
-                /* Zeros are implicitly convertible, except for special cases.
+                /* With new() must look at the class instance initializer.
                  */
-                if (auto tc = ntb.isTypeClass())
-                {
-                    /* With new() must look at the class instance initializer.
-                     */
-                    ClassDeclaration cd = tc.sym;
+                ClassDeclaration cd = tc.sym;
 
-                    cd.size(e.loc); // resolve any forward references
+                cd.size(e.loc); // resolve any forward references
 
-                    if (cd.isNested())
-                        return; // uplevel reference may not be convertible
+                if (cd.isNested())
+                    return MATCH.nomatch; // uplevel reference may not be convertible
 
-                    assert(!cd.isInterfaceDeclaration());
+                assert(!cd.isInterfaceDeclaration());
 
-                    struct ClassCheck
+                struct ClassCheck
+                {
+                    extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod)
                     {
-                        extern (C++) static bool convertible(Expression e, ClassDeclaration cd, MOD mod)
+                        for (size_t i = 0; i < cd.fields.dim; i++)
                         {
-                            for (size_t i = 0; i < cd.fields.dim; i++)
+                            VarDeclaration v = cd.fields[i];
+                            Initializer _init = v._init;
+                            if (_init)
                             {
-                                VarDeclaration v = cd.fields[i];
-                                Initializer _init = v._init;
-                                if (_init)
+                                if (_init.isVoidInitializer())
+                                {
+                                }
+                                else if (ExpInitializer ei = _init.isExpInitializer())
                                 {
-                                    if (_init.isVoidInitializer())
-                                    {
-                                    }
-                                    else if (ExpInitializer ei = _init.isExpInitializer())
-                                    {
-                                        // https://issues.dlang.org/show_bug.cgi?id=21319
-                                        // This is to prevent re-analyzing the same expression
-                                        // over and over again.
-                                        if (ei.exp == e)
-                                            return false;
-                                        Type tb = v.type.toBasetype();
-                                        if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch)
-                                            return false;
-                                    }
-                                    else
-                                    {
-                                        /* Enhancement: handle StructInitializer and ArrayInitializer
-                                         */
+                                    // https://issues.dlang.org/show_bug.cgi?id=21319
+                                    // This is to prevent re-analyzing the same expression
+                                    // over and over again.
+                                    if (ei.exp == e)
+                                        return false;
+                                    Type tb = v.type.toBasetype();
+                                    if (implicitMod(ei.exp, tb, mod) == MATCH.nomatch)
                                         return false;
-                                    }
                                 }
-                                else if (!v.type.isZeroInit(e.loc))
+                                else
+                                {
+                                    /* Enhancement: handle StructInitializer and ArrayInitializer
+                                     */
                                     return false;
+                                }
                             }
-                            return cd.baseClass ? convertible(e, cd.baseClass, mod) : true;
+                            else if (!v.type.isZeroInit(e.loc))
+                                return false;
                         }
+                        return cd.baseClass ? convertible(e, cd.baseClass, mod) : true;
                     }
-
-                    if (!ClassCheck.convertible(e, cd, mod))
-                        return;
                 }
-            }
-            else
-            {
-                Expression earg = e.newtype.defaultInitLiteral(e.loc);
-                Type targ = e.newtype.toBasetype();
 
-                if (implicitMod(earg, targ, mod) == MATCH.nomatch)
-                    return;
+                if (!ClassCheck.convertible(e, cd, mod))
+                    return MATCH.nomatch;
             }
+        }
+        else
+        {
+            Expression earg = e.newtype.defaultInitLiteral(e.loc);
+            Type targ = e.newtype.toBasetype();
 
-            /* Success
-             */
-            result = MATCH.constant;
+            if (implicitMod(earg, targ, mod) == MATCH.nomatch)
+                return MATCH.nomatch;
         }
 
-        override void visit(SliceExp e)
-        {
-            //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars());
-            visit(cast(Expression)e);
-            if (result != MATCH.nomatch)
-                return;
+        /* Success
+         */
+        return MATCH.constant;
+    }
+
+    MATCH visitSlice(SliceExp e)
+    {
+        //printf("SliceExp::implicitConvTo e = %s, type = %s\n", e.toChars(), e.type.toChars());
+        auto result = visit(e);
+        if (result != MATCH.nomatch)
+            return result;
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            if (tb.ty == Tsarray && typeb.ty == Tarray)
+        if (tb.ty == Tsarray && typeb.ty == Tarray)
+        {
+            typeb = toStaticArrayType(e);
+            if (typeb)
             {
-                typeb = toStaticArrayType(e);
-                if (typeb)
-                {
-                    // Try: T[] -> T[dim]
-                    // (Slice with compile-time known boundaries to static array)
-                    result = typeb.implicitConvTo(t);
-                    if (result > MATCH.convert)
-                        result = MATCH.convert; // match with implicit conversion at most
-                }
-                return;
+                // Try: T[] -> T[dim]
+                // (Slice with compile-time known boundaries to static array)
+                result = typeb.implicitConvTo(t);
+                if (result > MATCH.convert)
+                    result = MATCH.convert; // match with implicit conversion at most
             }
+            return result;
+        }
 
-            /* If the only reason it won't convert is because of the mod bits,
-             * then test for conversion by seeing if e1 can be converted with those
-             * same mod bits.
-             */
-            Type t1b = e.e1.type.toBasetype();
-            if (tb.ty == Tarray && typeb.equivalent(tb))
-            {
-                Type tbn = tb.nextOf();
-                Type tx = null;
+        /* If the only reason it won't convert is because of the mod bits,
+         * then test for conversion by seeing if e1 can be converted with those
+         * same mod bits.
+         */
+        Type t1b = e.e1.type.toBasetype();
+        if (tb.ty == Tarray && typeb.equivalent(tb))
+        {
+            Type tbn = tb.nextOf();
+            Type tx = null;
 
-                /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1
-                 * is equivalent with the uniqueness of the referred data. And in here
-                 * we can have arbitrary typed reference for that.
-                 */
-                if (t1b.ty == Tarray)
-                    tx = tbn.arrayOf();
-                if (t1b.ty == Tpointer)
-                    tx = tbn.pointerTo();
-
-                /* If e.e1 is static array, at least it should be an rvalue.
-                 * If not, e.e1 is a reference, and its uniqueness does not link
-                 * to the uniqueness of the referred data.
-                 */
-                if (t1b.ty == Tsarray && !e.e1.isLvalue())
-                    tx = tbn.sarrayOf(t1b.size() / tbn.size());
+            /* If e.e1 is dynamic array or pointer, the uniqueness of e.e1
+             * is equivalent with the uniqueness of the referred data. And in here
+             * we can have arbitrary typed reference for that.
+             */
+            if (t1b.ty == Tarray)
+                tx = tbn.arrayOf();
+            if (t1b.ty == Tpointer)
+                tx = tbn.pointerTo();
+
+            /* If e.e1 is static array, at least it should be an rvalue.
+             * If not, e.e1 is a reference, and its uniqueness does not link
+             * to the uniqueness of the referred data.
+             */
+            if (t1b.ty == Tsarray && !e.e1.isLvalue())
+                tx = tbn.sarrayOf(t1b.size() / tbn.size());
 
-                if (tx)
-                {
-                    result = e.e1.implicitConvTo(tx);
-                    if (result > MATCH.constant) // Match level is MATCH.constant at best.
-                        result = MATCH.constant;
-                }
+            if (tx)
+            {
+                result = e.e1.implicitConvTo(tx);
+                if (result > MATCH.constant) // Match level is MATCH.constant at best.
+                    result = MATCH.constant;
             }
-
-            // Enhancement 10724
-            if (tb.ty == Tpointer && e.e1.op == EXP.string_)
-                e.e1.accept(this);
         }
 
-        override void visit(TupleExp e)
-        {
-            result = e.type.implicitConvTo(t);
-            if (result != MATCH.nomatch)
-                return;
+        // Enhancement 10724
+        if (tb.ty == Tpointer && e.e1.op == EXP.string_)
+            result = e.e1.implicitConvTo(t);
+        return result;
+    }
 
-            /* If target type is a tuple of same length, test conversion of
-             * each expression to the corresponding type in the tuple.
-             */
-            TypeTuple totuple = t.isTypeTuple();
-            if (totuple && e.exps.length == totuple.arguments.length)
+    MATCH visitTuple(TupleExp e)
+    {
+        auto result = e.type.implicitConvTo(t);
+        if (result != MATCH.nomatch)
+            return result;
+
+        /* If target type is a tuple of same length, test conversion of
+         * each expression to the corresponding type in the tuple.
+         */
+        TypeTuple totuple = t.isTypeTuple();
+        if (totuple && e.exps.length == totuple.arguments.length)
+        {
+            result = MATCH.exact;
+            foreach (i, ex; *e.exps)
             {
-                result = MATCH.exact;
-                foreach (i, ex; *e.exps)
-                {
-                    auto to = (*totuple.arguments)[i].type;
-                    MATCH mi = ex.implicitConvTo(to);
-                    if (mi < result)
-                        result = mi;
-                }
+                auto to = (*totuple.arguments)[i].type;
+                MATCH mi = ex.implicitConvTo(to);
+                if (mi < result)
+                    result = mi;
             }
         }
+        return result;
     }
 
-    scope ImplicitConvTo v = new ImplicitConvTo(t);
-    e.accept(v);
-    return v.result;
+    switch (e.op)
+    {
+        default                   : return visit(e);
+        case EXP.add              : return visitAdd(e.isAddExp());
+        case EXP.min              : return visitMin(e.isMinExp());
+        case EXP.int64            : return visitInteger(e.isIntegerExp());
+        case EXP.error            : return visitError(e.isErrorExp());
+        case EXP.null_            : return visitNull(e.isNullExp());
+        case EXP.structLiteral    : return visitStructLiteral(e.isStructLiteralExp());
+        case EXP.string_          : return visitString(e.isStringExp());
+        case EXP.arrayLiteral     : return visitArrayLiteral(e.isArrayLiteralExp());
+        case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
+        case EXP.call             : return visitCall(e.isCallExp());
+        case EXP.address          : return visitAddr(e.isAddrExp());
+        case EXP.symbolOffset     : return visitSymOff(e.isSymOffExp());
+        case EXP.delegate_        : return visitDelegate(e.isDelegateExp());
+        case EXP.function_        : return visitFunc(e.isFuncExp());
+        case EXP.and              : return visitAnd(e.isAndExp());
+        case EXP.or               : return visitOr(e.isOrExp());
+        case EXP.xor              : return visitXor(e.isXorExp());
+        case EXP.question         : return visitCond(e.isCondExp());
+        case EXP.comma            : return visitComma(e.isCommaExp());
+        case EXP.cast_            : return visitCast(e.isCastExp());
+        case EXP.new_             : return visitNew(e.isNewExp());
+        case EXP.slice            : return visitSlice(e.isSliceExp());
+        case EXP.tuple            : return visitTuple(e.isTupleExp());
+    }
 }
 
 /**
@@ -1536,1124 +1529,1081 @@ Type toStaticArrayType(SliceExp e)
  */
 Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
 {
-    extern (C++) final class CastTo : Visitor
+    Expression visit(Expression e)
     {
-        alias visit = Visitor.visit;
-    public:
-        Type t;
-        Scope* sc;
-        Expression result;
-
-        extern (D) this(Scope* sc, Type t)
+        //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
+        version (none)
         {
-            this.sc = sc;
-            this.t = t;
+            printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
-
-        override void visit(Expression e)
+        if (e.type.equals(t))
         {
-            //printf("Expression::castTo(this=%s, t=%s)\n", e.toChars(), t.toChars());
-            version (none)
-            {
-                printf("Expression::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
-            if (e.type.equals(t))
-            {
-                result = e;
-                return;
-            }
-            if (auto ve = e.isVarExp())
+            return e;
+        }
+        if (auto ve = e.isVarExp())
+        {
+            VarDeclaration v = ve.var.isVarDeclaration();
+            if (v && v.storage_class & STC.manifest)
             {
-                VarDeclaration v = ve.var.isVarDeclaration();
-                if (v && v.storage_class & STC.manifest)
-                {
-                    result = e.ctfeInterpret();
-                    /* https://issues.dlang.org/show_bug.cgi?id=18236
-                     *
-                     * The expression returned by ctfeInterpret points
-                     * to the line where the manifest constant was declared
-                     * so we need to update the location before trying to cast
-                     */
-                    result.loc = e.loc;
-                    result = result.castTo(sc, t);
-                    return;
-                }
+                auto result = e.ctfeInterpret();
+                /* https://issues.dlang.org/show_bug.cgi?id=18236
+                 *
+                 * The expression returned by ctfeInterpret points
+                 * to the line where the manifest constant was declared
+                 * so we need to update the location before trying to cast
+                 */
+                result.loc = e.loc;
+                return result.castTo(sc, t);
             }
+        }
 
-            Type tob = t.toBasetype();
-            Type t1b = e.type.toBasetype();
-            if (tob.equals(t1b))
-            {
-                result = e.copy(); // because of COW for assignment to e.type
-                result.type = t;
-                return;
-            }
+        Type tob = t.toBasetype();
+        Type t1b = e.type.toBasetype();
+        if (tob.equals(t1b))
+        {
+            auto result = e.copy(); // because of COW for assignment to e.type
+            result.type = t;
+            return result;
+        }
 
-            /* Make semantic error against invalid cast between concrete types.
-             * Assume that 'e' is never be any placeholder expressions.
-             * The result of these checks should be consistent with CastExp::toElem().
-             */
+        /* Make semantic error against invalid cast between concrete types.
+         * Assume that 'e' is never be any placeholder expressions.
+         * The result of these checks should be consistent with CastExp::toElem().
+         */
 
-            // Fat Value types
-            const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector);
-            const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector);
+        // Fat Value types
+        const(bool) tob_isFV = (tob.ty == Tstruct || tob.ty == Tsarray || tob.ty == Tvector);
+        const(bool) t1b_isFV = (t1b.ty == Tstruct || t1b.ty == Tsarray || t1b.ty == Tvector);
 
-            // Fat Reference types
-            const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate);
-            const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate);
+        // Fat Reference types
+        const(bool) tob_isFR = (tob.ty == Tarray || tob.ty == Tdelegate);
+        const(bool) t1b_isFR = (t1b.ty == Tarray || t1b.ty == Tdelegate);
 
-            // Reference types
-            const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass);
-            const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass);
+        // Reference types
+        const(bool) tob_isR = (tob_isFR || tob.ty == Tpointer || tob.ty == Taarray || tob.ty == Tclass);
+        const(bool) t1b_isR = (t1b_isFR || t1b.ty == Tpointer || t1b.ty == Taarray || t1b.ty == Tclass);
 
-            // Arithmetic types (== valueable basic types)
-            const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
-            const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
+        // Arithmetic types (== valueable basic types)
+        const(bool) tob_isA = ((tob.isintegral() || tob.isfloating()) && tob.ty != Tvector);
+        const(bool) t1b_isA = ((t1b.isintegral() || t1b.isfloating()) && t1b.ty != Tvector);
 
-            // Try casting the alias this member.
-            // Return the expression if it succeeds, null otherwise.
-            Expression tryAliasThisCast()
-            {
-                if (isRecursiveAliasThis(att, t1b))
-                    return null;
+        // Try casting the alias this member.
+        // Return the expression if it succeeds, null otherwise.
+        Expression tryAliasThisCast()
+        {
+            if (isRecursiveAliasThis(att, t1b))
+                return null;
 
-                /* Forward the cast to our alias this member, rewrite to:
-                 *   cast(to)e1.aliasthis
-                 */
-                auto exp = resolveAliasThis(sc, e);
-                const errors = global.startGagging();
-                exp = castTo(exp, sc, t, att);
-                return global.endGagging(errors) ? null : exp;
-            }
+            /* Forward the cast to our alias this member, rewrite to:
+             *   cast(to)e1.aliasthis
+             */
+            auto exp = resolveAliasThis(sc, e);
+            const errors = global.startGagging();
+            exp = castTo(exp, sc, t, att);
+            return global.endGagging(errors) ? null : exp;
+        }
 
-            bool hasAliasThis;
-            if (AggregateDeclaration t1ad = isAggregate(t1b))
-            {
-                AggregateDeclaration toad = isAggregate(tob);
-                if (t1ad != toad && t1ad.aliasthis)
-                {
-                    if (t1b.ty == Tclass && tob.ty == Tclass)
-                    {
-                        ClassDeclaration t1cd = t1b.isClassHandle();
-                        ClassDeclaration tocd = tob.isClassHandle();
-                        int offset;
-                        if (tocd.isBaseOf(t1cd, &offset))
-                            goto Lok;
-                    }
-                    hasAliasThis = true;
-                }
-            }
-            else if (tob.ty == Tvector && t1b.ty != Tvector)
-            {
-                //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
-                TypeVector tv = tob.isTypeVector();
-                result = new CastExp(e.loc, e, tv.elementType());
-                result = new VectorExp(e.loc, result, tob);
-                result = result.expressionSemantic(sc);
-                return;
-            }
-            else if (tob.ty != Tvector && t1b.ty == Tvector)
+        bool hasAliasThis;
+        if (AggregateDeclaration t1ad = isAggregate(t1b))
+        {
+            AggregateDeclaration toad = isAggregate(tob);
+            if (t1ad != toad && t1ad.aliasthis)
             {
-                // T[n] <-- __vector(U[m])
-                if (tob.ty == Tsarray)
+                if (t1b.ty == Tclass && tob.ty == Tclass)
                 {
-                    if (t1b.size(e.loc) == tob.size(e.loc))
+                    ClassDeclaration t1cd = t1b.isClassHandle();
+                    ClassDeclaration tocd = tob.isClassHandle();
+                    int offset;
+                    if (tocd.isBaseOf(t1cd, &offset))
                         goto Lok;
                 }
-                goto Lfail;
+                hasAliasThis = true;
             }
-            else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf()))
+        }
+        else if (tob.ty == Tvector && t1b.ty != Tvector)
+        {
+            //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
+            TypeVector tv = tob.isTypeVector();
+            Expression result = new CastExp(e.loc, e, tv.elementType());
+            result = new VectorExp(e.loc, result, tob);
+            result = result.expressionSemantic(sc);
+            return result;
+        }
+        else if (tob.ty != Tvector && t1b.ty == Tvector)
+        {
+            // T[n] <-- __vector(U[m])
+            if (tob.ty == Tsarray)
             {
-                result = e.copy();
-                result.type = t;
-                return;
+                if (t1b.size(e.loc) == tob.size(e.loc))
+                    goto Lok;
             }
+            goto Lfail;
+        }
+        else if (t1b.implicitConvTo(tob) == MATCH.constant && t.equals(e.type.constOf()))
+        {
+            auto result = e.copy();
+            result.type = t;
+            return result;
+        }
 
-            // arithmetic values vs. other arithmetic values
-            // arithmetic values vs. T*
-            if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer))
-            {
-                goto Lok;
-            }
+        // arithmetic values vs. other arithmetic values
+        // arithmetic values vs. T*
+        if (tob_isA && (t1b_isA || t1b.ty == Tpointer) || t1b_isA && (tob_isA || tob.ty == Tpointer))
+        {
+            goto Lok;
+        }
+
+        // arithmetic values vs. references or fat values
+        if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV))
+        {
+            goto Lfail;
+        }
 
-            // arithmetic values vs. references or fat values
-            if (tob_isA && (t1b_isR || t1b_isFV) || t1b_isA && (tob_isR || tob_isFV))
+        // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
+        if (tob_isFV && t1b_isFV)
+        {
+            if (hasAliasThis)
             {
-                goto Lfail;
+                auto result = tryAliasThisCast();
+                if (result)
+                    return result;
             }
 
-            // Bugzlla 3133: A cast between fat values is possible only when the sizes match.
-            if (tob_isFV && t1b_isFV)
-            {
-                if (hasAliasThis)
-                {
-                    result = tryAliasThisCast();
-                    if (result)
-                        return;
-                }
+            if (t1b.size(e.loc) == tob.size(e.loc))
+                goto Lok;
 
-                if (t1b.size(e.loc) == tob.size(e.loc))
-                    goto Lok;
+            auto ts = toAutoQualChars(e.type, t);
+            e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
+                e.toChars(), ts[0], ts[1]);
+            return ErrorExp.get();
+        }
 
-                auto ts = toAutoQualChars(e.type, t);
-                e.error("cannot cast expression `%s` of type `%s` to `%s` because of different sizes",
-                    e.toChars(), ts[0], ts[1]);
-                result = ErrorExp.get();
-                return;
+        // Fat values vs. null or references
+        if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR))
+        {
+            if (tob.ty == Tpointer && t1b.ty == Tsarray)
+            {
+                // T[n] sa;
+                // cast(U*)sa; // ==> cast(U*)sa.ptr;
+                return new AddrExp(e.loc, e, t);
             }
-
-            // Fat values vs. null or references
-            if (tob_isFV && (t1b.ty == Tnull || t1b_isR) || t1b_isFV && (tob.ty == Tnull || tob_isR))
+            if (tob.ty == Tarray && t1b.ty == Tsarray)
             {
-                if (tob.ty == Tpointer && t1b.ty == Tsarray)
+                // T[n] sa;
+                // cast(U[])sa; // ==> cast(U[])sa[];
+                if (global.params.useDIP1000 == FeatureState.enabled)
                 {
-                    // T[n] sa;
-                    // cast(U*)sa; // ==> cast(U*)sa.ptr;
-                    result = new AddrExp(e.loc, e, t);
-                    return;
-                }
-                if (tob.ty == Tarray && t1b.ty == Tsarray)
-                {
-                    // T[n] sa;
-                    // cast(U[])sa; // ==> cast(U[])sa[];
-                    if (global.params.useDIP1000 == FeatureState.enabled)
+                    if (auto v = expToVariable(e))
                     {
-                        if (auto v = expToVariable(e))
-                        {
-                            if (e.type.hasPointers() && !checkAddressVar(sc, e, v))
-                                goto Lfail;
-                        }
+                        if (e.type.hasPointers() && !checkAddressVar(sc, e, v))
+                            goto Lfail;
                     }
-                    const fsize = t1b.nextOf().size();
-                    const tsize = tob.nextOf().size();
-                    if (fsize == SIZE_INVALID || tsize == SIZE_INVALID)
-                    {
-                        result = ErrorExp.get();
-                        return;
-                    }
-                    if (fsize != tsize)
+                }
+                const fsize = t1b.nextOf().size();
+                const tsize = tob.nextOf().size();
+                if (fsize == SIZE_INVALID || tsize == SIZE_INVALID)
+                {
+                    return ErrorExp.get();
+                }
+                if (fsize != tsize)
+                {
+                    const dim = t1b.isTypeSArray().dim.toInteger();
+                    if (tsize == 0 || (dim * fsize) % tsize != 0)
                     {
-                        const dim = t1b.isTypeSArray().dim.toInteger();
-                        if (tsize == 0 || (dim * fsize) % tsize != 0)
-                        {
-                            e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
-                                    e.toChars(), e.type.toChars(), t.toChars());
-                            result = ErrorExp.get();
-                            return;
-                        }
+                        e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up",
+                                e.toChars(), e.type.toChars(), t.toChars());
+                        return ErrorExp.get();
                     }
-                    goto Lok;
                 }
-                goto Lfail;
+                goto Lok;
             }
+            goto Lfail;
+        }
 
-            /* For references, any reinterpret casts are allowed to same 'ty' type.
-             *      T* to U*
-             *      R1 function(P1) to R2 function(P2)
-             *      R1 delegate(P1) to R2 delegate(P2)
-             *      T[] to U[]
-             *      V1[K1] to V2[K2]
-             *      class/interface A to B  (will be a dynamic cast if possible)
-             */
-            if (tob.ty == t1b.ty && tob_isR && t1b_isR)
-                goto Lok;
+        /* For references, any reinterpret casts are allowed to same 'ty' type.
+         *      T* to U*
+         *      R1 function(P1) to R2 function(P2)
+         *      R1 delegate(P1) to R2 delegate(P2)
+         *      T[] to U[]
+         *      V1[K1] to V2[K2]
+         *      class/interface A to B  (will be a dynamic cast if possible)
+         */
+        if (tob.ty == t1b.ty && tob_isR && t1b_isR)
+            goto Lok;
 
-            // typeof(null) <-- non-null references or values
-            if (tob.ty == Tnull && t1b.ty != Tnull)
-                goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629
-            // typeof(null) --> non-null references or arithmetic values
-            if (t1b.ty == Tnull && tob.ty != Tnull)
-                goto Lok;
+        // typeof(null) <-- non-null references or values
+        if (tob.ty == Tnull && t1b.ty != Tnull)
+            goto Lfail; // https://issues.dlang.org/show_bug.cgi?id=14629
+        // typeof(null) --> non-null references or arithmetic values
+        if (t1b.ty == Tnull && tob.ty != Tnull)
+            goto Lok;
 
-            // Check size mismatch of references.
-            // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
-            if (tob_isFR && t1b_isR || t1b_isFR && tob_isR)
+        // Check size mismatch of references.
+        // Tarray and Tdelegate are (void*).sizeof*2, but others have (void*).sizeof.
+        if (tob_isFR && t1b_isR || t1b_isFR && tob_isR)
+        {
+            if (tob.ty == Tpointer && t1b.ty == Tarray)
             {
-                if (tob.ty == Tpointer && t1b.ty == Tarray)
-                {
-                    // T[] da;
-                    // cast(U*)da; // ==> cast(U*)da.ptr;
-                    goto Lok;
-                }
-                if (tob.ty == Tpointer && t1b.ty == Tdelegate)
-                {
-                    // void delegate() dg;
-                    // cast(U*)dg; // ==> cast(U*)dg.ptr;
-                    // Note that it happens even when U is a Tfunction!
-                    e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars());
-                    goto Lok;
-                }
-                goto Lfail;
+                // T[] da;
+                // cast(U*)da; // ==> cast(U*)da.ptr;
+                goto Lok;
             }
-
-            if (t1b.ty == Tvoid && tob.ty != Tvoid)
+            if (tob.ty == Tpointer && t1b.ty == Tdelegate)
             {
-            Lfail:
-                /* if the cast cannot be performed, maybe there is an alias
-                 * this that can be used for casting.
-                 */
-                if (hasAliasThis)
-                {
-                    result = tryAliasThisCast();
-                    if (result)
-                        return;
-                }
-                e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
-                result = ErrorExp.get();
-                return;
+                // void delegate() dg;
+                // cast(U*)dg; // ==> cast(U*)dg.ptr;
+                // Note that it happens even when U is a Tfunction!
+                e.deprecation("casting from %s to %s is deprecated", e.type.toChars(), t.toChars());
+                goto Lok;
             }
-
-        Lok:
-            result = new CastExp(e.loc, e, t);
-            result.type = t; // Don't call semantic()
-            //printf("Returning: %s\n", result.toChars());
+            goto Lfail;
         }
 
-        override void visit(ErrorExp e)
+        if (t1b.ty == Tvoid && tob.ty != Tvoid)
         {
-            result = e;
+        Lfail:
+            /* if the cast cannot be performed, maybe there is an alias
+             * this that can be used for casting.
+             */
+            if (hasAliasThis)
+            {
+                auto result = tryAliasThisCast();
+                if (result)
+                    return result;
+            }
+            e.error("cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
+            return ErrorExp.get();
         }
 
-        override void visit(RealExp e)
+    Lok:
+        auto result = new CastExp(e.loc, e, t);
+        result.type = t; // Don't call semantic()
+        //printf("Returning: %s\n", result.toChars());
+        return result;
+    }
+
+    Expression visitError(ErrorExp e)
+    {
+        return e;
+    }
+
+    Expression visitReal(RealExp e)
+    {
+        if (!e.type.equals(t))
         {
-            if (!e.type.equals(t))
+            if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary()))
             {
-                if ((e.type.isreal() && t.isreal()) || (e.type.isimaginary() && t.isimaginary()))
-                {
-                    result = e.copy();
-                    result.type = t;
-                }
-                else
-                    visit(cast(Expression)e);
-                return;
+                auto result = e.copy();
+                result.type = t;
+                return result;
             }
-            result = e;
+            else
+                return visit(e);
         }
+        return e;
+    }
 
-        override void visit(ComplexExp e)
+    Expression visitComplex(ComplexExp e)
+    {
+        if (!e.type.equals(t))
         {
-            if (!e.type.equals(t))
+            if (e.type.iscomplex() && t.iscomplex())
             {
-                if (e.type.iscomplex() && t.iscomplex())
-                {
-                    result = e.copy();
-                    result.type = t;
-                }
-                else
-                    visit(cast(Expression)e);
-                return;
+                auto result = e.copy();
+                result.type = t;
+                return result;
             }
-            result = e;
+            else
+                return visit(e);
         }
+        return e;
+    }
+
+    Expression visitStructLiteral(StructLiteralExp e)
+    {
+        auto result = visit(e);
+        if (auto sle = result.isStructLiteralExp())
+            sle.stype = t; // commit type
+        return result;
+    }
+
+    Expression visitString(StringExp e)
+    {
+        /* This follows copy-on-write; any changes to 'this'
+         * will result in a copy.
+         * The this.string member is considered immutable.
+         */
+        int copied = 0;
 
-        override void visit(StructLiteralExp e)
+        //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
+
+        if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
+            (!sc || !(sc.flags & SCOPE.Cfile)))
         {
-            visit(cast(Expression)e);
-            if (auto sle = result.isStructLiteralExp())
-                sle.stype = t; // commit type
+            e.error("cannot convert string literal to `void*`");
+            return ErrorExp.get();
         }
 
-        override void visit(StringExp e)
+        StringExp se = e;
+
+        Expression lcast()
         {
-            /* This follows copy-on-write; any changes to 'this'
-             * will result in a copy.
-             * The this.string member is considered immutable.
-             */
-            int copied = 0;
+            auto result = new CastExp(e.loc, se, t);
+            result.type = t; // so semantic() won't be run on e
+            return result;
+        }
 
-            //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
+        if (!e.committed)
+        {
+            se = e.copy().isStringExp();
+            se.committed = 1;
+            copied = 1;
+        }
+
+        if (e.type.equals(t))
+        {
+            return se;
+        }
+
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
+
+        //printf("\ttype = %s\n", e.type.toChars());
+        if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
+        {
+            return visit(e);
+        }
 
-            if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
-                (!sc || !(sc.flags & SCOPE.Cfile)))
+        if (typeb.equals(tb))
+        {
+            if (!copied)
             {
-                e.error("cannot convert string literal to `void*`");
-                result = ErrorExp.get();
-                return;
+                se = e.copy().isStringExp();
+                copied = 1;
             }
+            se.type = t;
+            return se;
+        }
 
-            StringExp se = e;
+        /* Handle reinterpret casts:
+         *  cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
+         *  cast(wchar[2])"abcd"c --> [\u6261, \u6463]
+         *  cast(wchar[1])"abcd"c --> [\u6261]
+         *  cast(char[4])"a" --> ['a', 0, 0, 0]
+         */
+        if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
+        {
+            se = e.copy().isStringExp();
+            d_uns64 szx = tb.nextOf().size();
+            assert(szx <= 255);
+            se.sz = cast(ubyte)szx;
+            se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
+            se.committed = 1;
+            se.type = t;
 
-            void lcast()
+            /* If larger than source, pad with zeros.
+             */
+            const fullSize = (se.len + 1) * se.sz; // incl. terminating 0
+            if (fullSize > (e.len + 1) * e.sz)
             {
-                result = new CastExp(e.loc, se, t);
-                result.type = t; // so semantic() won't be run on e
+                void* s = mem.xmalloc(fullSize);
+                const srcSize = e.len * e.sz;
+                const data = se.peekData();
+                memcpy(s, data.ptr, srcSize);
+                memset(s + srcSize, 0, fullSize - srcSize);
+                se.setData(s, se.len, se.sz);
             }
+            return se;
+        }
 
-            if (!e.committed)
+        if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer)
+        {
+            if (!copied)
             {
                 se = e.copy().isStringExp();
-                se.committed = 1;
                 copied = 1;
             }
-
-            if (e.type.equals(t))
+            return lcast();
+        }
+        if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
+        {
+            if (!copied)
             {
-                result = se;
-                return;
+                se = e.copy().isStringExp();
+                copied = 1;
             }
+            return lcast();
+        }
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
-
-            //printf("\ttype = %s\n", e.type.toChars());
-            if (tb.ty == Tdelegate && typeb.ty != Tdelegate)
+        const nextSz = typeb.nextOf().size();
+        if (nextSz == SIZE_INVALID)
+        {
+            return ErrorExp.get();
+        }
+        if (nextSz == tb.nextOf().size())
+        {
+            if (!copied)
             {
-                visit(cast(Expression)e);
-                return;
+                se = e.copy().isStringExp();
+                copied = 1;
             }
+            if (tb.ty == Tsarray)
+                goto L2; // handle possible change in static array dimension
+            se.type = t;
+            return se;
+        }
+
+        if (e.committed)
+            goto Lcast;
+
+        auto X(T, U)(T tf, U tt)
+        {
+            return (cast(int)tf * 256 + cast(int)tt);
+        }
 
-            if (typeb.equals(tb))
+        {
+            OutBuffer buffer;
+            size_t newlen = 0;
+            int tfty = typeb.nextOf().toBasetype().ty;
+            int ttty = tb.nextOf().toBasetype().ty;
+            switch (X(tfty, ttty))
             {
-                if (!copied)
+            case X(Tchar, Tchar):
+            case X(Twchar, Twchar):
+            case X(Tdchar, Tdchar):
+                break;
+
+            case X(Tchar, Twchar):
+                for (size_t u = 0; u < e.len;)
                 {
-                    se = e.copy().isStringExp();
-                    copied = 1;
+                    dchar c;
+                    if (const s = utf_decodeChar(se.peekString(), u, c))
+                        e.error("%.*s", cast(int)s.length, s.ptr);
+                    else
+                        buffer.writeUTF16(c);
                 }
-                se.type = t;
-                result = se;
-                return;
-            }
+                newlen = buffer.length / 2;
+                buffer.writeUTF16(0);
+                goto L1;
 
-            /* Handle reinterpret casts:
-             *  cast(wchar[3])"abcd"c --> [\u6261, \u6463, \u0000]
-             *  cast(wchar[2])"abcd"c --> [\u6261, \u6463]
-             *  cast(wchar[1])"abcd"c --> [\u6261]
-             *  cast(char[4])"a" --> ['a', 0, 0, 0]
-             */
-            if (e.committed && tb.ty == Tsarray && typeb.ty == Tarray)
-            {
-                se = e.copy().isStringExp();
-                d_uns64 szx = tb.nextOf().size();
-                assert(szx <= 255);
-                se.sz = cast(ubyte)szx;
-                se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
-                se.committed = 1;
-                se.type = t;
-
-                /* If larger than source, pad with zeros.
-                 */
-                const fullSize = (se.len + 1) * se.sz; // incl. terminating 0
-                if (fullSize > (e.len + 1) * e.sz)
+            case X(Tchar, Tdchar):
+                for (size_t u = 0; u < e.len;)
                 {
-                    void* s = mem.xmalloc(fullSize);
-                    const srcSize = e.len * e.sz;
-                    const data = se.peekData();
-                    memcpy(s, data.ptr, srcSize);
-                    memset(s + srcSize, 0, fullSize - srcSize);
-                    se.setData(s, se.len, se.sz);
+                    dchar c;
+                    if (const s = utf_decodeChar(se.peekString(), u, c))
+                        e.error("%.*s", cast(int)s.length, s.ptr);
+                    buffer.write4(c);
+                    newlen++;
                 }
-                result = se;
-                return;
-            }
+                buffer.write4(0);
+                goto L1;
 
-            if (tb.ty != Tsarray && tb.ty != Tarray && tb.ty != Tpointer)
-            {
-                if (!copied)
+            case X(Twchar, Tchar):
+                for (size_t u = 0; u < e.len;)
                 {
-                    se = e.copy().isStringExp();
-                    copied = 1;
+                    dchar c;
+                    if (const s = utf_decodeWchar(se.peekWstring(), u, c))
+                        e.error("%.*s", cast(int)s.length, s.ptr);
+                    else
+                        buffer.writeUTF8(c);
                 }
-                return lcast();
-            }
-            if (typeb.ty != Tsarray && typeb.ty != Tarray && typeb.ty != Tpointer)
-            {
-                if (!copied)
+                newlen = buffer.length;
+                buffer.writeUTF8(0);
+                goto L1;
+
+            case X(Twchar, Tdchar):
+                for (size_t u = 0; u < e.len;)
                 {
-                    se = e.copy().isStringExp();
-                    copied = 1;
+                    dchar c;
+                    if (const s = utf_decodeWchar(se.peekWstring(), u, c))
+                        e.error("%.*s", cast(int)s.length, s.ptr);
+                    buffer.write4(c);
+                    newlen++;
                 }
-                return lcast();
-            }
+                buffer.write4(0);
+                goto L1;
 
-            const nextSz = typeb.nextOf().size();
-            if (nextSz == SIZE_INVALID)
-            {
-                result = ErrorExp.get();
-                return;
-            }
-            if (nextSz == tb.nextOf().size())
-            {
-                if (!copied)
+            case X(Tdchar, Tchar):
+                for (size_t u = 0; u < e.len; u++)
                 {
-                    se = e.copy().isStringExp();
-                    copied = 1;
+                    uint c = se.peekDstring()[u];
+                    if (!utf_isValidDchar(c))
+                        e.error("invalid UCS-32 char \\U%08x", c);
+                    else
+                        buffer.writeUTF8(c);
+                    newlen++;
                 }
-                if (tb.ty == Tsarray)
-                    goto L2; // handle possible change in static array dimension
-                se.type = t;
-                result = se;
-                return;
-            }
-
-            if (e.committed)
-                goto Lcast;
-
-            auto X(T, U)(T tf, U tt)
-            {
-                return (cast(int)tf * 256 + cast(int)tt);
-            }
+                newlen = buffer.length;
+                buffer.writeUTF8(0);
+                goto L1;
 
-            {
-                OutBuffer buffer;
-                size_t newlen = 0;
-                int tfty = typeb.nextOf().toBasetype().ty;
-                int ttty = tb.nextOf().toBasetype().ty;
-                switch (X(tfty, ttty))
+            case X(Tdchar, Twchar):
+                for (size_t u = 0; u < e.len; u++)
                 {
-                case X(Tchar, Tchar):
-                case X(Twchar, Twchar):
-                case X(Tdchar, Tdchar):
-                    break;
-
-                case X(Tchar, Twchar):
-                    for (size_t u = 0; u < e.len;)
-                    {
-                        dchar c;
-                        if (const s = utf_decodeChar(se.peekString(), u, c))
-                            e.error("%.*s", cast(int)s.length, s.ptr);
-                        else
-                            buffer.writeUTF16(c);
-                    }
-                    newlen = buffer.length / 2;
-                    buffer.writeUTF16(0);
-                    goto L1;
-
-                case X(Tchar, Tdchar):
-                    for (size_t u = 0; u < e.len;)
-                    {
-                        dchar c;
-                        if (const s = utf_decodeChar(se.peekString(), u, c))
-                            e.error("%.*s", cast(int)s.length, s.ptr);
-                        buffer.write4(c);
-                        newlen++;
-                    }
-                    buffer.write4(0);
-                    goto L1;
-
-                case X(Twchar, Tchar):
-                    for (size_t u = 0; u < e.len;)
-                    {
-                        dchar c;
-                        if (const s = utf_decodeWchar(se.peekWstring(), u, c))
-                            e.error("%.*s", cast(int)s.length, s.ptr);
-                        else
-                            buffer.writeUTF8(c);
-                    }
-                    newlen = buffer.length;
-                    buffer.writeUTF8(0);
-                    goto L1;
-
-                case X(Twchar, Tdchar):
-                    for (size_t u = 0; u < e.len;)
-                    {
-                        dchar c;
-                        if (const s = utf_decodeWchar(se.peekWstring(), u, c))
-                            e.error("%.*s", cast(int)s.length, s.ptr);
-                        buffer.write4(c);
-                        newlen++;
-                    }
-                    buffer.write4(0);
-                    goto L1;
-
-                case X(Tdchar, Tchar):
-                    for (size_t u = 0; u < e.len; u++)
-                    {
-                        uint c = se.peekDstring()[u];
-                        if (!utf_isValidDchar(c))
-                            e.error("invalid UCS-32 char \\U%08x", c);
-                        else
-                            buffer.writeUTF8(c);
-                        newlen++;
-                    }
-                    newlen = buffer.length;
-                    buffer.writeUTF8(0);
-                    goto L1;
-
-                case X(Tdchar, Twchar):
-                    for (size_t u = 0; u < e.len; u++)
-                    {
-                        uint c = se.peekDstring()[u];
-                        if (!utf_isValidDchar(c))
-                            e.error("invalid UCS-32 char \\U%08x", c);
-                        else
-                            buffer.writeUTF16(c);
-                        newlen++;
-                    }
-                    newlen = buffer.length / 2;
-                    buffer.writeUTF16(0);
-                    goto L1;
-
-                L1:
-                    if (!copied)
-                    {
-                        se = e.copy().isStringExp();
-                        copied = 1;
-                    }
-
-                    {
-                        d_uns64 szx = tb.nextOf().size();
-                        assert(szx <= 255);
-                        se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx);
-                    }
-                    break;
-
-                default:
-                    assert(typeb.nextOf().size() != tb.nextOf().size());
-                    goto Lcast;
+                    uint c = se.peekDstring()[u];
+                    if (!utf_isValidDchar(c))
+                        e.error("invalid UCS-32 char \\U%08x", c);
+                    else
+                        buffer.writeUTF16(c);
+                    newlen++;
                 }
-            }
-        L2:
-            assert(copied);
+                newlen = buffer.length / 2;
+                buffer.writeUTF16(0);
+                goto L1;
 
-            // See if need to truncate or extend the literal
-            if (auto tsa = tb.isTypeSArray())
-            {
-                size_t dim2 = cast(size_t)tsa.dim.toInteger();
-                //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
+            L1:
+                if (!copied)
+                {
+                    se = e.copy().isStringExp();
+                    copied = 1;
+                }
 
-                // Changing dimensions
-                if (dim2 != se.len)
                 {
-                    // Copy when changing the string literal
-                    const newsz = se.sz;
-                    const d = (dim2 < se.len) ? dim2 : se.len;
-                    void* s = mem.xmalloc((dim2 + 1) * newsz);
-                    memcpy(s, se.peekData().ptr, d * newsz);
-                    // Extend with 0, add terminating 0
-                    memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz);
-                    se.setData(s, dim2, newsz);
+                    d_uns64 szx = tb.nextOf().size();
+                    assert(szx <= 255);
+                    se.setData(buffer.extractSlice().ptr, newlen, cast(ubyte)szx);
                 }
-            }
-            se.type = t;
-            result = se;
-            return;
+                break;
 
-        Lcast:
-            result = new CastExp(e.loc, se, t);
-            result.type = t; // so semantic() won't be run on e
+            default:
+                assert(typeb.nextOf().size() != tb.nextOf().size());
+                goto Lcast;
+            }
         }
+    L2:
+        assert(copied);
 
-        override void visit(AddrExp e)
+        // See if need to truncate or extend the literal
+        if (auto tsa = tb.isTypeSArray())
         {
-            version (none)
+            size_t dim2 = cast(size_t)tsa.dim.toInteger();
+            //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
+
+            // Changing dimensions
+            if (dim2 != se.len)
             {
-                printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+                // Copy when changing the string literal
+                const newsz = se.sz;
+                const d = (dim2 < se.len) ? dim2 : se.len;
+                void* s = mem.xmalloc((dim2 + 1) * newsz);
+                memcpy(s, se.peekData().ptr, d * newsz);
+                // Extend with 0, add terminating 0
+                memset(s + d * newsz, 0, (dim2 + 1 - d) * newsz);
+                se.setData(s, dim2, newsz);
             }
-            result = e;
+        }
+        se.type = t;
+        return se;
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+    Lcast:
+        auto result = new CastExp(e.loc, se, t);
+        result.type = t; // so semantic() won't be run on e
+        return result;
+    }
 
-            if (tb.equals(typeb))
-            {
-                result = e.copy();
-                result.type = t;
-                return;
-            }
+    Expression visitAddr(AddrExp e)
+    {
+        version (none)
+        {
+            printf("AddrExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            // Look for pointers to functions where the functions are overloaded.
-            if (e.e1.isOverExp() &&
-                (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
-            {
-                OverExp eo = e.e1.isOverExp();
-                FuncDeclaration f = null;
-                for (size_t i = 0; i < eo.vars.a.dim; i++)
-                {
-                    auto s = eo.vars.a[i];
-                    auto f2 = s.isFuncDeclaration();
-                    assert(f2);
-                    if (f2.overloadExactMatch(tb.nextOf()))
-                    {
-                        if (f)
-                        {
-                            /* Error if match in more than one overload set,
-                             * even if one is a 'better' match than the other.
-                             */
-                            ScopeDsymbol.multiplyDefined(e.loc, f, f2);
-                        }
-                        else
-                            f = f2;
-                    }
-                }
-                if (f)
-                {
-                    f.tookAddressOf++;
-                    auto se = new SymOffExp(e.loc, f, 0, false);
-                    auto se2 = se.expressionSemantic(sc);
-                    // Let SymOffExp::castTo() do the heavy lifting
-                    visit(se2);
-                    return;
-                }
-            }
+        if (tb.equals(typeb))
+        {
+            auto result = e.copy();
+            result.type = t;
+            return result;
+        }
 
-            if (e.e1.isVarExp() &&
-                typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
-                tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
+        // Look for pointers to functions where the functions are overloaded.
+        if (e.e1.isOverExp() &&
+            (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        {
+            OverExp eo = e.e1.isOverExp();
+            FuncDeclaration f = null;
+            for (size_t i = 0; i < eo.vars.a.dim; i++)
             {
-                auto ve = e.e1.isVarExp();
-                auto f = ve.var.isFuncDeclaration();
-                if (f)
+                auto s = eo.vars.a[i];
+                auto f2 = s.isFuncDeclaration();
+                assert(f2);
+                if (f2.overloadExactMatch(tb.nextOf()))
                 {
-                    assert(f.isImportedSymbol());
-                    f = f.overloadExactMatch(tb.nextOf());
                     if (f)
                     {
-                        result = new VarExp(e.loc, f, false);
-                        result.type = f.type;
-                        result = new AddrExp(e.loc, result, t);
-                        return;
+                        /* Error if match in more than one overload set,
+                         * even if one is a 'better' match than the other.
+                         */
+                        ScopeDsymbol.multiplyDefined(e.loc, f, f2);
                     }
+                    else
+                        f = f2;
                 }
             }
+            if (f)
+            {
+                f.tookAddressOf++;
+                auto se = new SymOffExp(e.loc, f, 0, false);
+                auto se2 = se.expressionSemantic(sc);
+                // Let SymOffExp::castTo() do the heavy lifting
+                return visit(se2);
+            }
+        }
 
-            if (auto f = isFuncAddress(e))
+        if (e.e1.isVarExp() &&
+            typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+            tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
+        {
+            auto ve = e.e1.isVarExp();
+            auto f = ve.var.isFuncDeclaration();
+            if (f)
             {
-                if (f.checkForwardRef(e.loc))
+                assert(f.isImportedSymbol());
+                f = f.overloadExactMatch(tb.nextOf());
+                if (f)
                 {
-                    result = ErrorExp.get();
-                    return;
+                    Expression result = new VarExp(e.loc, f, false);
+                    result.type = f.type;
+                    result = new AddrExp(e.loc, result, t);
+                    return result;
                 }
             }
-
-            visit(cast(Expression)e);
         }
 
-        override void visit(TupleExp e)
+        if (auto f = isFuncAddress(e))
         {
-            if (e.type.equals(t))
+            if (f.checkForwardRef(e.loc))
             {
-                result = e;
-                return;
+                return ErrorExp.get();
             }
-
-            /* If target type is a tuple of same length, cast each expression to
-             * the corresponding type in the tuple.
-             */
-            TypeTuple totuple;
-            if (auto tt = t.isTypeTuple())
-                totuple = e.exps.length == tt.arguments.length ? tt : null;
-
-            TupleExp te = e.copy().isTupleExp();
-            te.e0 = e.e0 ? e.e0.copy() : null;
-            te.exps = e.exps.copy();
-            for (size_t i = 0; i < te.exps.dim; i++)
-            {
-                Expression ex = (*te.exps)[i];
-                ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
-                (*te.exps)[i] = ex;
-            }
-            if (totuple)
-                te.type = totuple;
-            result = te;
-
-            /* Questionable behavior: In here, result.type is not set to t
-             *  if target type is not a tuple of same length.
-             * Therefoe:
-             *  TypeTuple!(int, int) values;
-             *  auto values2 = cast(long)values;
-             *  // typeof(values2) == TypeTuple!(int, int) !!
-             *
-             * Only when the casted tuple is immediately expanded, it would work.
-             *  auto arr = [cast(long)values];
-             *  // typeof(arr) == long[]
-             */
         }
 
-        override void visit(ArrayLiteralExp e)
+        return visit(e);
+    }
+
+    Expression visitTuple(TupleExp e)
+    {
+        if (e.type.equals(t))
         {
-            version (none)
-            {
-                printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            }
+            return e;
+        }
 
-            ArrayLiteralExp ae = e;
+        /* If target type is a tuple of same length, cast each expression to
+         * the corresponding type in the tuple.
+         */
+        TypeTuple totuple;
+        if (auto tt = t.isTypeTuple())
+            totuple = e.exps.length == tt.arguments.length ? tt : null;
+
+        TupleExp te = e.copy().isTupleExp();
+        te.e0 = e.e0 ? e.e0.copy() : null;
+        te.exps = e.exps.copy();
+        for (size_t i = 0; i < te.exps.dim; i++)
+        {
+            Expression ex = (*te.exps)[i];
+            ex = ex.castTo(sc, totuple ? (*totuple.arguments)[i].type : t);
+            (*te.exps)[i] = ex;
+        }
+        if (totuple)
+            te.type = totuple;
+        return te;
+
+        /* Questionable behavior: In here, result.type is not set to t
+         *  if target type is not a tuple of same length.
+         * Therefoe:
+         *  TypeTuple!(int, int) values;
+         *  auto values2 = cast(long)values;
+         *  // typeof(values2) == TypeTuple!(int, int) !!
+         *
+         * Only when the casted tuple is immediately expanded, it would work.
+         *  auto arr = [cast(long)values];
+         *  // typeof(arr) == long[]
+         */
+    }
 
-            Type tb = t.toBasetype();
-            if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled)
-            {
-                if (checkArrayLiteralEscape(sc, ae, false))
-                {
-                    result = ErrorExp.get();
-                    return;
-                }
-            }
+    Expression visitArrayLiteral(ArrayLiteralExp e)
+    {
+        version (none)
+        {
+            printf("ArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+
+        ArrayLiteralExp ae = e;
 
-            if (e.type == t)
+        Type tb = t.toBasetype();
+        if (tb.ty == Tarray && global.params.useDIP1000 == FeatureState.enabled)
+        {
+            if (checkArrayLiteralEscape(sc, ae, false))
             {
-                result = e;
-                return;
+                return ErrorExp.get();
             }
-            Type typeb = e.type.toBasetype();
+        }
 
-            if ((tb.ty == Tarray || tb.ty == Tsarray) &&
-                (typeb.ty == Tarray || typeb.ty == Tsarray))
-            {
-                if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)
-                {
-                    // Don't do anything to cast non-void[] to void[]
-                }
-                else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid)
-                {
-                    // Don't do anything for casting void[n] to others
-                }
-                else
-                {
-                    if (auto tsa = tb.isTypeSArray())
-                    {
-                        if (e.elements.dim != tsa.dim.toInteger())
-                            goto L1;
-                    }
+        if (e.type == t)
+        {
+            return e;
+        }
+        Type typeb = e.type.toBasetype();
 
-                    ae = e.copy().isArrayLiteralExp();
-                    if (e.basis)
-                        ae.basis = e.basis.castTo(sc, tb.nextOf());
-                    ae.elements = e.elements.copy();
-                    for (size_t i = 0; i < e.elements.dim; i++)
-                    {
-                        Expression ex = (*e.elements)[i];
-                        if (!ex)
-                            continue;
-                        ex = ex.castTo(sc, tb.nextOf());
-                        (*ae.elements)[i] = ex;
-                    }
-                    ae.type = t;
-                    result = ae;
-                    return;
-                }
+        if ((tb.ty == Tarray || tb.ty == Tsarray) &&
+            (typeb.ty == Tarray || typeb.ty == Tsarray))
+        {
+            if (tb.nextOf().toBasetype().ty == Tvoid && typeb.nextOf().toBasetype().ty != Tvoid)
+            {
+                // Don't do anything to cast non-void[] to void[]
             }
-            else if (tb.ty == Tpointer && typeb.ty == Tsarray)
+            else if (typeb.ty == Tsarray && typeb.nextOf().toBasetype().ty == Tvoid)
             {
-                Type tp = typeb.nextOf().pointerTo();
-                if (!tp.equals(ae.type))
-                {
-                    ae = e.copy().isArrayLiteralExp();
-                    ae.type = tp;
-                }
+                // Don't do anything for casting void[n] to others
             }
-            else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
+            else
             {
-                // Convert array literal to vector type
-                TypeVector tv = tb.isTypeVector();
-                TypeSArray tbase = tv.basetype.isTypeSArray();
-                assert(tbase.ty == Tsarray);
-                const edim = e.elements.dim;
-                const tbasedim = tbase.dim.toInteger();
-                if (edim > tbasedim)
-                    goto L1;
+                if (auto tsa = tb.isTypeSArray())
+                {
+                    if (e.elements.dim != tsa.dim.toInteger())
+                        goto L1;
+                }
 
                 ae = e.copy().isArrayLiteralExp();
-                ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642
+                if (e.basis)
+                    ae.basis = e.basis.castTo(sc, tb.nextOf());
                 ae.elements = e.elements.copy();
-                Type telement = tv.elementType();
-                foreach (i; 0 .. edim)
+                for (size_t i = 0; i < e.elements.dim; i++)
                 {
                     Expression ex = (*e.elements)[i];
-                    ex = ex.castTo(sc, telement);
-                    (*ae.elements)[i] = ex;
-                }
-                // Fill in the rest with the default initializer
-                ae.elements.setDim(cast(size_t)tbasedim);
-                foreach (i; edim .. cast(size_t)tbasedim)
-                {
-                    Expression ex = typeb.nextOf.defaultInitLiteral(e.loc);
-                    ex = ex.castTo(sc, telement);
+                    if (!ex)
+                        continue;
+                    ex = ex.castTo(sc, tb.nextOf());
                     (*ae.elements)[i] = ex;
                 }
-                Expression ev = new VectorExp(e.loc, ae, tb);
-                ev = ev.expressionSemantic(sc);
-                result = ev;
-                return;
+                ae.type = t;
+                return ae;
             }
-        L1:
-            visit(cast(Expression)ae);
         }
-
-        override void visit(AssocArrayLiteralExp e)
+        else if (tb.ty == Tpointer && typeb.ty == Tsarray)
         {
-            //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
-            if (e.type == t)
-            {
-                result = e;
-                return;
-            }
-
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
-
-            if (tb.ty == Taarray && typeb.ty == Taarray &&
-                tb.nextOf().toBasetype().ty != Tvoid)
+            Type tp = typeb.nextOf().pointerTo();
+            if (!tp.equals(ae.type))
             {
-                AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp();
-                ae.keys = e.keys.copy();
-                ae.values = e.values.copy();
-                assert(e.keys.dim == e.values.dim);
-                for (size_t i = 0; i < e.keys.dim; i++)
-                {
-                    Expression ex = (*e.values)[i];
-                    ex = ex.castTo(sc, tb.nextOf());
-                    (*ae.values)[i] = ex;
-
-                    ex = (*e.keys)[i];
-                    ex = ex.castTo(sc, tb.isTypeAArray().index);
-                    (*ae.keys)[i] = ex;
-                }
-                ae.type = t;
-                result = ae;
-                return;
+                ae = e.copy().isArrayLiteralExp();
+                ae.type = tp;
             }
-            visit(cast(Expression)e);
         }
-
-        override void visit(SymOffExp e)
+        else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
         {
-            version (none)
+            // Convert array literal to vector type
+            TypeVector tv = tb.isTypeVector();
+            TypeSArray tbase = tv.basetype.isTypeSArray();
+            assert(tbase.ty == Tsarray);
+            const edim = e.elements.dim;
+            const tbasedim = tbase.dim.toInteger();
+            if (edim > tbasedim)
+                goto L1;
+
+            ae = e.copy().isArrayLiteralExp();
+            ae.type = tbase; // https://issues.dlang.org/show_bug.cgi?id=12642
+            ae.elements = e.elements.copy();
+            Type telement = tv.elementType();
+            foreach (i; 0 .. edim)
             {
-                printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+                Expression ex = (*e.elements)[i];
+                ex = ex.castTo(sc, telement);
+                (*ae.elements)[i] = ex;
             }
-            if (e.type == t && !e.hasOverloads)
+            // Fill in the rest with the default initializer
+            ae.elements.setDim(cast(size_t)tbasedim);
+            foreach (i; edim .. cast(size_t)tbasedim)
             {
-                result = e;
-                return;
+                Expression ex = typeb.nextOf.defaultInitLiteral(e.loc);
+                ex = ex.castTo(sc, telement);
+                (*ae.elements)[i] = ex;
             }
+            Expression ev = new VectorExp(e.loc, ae, tb);
+            ev = ev.expressionSemantic(sc);
+            return ev;
+        }
+    L1:
+        return visit(ae);
+    }
+
+    Expression visitAssocArrayLiteral(AssocArrayLiteralExp e)
+    {
+        //printf("AssocArrayLiteralExp::castTo(this=%s, type=%s, => %s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        if (e.type == t)
+        {
+            return e;
+        }
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            if (tb.equals(typeb))
+        if (tb.ty == Taarray && typeb.ty == Taarray &&
+            tb.nextOf().toBasetype().ty != Tvoid)
+        {
+            AssocArrayLiteralExp ae = e.copy().isAssocArrayLiteralExp();
+            ae.keys = e.keys.copy();
+            ae.values = e.values.copy();
+            assert(e.keys.dim == e.values.dim);
+            for (size_t i = 0; i < e.keys.dim; i++)
             {
-                result = e.copy();
-                result.type = t;
-                result.isSymOffExp().hasOverloads = false;
-                return;
+                Expression ex = (*e.values)[i];
+                ex = ex.castTo(sc, tb.nextOf());
+                (*ae.values)[i] = ex;
+
+                ex = (*e.keys)[i];
+                ex = ex.castTo(sc, tb.isTypeAArray().index);
+                (*ae.keys)[i] = ex;
             }
+            ae.type = t;
+            return ae;
+        }
+        return visit(e);
+    }
+
+    Expression visitSymOff(SymOffExp e)
+    {
+        version (none)
+        {
+            printf("SymOffExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        if (e.type == t && !e.hasOverloads)
+        {
+            return e;
+        }
+
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
+
+        if (tb.equals(typeb))
+        {
+            auto result = e.copy();
+            result.type = t;
+            result.isSymOffExp().hasOverloads = false;
+            return result;
+        }
 
-            // Look for pointers to functions where the functions are overloaded.
-            if (e.hasOverloads &&
-                typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
-                (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        // Look for pointers to functions where the functions are overloaded.
+        if (e.hasOverloads &&
+            typeb.ty == Tpointer && typeb.nextOf().ty == Tfunction &&
+            (tb.ty == Tpointer || tb.ty == Tdelegate) && tb.nextOf().ty == Tfunction)
+        {
+            FuncDeclaration f = e.var.isFuncDeclaration();
+            f = f ? f.overloadExactMatch(tb.nextOf()) : null;
+            if (f)
             {
-                FuncDeclaration f = e.var.isFuncDeclaration();
-                f = f ? f.overloadExactMatch(tb.nextOf()) : null;
-                if (f)
+                Expression result;
+                if (tb.ty == Tdelegate)
                 {
-                    if (tb.ty == Tdelegate)
+                    if (f.needThis() && hasThis(sc))
                     {
-                        if (f.needThis() && hasThis(sc))
-                        {
-                            result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false);
-                            result = result.expressionSemantic(sc);
-                        }
-                        else if (f.needThis())
-                        {
-                            e.error("no `this` to create delegate for `%s`", f.toChars());
-                            result = ErrorExp.get();
-                            return;
-                        }
-                        else if (f.isNested())
-                        {
-                            result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
-                            result = result.expressionSemantic(sc);
-                        }
-                        else
-                        {
-                            e.error("cannot cast from function pointer to delegate");
-                            result = ErrorExp.get();
-                            return;
-                        }
+                        result = new DelegateExp(e.loc, new ThisExp(e.loc), f, false);
+                        result = result.expressionSemantic(sc);
+                    }
+                    else if (f.needThis())
+                    {
+                        e.error("no `this` to create delegate for `%s`", f.toChars());
+                        return ErrorExp.get();
+                    }
+                    else if (f.isNested())
+                    {
+                        result = new DelegateExp(e.loc, IntegerExp.literal!0, f, false);
+                        result = result.expressionSemantic(sc);
                     }
                     else
                     {
-                        result = new SymOffExp(e.loc, f, 0, false);
-                        result.type = t;
+                        e.error("cannot cast from function pointer to delegate");
+                        return ErrorExp.get();
                     }
-                    f.tookAddressOf++;
-                    return;
                 }
-            }
-
-            if (auto f = isFuncAddress(e))
-            {
-                if (f.checkForwardRef(e.loc))
+                else
                 {
-                    result = ErrorExp.get();
-                    return;
+                    result = new SymOffExp(e.loc, f, 0, false);
+                    result.type = t;
                 }
+                f.tookAddressOf++;
+                return result;
             }
-
-            visit(cast(Expression)e);
         }
 
-        override void visit(DelegateExp e)
+        if (auto f = isFuncAddress(e))
         {
-            version (none)
+            if (f.checkForwardRef(e.loc))
             {
-                printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+                return ErrorExp.get();
             }
-            __gshared const(char)* msg = "cannot form delegate due to covariant return type";
+        }
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        return visit(e);
+    }
 
-            if (tb.equals(typeb) && !e.hasOverloads)
-            {
-                int offset;
-                e.func.tookAddressOf++;
-                if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
-                    e.error("%s", msg);
-                result = e.copy();
-                result.type = t;
-                return;
-            }
+    Expression visitDelegate(DelegateExp e)
+    {
+        version (none)
+        {
+            printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
+        }
+        __gshared const(char)* msg = "cannot form delegate due to covariant return type";
 
-            // Look for delegates to functions where the functions are overloaded.
-            if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
-            {
-                if (e.func)
-                {
-                    auto f = e.func.overloadExactMatch(tb.nextOf());
-                    if (f)
-                    {
-                        int offset;
-                        if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
-                            e.error("%s", msg);
-                        if (f != e.func)    // if address not already marked as taken
-                            f.tookAddressOf++;
-                        result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
-                        result.type = t;
-                        return;
-                    }
-                    if (e.func.tintro)
-                        e.error("%s", msg);
-                }
-            }
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
+
+        if (tb.equals(typeb) && !e.hasOverloads)
+        {
+            int offset;
+            e.func.tookAddressOf++;
+            if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
+                e.error("%s", msg);
+            auto result = e.copy();
+            result.type = t;
+            return result;
+        }
 
-            if (auto f = isFuncAddress(e))
+        // Look for delegates to functions where the functions are overloaded.
+        if (typeb.ty == Tdelegate && tb.ty == Tdelegate)
+        {
+            if (e.func)
             {
-                if (f.checkForwardRef(e.loc))
+                auto f = e.func.overloadExactMatch(tb.nextOf());
+                if (f)
                 {
-                    result = ErrorExp.get();
-                    return;
+                    int offset;
+                    if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
+                        e.error("%s", msg);
+                    if (f != e.func)    // if address not already marked as taken
+                        f.tookAddressOf++;
+                    auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
+                    result.type = t;
+                    return result;
                 }
+                if (e.func.tintro)
+                    e.error("%s", msg);
             }
-
-            visit(cast(Expression)e);
         }
 
-        override void visit(FuncExp e)
+        if (auto f = isFuncAddress(e))
         {
-            //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
-            FuncExp fe;
-            if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch)
+            if (f.checkForwardRef(e.loc))
             {
-                result = fe;
-                return;
+                return ErrorExp.get();
             }
-            visit(cast(Expression)e);
         }
 
-        override void visit(CondExp e)
+        return visit(e);
+    }
+
+    Expression visitFunc(FuncExp e)
+    {
+        //printf("FuncExp::castTo type = %s, t = %s\n", e.type.toChars(), t.toChars());
+        FuncExp fe;
+        if (e.matchType(t, sc, &fe, 1) > MATCH.nomatch)
         {
-            if (!e.type.equals(t))
-            {
-                result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t));
-                result.type = t;
-                return;
-            }
-            result = e;
+            return fe;
         }
+        return visit(e);
+    }
 
-        override void visit(CommaExp e)
+    Expression visitCond(CondExp e)
+    {
+        if (!e.type.equals(t))
         {
-            Expression e2c = e.e2.castTo(sc, t);
-
-            if (e2c != e.e2)
-            {
-                result = new CommaExp(e.loc, e.e1, e2c);
-                result.type = e2c.type;
-            }
-            else
-            {
-                result = e;
-                result.type = e.e2.type;
-            }
+            auto result = new CondExp(e.loc, e.econd, e.e1.castTo(sc, t), e.e2.castTo(sc, t));
+            result.type = t;
+            return result;
         }
+        return e;
+    }
 
-        override void visit(SliceExp e)
+    Expression visitComma(CommaExp e)
+    {
+        Expression e2c = e.e2.castTo(sc, t);
+
+        if (e2c != e.e2)
+        {
+            auto result = new CommaExp(e.loc, e.e1, e2c);
+            result.type = e2c.type;
+            return result;
+        }
+        else
         {
-            //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
+            e.type = e.e2.type;
+            return e;
+        }
+    }
+
+    Expression visitSlice(SliceExp e)
+    {
+        //printf("SliceExp::castTo e = %s, type = %s, t = %s\n", e.toChars(), e.type.toChars(), t.toChars());
+
+        Type tb = t.toBasetype();
+        Type typeb = e.type.toBasetype();
 
-            Type tb = t.toBasetype();
-            Type typeb = e.type.toBasetype();
+        if (e.type.equals(t) || typeb.ty != Tarray ||
+            (tb.ty != Tarray && tb.ty != Tsarray))
+        {
+            return visit(e);
+        }
 
-            if (e.type.equals(t) || typeb.ty != Tarray ||
-                (tb.ty != Tarray && tb.ty != Tsarray))
+        if (tb.ty == Tarray)
+        {
+            if (typeb.nextOf().equivalent(tb.nextOf()))
             {
-                visit(cast(Expression)e);
-                return;
+                // T[] to const(T)[]
+                auto result = e.copy();
+                result.type = t;
+                return result;
             }
-
-            if (tb.ty == Tarray)
+            else
             {
-                if (typeb.nextOf().equivalent(tb.nextOf()))
-                {
-                    // T[] to const(T)[]
-                    result = e.copy();
-                    result.type = t;
-                }
-                else
-                {
-                    visit(cast(Expression)e);
-                }
-                return;
+                return visit(e);
             }
+        }
 
-            // Handle the cast from Tarray to Tsarray with CT-known slicing
+        // Handle the cast from Tarray to Tsarray with CT-known slicing
 
-            TypeSArray tsa = toStaticArrayType(e).isTypeSArray();
-            if (tsa && tsa.size(e.loc) == tb.size(e.loc))
-            {
-                /* Match if the sarray sizes are equal:
-                 *  T[a .. b] to const(T)[b-a]
-                 *  T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
-                 *
-                 * If a SliceExp has Tsarray, it will become lvalue.
-                 * That's handled in SliceExp::isLvalue and toLvalue
-                 */
-                result = e.copy();
-                result.type = t;
-                return;
-            }
-            if (tsa && tsa.dim.equals(tb.isTypeSArray().dim))
+        TypeSArray tsa = toStaticArrayType(e).isTypeSArray();
+        if (tsa && tsa.size(e.loc) == tb.size(e.loc))
+        {
+            /* Match if the sarray sizes are equal:
+             *  T[a .. b] to const(T)[b-a]
+             *  T[a .. b] to U[dim] if (T.sizeof*(b-a) == U.sizeof*dim)
+             *
+             * If a SliceExp has Tsarray, it will become lvalue.
+             * That's handled in SliceExp::isLvalue and toLvalue
+             */
+            auto result = e.copy();
+            result.type = t;
+            return result;
+        }
+        if (tsa && tsa.dim.equals(tb.isTypeSArray().dim))
+        {
+            /* Match if the dimensions are equal
+             * with the implicit conversion of e.e1:
+             *  cast(float[2]) [2.0, 1.0, 0.0][0..2];
+             */
+            Type t1b = e.e1.type.toBasetype();
+            if (t1b.ty == Tsarray)
+                t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger());
+            else if (t1b.ty == Tarray)
+                t1b = tb.nextOf().arrayOf();
+            else if (t1b.ty == Tpointer)
+                t1b = tb.nextOf().pointerTo();
+            else
+                assert(0);
+            if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
             {
-                /* Match if the dimensions are equal
-                 * with the implicit conversion of e.e1:
-                 *  cast(float[2]) [2.0, 1.0, 0.0][0..2];
-                 */
-                Type t1b = e.e1.type.toBasetype();
-                if (t1b.ty == Tsarray)
-                    t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger());
-                else if (t1b.ty == Tarray)
-                    t1b = tb.nextOf().arrayOf();
-                else if (t1b.ty == Tpointer)
-                    t1b = tb.nextOf().pointerTo();
-                else
-                    assert(0);
-                if (e.e1.implicitConvTo(t1b) > MATCH.nomatch)
-                {
-                    Expression e1x = e.e1.implicitCastTo(sc, t1b);
-                    assert(e1x.op != EXP.error);
-                    e = e.copy().isSliceExp();
-                    e.e1 = e1x;
-                    e.type = t;
-                    result = e;
-                    return;
-                }
+                Expression e1x = e.e1.implicitCastTo(sc, t1b);
+                assert(e1x.op != EXP.error);
+                e = e.copy().isSliceExp();
+                e.e1 = e1x;
+                e.type = t;
+                return e;
             }
-            auto ts = toAutoQualChars(tsa ? tsa : e.type, t);
-            e.error("cannot cast expression `%s` of type `%s` to `%s`",
-                e.toChars(), ts[0], ts[1]);
-            result = ErrorExp.get();
         }
+        auto ts = toAutoQualChars(tsa ? tsa : e.type, t);
+        e.error("cannot cast expression `%s` of type `%s` to `%s`",
+            e.toChars(), ts[0], ts[1]);
+        return ErrorExp.get();
     }
 
     // Casting to noreturn isn't an actual cast
@@ -2673,9 +2623,25 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         return Expression.combine(e, ini);
     }
 
-    scope CastTo v = new CastTo(sc, t);
-    e.accept(v);
-    return v.result;
+    switch (e.op)
+    {
+        default                   : return visit(e);
+        case EXP.error            : return visitError(e.isErrorExp());
+        case EXP.float64          : return visitReal(e.isRealExp());
+        case EXP.complex80        : return visitComplex(e.isComplexExp());
+        case EXP.structLiteral    : return visitStructLiteral(e.isStructLiteralExp());
+        case EXP.string_          : return visitString(e.isStringExp());
+        case EXP.address          : return visitAddr(e.isAddrExp());
+        case EXP.tuple            : return visitTuple(e.isTupleExp());
+        case EXP.arrayLiteral     : return visitArrayLiteral(e.isArrayLiteralExp());
+        case EXP.assocArrayLiteral: return visitAssocArrayLiteral(e.isAssocArrayLiteralExp());
+        case EXP.symbolOffset     : return visitSymOff(e.isSymOffExp());
+        case EXP.delegate_        : return visitDelegate(e.isDelegateExp());
+        case EXP.function_        : return visitFunc(e.isFuncExp());
+        case EXP.question         : return visitCond(e.isCondExp());
+        case EXP.comma            : return visitComma(e.isCommaExp());
+        case EXP.slice            : return visitSlice(e.isSliceExp());
+    }
 }
 
 /****************************************
@@ -3731,172 +3697,187 @@ extern (C++) bool arrayTypeCompatibleWithoutCasting(Type t1, Type t2)
  * This is used to determine if implicit narrowing conversions will
  * be allowed.
  */
+@trusted
 IntRange getIntRange(Expression e)
 {
-    extern (C++) final class IntRangeVisitor : Visitor
+    IntRange visit(Expression e)
     {
-        alias visit = Visitor.visit;
-
-    public:
-        IntRange range;
+        return IntRange.fromType(e.type);
+    }
 
-        override void visit(Expression e)
-        {
-            range = IntRange.fromType(e.type);
-        }
+    IntRange visitInteger(IntegerExp e)
+    {
+        return IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type);
+    }
 
-        override void visit(IntegerExp e)
-        {
-            range = IntRange(SignExtendedNumber(e.getInteger()))._cast(e.type);
-        }
+    IntRange visitCast(CastExp e)
+    {
+        return getIntRange(e.e1)._cast(e.type);
+    }
 
-        override void visit(CastExp e)
-        {
-            range = getIntRange(e.e1)._cast(e.type);
-        }
+    IntRange visitAdd(AddExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
+        return (ir1 + ir2)._cast(e.type);
+    }
 
-        override void visit(AddExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
-            range = (ir1 + ir2)._cast(e.type);
-        }
+    IntRange visitMin(MinExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
+        return (ir1 - ir2)._cast(e.type);
+    }
 
-        override void visit(MinExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
-            range = (ir1 - ir2)._cast(e.type);
-        }
+    IntRange visitDiv(DivExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
 
-        override void visit(DivExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
+        return (ir1 / ir2)._cast(e.type);
+    }
 
-            range = (ir1 / ir2)._cast(e.type);
-        }
+    IntRange visitMul(MulExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
 
-        override void visit(MulExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
+        return (ir1 * ir2)._cast(e.type);
+    }
 
-            range = (ir1 * ir2)._cast(e.type);
-        }
+    IntRange visitMod(ModExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
 
-        override void visit(ModExp e)
+        // Modding on 0 is invalid anyway.
+        if (!ir2.absNeg().imin.negative)
         {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
-
-            // Modding on 0 is invalid anyway.
-            if (!ir2.absNeg().imin.negative)
-            {
-                visit(cast(Expression)e);
-                return;
-            }
-            range = (ir1 % ir2)._cast(e.type);
+            return visit(e);
         }
+        return (ir1 % ir2)._cast(e.type);
+    }
 
-        override void visit(AndExp e)
-        {
-            IntRange result;
-            bool hasResult = false;
-            result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult);
+    IntRange visitAnd(AndExp e)
+    {
+        IntRange result;
+        bool hasResult = false;
+        result.unionOrAssign(getIntRange(e.e1) & getIntRange(e.e2), hasResult);
 
-            assert(hasResult);
-            range = result._cast(e.type);
-        }
+        assert(hasResult);
+        return result._cast(e.type);
+    }
 
-        override void visit(OrExp e)
-        {
-            IntRange result;
-            bool hasResult = false;
-            result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult);
+    IntRange visitOr(OrExp e)
+    {
+        IntRange result;
+        bool hasResult = false;
+        result.unionOrAssign(getIntRange(e.e1) | getIntRange(e.e2), hasResult);
 
-            assert(hasResult);
-            range = result._cast(e.type);
-        }
+        assert(hasResult);
+        return result._cast(e.type);
+    }
 
-        override void visit(XorExp e)
-        {
-            IntRange result;
-            bool hasResult = false;
-            result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult);
+    IntRange visitXor(XorExp e)
+    {
+        IntRange result;
+        bool hasResult = false;
+        result.unionOrAssign(getIntRange(e.e1) ^ getIntRange(e.e2), hasResult);
 
-            assert(hasResult);
-            range = result._cast(e.type);
-        }
+        assert(hasResult);
+        return result._cast(e.type);
+    }
 
-        override void visit(ShlExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
+    IntRange visitShl(ShlExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
 
-            range = (ir1 << ir2)._cast(e.type);
-        }
+        return (ir1 << ir2)._cast(e.type);
+    }
 
-        override void visit(ShrExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
+    IntRange visitShr(ShrExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
 
-            range = (ir1 >> ir2)._cast(e.type);
-        }
+        return (ir1 >> ir2)._cast(e.type);
+    }
 
-        override void visit(UshrExp e)
-        {
-            IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type);
-            IntRange ir2 = getIntRange(e.e2);
+    IntRange visitUshr(UshrExp e)
+    {
+        IntRange ir1 = getIntRange(e.e1).castUnsigned(e.e1.type);
+        IntRange ir2 = getIntRange(e.e2);
 
-            range = (ir1 >>> ir2)._cast(e.type);
-        }
+        return (ir1 >>> ir2)._cast(e.type);
+    }
 
-        override void visit(AssignExp e)
-        {
-            range = getIntRange(e.e2)._cast(e.type);
-        }
+    IntRange visitAssign(AssignExp e)
+    {
+        return getIntRange(e.e2)._cast(e.type);
+    }
 
-        override void visit(CondExp e)
-        {
-            // No need to check e.econd; assume caller has called optimize()
-            IntRange ir1 = getIntRange(e.e1);
-            IntRange ir2 = getIntRange(e.e2);
-            range = ir1.unionWith(ir2)._cast(e.type);
-        }
+    IntRange visitCond(CondExp e)
+    {
+        // No need to check e.econd; assume caller has called optimize()
+        IntRange ir1 = getIntRange(e.e1);
+        IntRange ir2 = getIntRange(e.e2);
+        return ir1.unionWith(ir2)._cast(e.type);
+    }
 
-        override void visit(VarExp e)
-        {
-            Expression ie;
-            VarDeclaration vd = e.var.isVarDeclaration();
-            if (vd && vd.range)
-                range = vd.range._cast(e.type);
-            else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
-                ie.accept(this);
-            else
-                visit(cast(Expression)e);
-        }
+    IntRange visitVar(VarExp e)
+    {
+        Expression ie;
+        VarDeclaration vd = e.var.isVarDeclaration();
+        if (vd && vd.range)
+            return vd.range._cast(e.type);
+        else if (vd && vd._init && !vd.type.isMutable() && (ie = vd.getConstInitializer()) !is null)
+            return getIntRange(ie);
+        else
+            return visit(e);
+    }
 
-        override void visit(CommaExp e)
-        {
-            e.e2.accept(this);
-        }
+    IntRange visitComma(CommaExp e)
+    {
+        return getIntRange(e.e2);
+    }
 
-        override void visit(ComExp e)
-        {
-            IntRange ir = getIntRange(e.e1);
-            range = IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type);
-        }
+    IntRange visitCom(ComExp e)
+    {
+        IntRange ir = getIntRange(e.e1);
+        return IntRange(SignExtendedNumber(~ir.imax.value, !ir.imax.negative), SignExtendedNumber(~ir.imin.value, !ir.imin.negative))._cast(e.type);
+    }
 
-        override void visit(NegExp e)
-        {
-            IntRange ir = getIntRange(e.e1);
-            range = (-ir)._cast(e.type);
-        }
+    IntRange visitNeg(NegExp e)
+    {
+        IntRange ir = getIntRange(e.e1);
+        return (-ir)._cast(e.type);
     }
 
-    scope IntRangeVisitor v = new IntRangeVisitor();
-    e.accept(v);
-    return v.range;
+    switch (e.op)
+    {
+        default                     : return visit(e);
+        case EXP.int64              : return visitInteger(e.isIntegerExp());
+        case EXP.cast_              : return visitCast(e.isCastExp());
+        case EXP.add                : return visitAdd(e.isAddExp());
+        case EXP.min                : return visitMin(e.isMinExp());
+        case EXP.div                : return visitDiv(e.isDivExp());
+        case EXP.mul                : return visitMul(e.isMulExp());
+        case EXP.mod                : return visitMod(e.isModExp());
+        case EXP.and                : return visitAnd(e.isAndExp());
+        case EXP.or                 : return visitOr(e.isOrExp());
+        case EXP.xor                : return visitXor(e.isXorExp());
+        case EXP.leftShift          : return visitShl(e.isShlExp());
+        case EXP.rightShift         : return visitShr(e.isShrExp());
+        case EXP.unsignedRightShift : return visitUshr(e.isUshrExp());
+        case EXP.blit               : return visitAssign(e.isBlitExp());
+        case EXP.construct          : return visitAssign(e.isConstructExp());
+        case EXP.assign             : return visitAssign(e.isAssignExp());
+        case EXP.question           : return visitCond(e.isCondExp());
+        case EXP.variable           : return visitVar(e.isVarExp());
+        case EXP.comma              : return visitComma(e.isCommaExp());
+        case EXP.tilde              : return visitCom(e.isComExp());
+        case EXP.negate             : return visitNeg(e.isNegExp());
+    }
 }
+
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 494b60f0493..cdf9355e94c 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -1064,9 +1064,8 @@ extern (C++) class VarDeclaration : Declaration
     // Both these mean the var is not rebindable once assigned,
     // and the destructor gets run when it goes out of scope
     bool onstack;                   // it is a class that was allocated on the stack
-    bool mynew;                     // it is a class new'd with custom operator new
 
-    byte canassign;                  // it can be assigned to
+    byte canassign;                 // it can be assigned to
     bool overlapped;                // if it is a field and has overlapping
     bool overlapUnsafe;             // if it is an overlapping field and the overlaps are unsafe
     bool doNotInferScope;           // do not infer 'scope' for this variable
@@ -1452,7 +1451,7 @@ extern (C++) class VarDeclaration : Declaration
                 //if (cd.isInterfaceDeclaration())
                 //    error("interface `%s` cannot be scope", cd.toChars());
 
-                if (mynew || onstack) // if any destructors
+                if (onstack) // if any destructors
                 {
                     // delete'ing C++ classes crashes (and delete is deprecated anyway)
                     if (cd.classKind == ClassKind.cpp)
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 353d36ce43f..e30acb41b2a 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -248,7 +248,6 @@ public:
     bool isowner;               // this is an Owner, despite it being `scope`
     bool setInCtorOnly;         // field can only be set in a constructor, as it is const or immutable
     bool onstack;               // it is a class that was allocated on the stack
-    bool mynew;                 // it is a class new'd with custom operator new
     char canassign;             // it can be assigned to
     bool overlapped;            // if it is a field and has overlapping
     bool overlapUnsafe;         // if it is an overlapping field and the overlaps are unsafe
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index b55b98160ff..6c3454daf10 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -3820,6 +3820,21 @@ public:
 
             payload = &(*sle.elements)[fieldi];
             oldval = *payload;
+            if (auto ival = newval.isIntegerExp())
+            {
+                if (auto bf = v.isBitFieldDeclaration())
+                {
+                    sinteger_t value = ival.toInteger();
+                    if (bf.type.isunsigned())
+                        value &= (1L << bf.fieldWidth) - 1; // zero extra bits
+                    else
+                    {   // sign extend extra bits
+                        value = value << (64 - bf.fieldWidth);
+                        value = value >> (64 - bf.fieldWidth);
+                    }
+                    ival.setInteger(value);
+                }
+            }
         }
         else if (auto ie = e1.isIndexExp())
         {
@@ -4851,47 +4866,6 @@ public:
                 result = interpret(ce, istate);
                 return;
             }
-            else if (fd.ident == Id._d_delstruct)
-            {
-                // Only interpret the dtor and the argument.
-                assert(e.arguments.dim == 1);
-
-                Type tb = (*e.arguments)[0].type.toBasetype();
-                auto ts = tb.nextOf().baseElemOf().isTypeStruct();
-                if (ts)
-                {
-                    result = interpretRegion((*e.arguments)[0], istate);
-                    if (exceptionOrCant(result))
-                        return;
-
-                    if (result.op == EXP.null_)
-                    {
-                        result = CTFEExp.voidexp;
-                        return;
-                    }
-
-                    if (result.op != EXP.address ||
-                        (cast(AddrExp)result).e1.op != EXP.structLiteral)
-                    {
-                        e.error("`delete` on invalid struct pointer `%s`", result.toChars());
-                        result = CTFEExp.cantexp;
-                        return;
-                    }
-
-                    auto sd = ts.sym;
-                    if (sd.dtor)
-                    {
-                        auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
-                        result = interpretFunction(pue, sd.dtor, istate, null, sle);
-                        if (exceptionOrCant(result))
-                            return;
-
-                        result = CTFEExp.voidexp;
-                    }
-                }
-
-                return;
-            }
         }
         else if (auto soe = ecall.isSymOffExp())
         {
@@ -5835,56 +5809,6 @@ public:
 
             break;
 
-        case Tpointer:
-            tb = (cast(TypePointer)tb).next.toBasetype();
-            if (tb.ty == Tstruct)
-            {
-                if (result.op != EXP.address ||
-                    (cast(AddrExp)result).e1.op != EXP.structLiteral)
-                {
-                    e.error("`delete` on invalid struct pointer `%s`", result.toChars());
-                    result = CTFEExp.cantexp;
-                    return;
-                }
-
-                auto sd = (cast(TypeStruct)tb).sym;
-                auto sle = cast(StructLiteralExp)(cast(AddrExp)result).e1;
-
-                if (sd.dtor)
-                {
-                    result = interpretFunction(pue, sd.dtor, istate, null, sle);
-                    if (exceptionOrCant(result))
-                        return;
-                }
-            }
-            break;
-
-        case Tarray:
-            auto tv = tb.nextOf().baseElemOf();
-            if (tv.ty == Tstruct)
-            {
-                if (result.op != EXP.arrayLiteral)
-                {
-                    e.error("`delete` on invalid struct array `%s`", result.toChars());
-                    result = CTFEExp.cantexp;
-                    return;
-                }
-
-                auto sd = (cast(TypeStruct)tv).sym;
-
-                if (sd.dtor)
-                {
-                    auto ale = cast(ArrayLiteralExp)result;
-                    foreach (el; *ale.elements)
-                    {
-                        result = interpretFunction(pue, sd.dtor, istate, null, el);
-                        if (exceptionOrCant(result))
-                            return;
-                    }
-                }
-            }
-            break;
-
         default:
             assert(0);
         }
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 78d17b2238c..ad305f966d4 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -726,7 +726,8 @@ public:
     extern (D) static const(char)[] externallyMangledIdentifier(Declaration d)
     {
         const par = d.toParent(); //toParent() skips over mixin templates
-        if (!par || par.isModule() || d.linkage == LINK.cpp)
+        if (!par || par.isModule() || d.linkage == LINK.cpp ||
+            (d.linkage == LINK.c && d.isCsymbol() && d.isFuncDeclaration()))
         {
             if (d.linkage != LINK.d && d.localNum)
                 d.error("the same declaration cannot be in multiple scopes with non-D linkage");
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 46e89d0f806..84e29fe1023 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -524,17 +524,8 @@ extern (C++) final class Module : Package
             buf.printf("%s\t(%s)", ident.toChars(), m.srcfile.toChars());
             message("import    %s", buf.peekChars());
         }
-        m = m.parse();
+        if((m = m.parse()) is null) return null;
 
-        // Call onImport here because if the module is going to be compiled then we
-        // need to determine it early because it affects semantic analysis. This is
-        // being done after parsing the module so the full module name can be taken
-        // from whatever was declared in the file.
-        if (!m.isRoot() && Compiler.onImport(m))
-        {
-            m.importedFrom = m;
-            assert(m.isRoot());
-        }
         return m;
     }
 
@@ -727,7 +718,7 @@ extern (C++) final class Module : Package
             if (buf.length & 3)
             {
                 error("odd length of UTF-32 char source %llu", cast(ulong) buf.length);
-                fatal();
+                return null;
             }
 
             const (uint)[] eBuf = cast(const(uint)[])buf;
@@ -743,7 +734,7 @@ extern (C++) final class Module : Package
                     if (u > 0x10FFFF)
                     {
                         error("UTF-32 value %08x greater than 0x10FFFF", u);
-                        fatal();
+                        return null;
                     }
                     dbuf.writeUTF8(u);
                 }
@@ -773,7 +764,7 @@ extern (C++) final class Module : Package
             if (buf.length & 1)
             {
                 error("odd length of UTF-16 char source %llu", cast(ulong) buf.length);
-                fatal();
+                return null;
             }
 
             const (ushort)[] eBuf = cast(const(ushort)[])buf;
@@ -793,13 +784,13 @@ extern (C++) final class Module : Package
                         if (i >= eBuf.length)
                         {
                             error("surrogate UTF-16 high value %04x at end of file", u);
-                            fatal();
+                            return null;
                         }
                         const u2 = readNext(&eBuf[i]);
                         if (u2 < 0xDC00 || 0xE000 <= u2)
                         {
                             error("surrogate UTF-16 low value %04x out of range", u2);
-                            fatal();
+                            return null;
                         }
                         u = (u - 0xD7C0) << 10;
                         u |= (u2 - 0xDC00);
@@ -807,12 +798,12 @@ extern (C++) final class Module : Package
                     else if (u >= 0xDC00 && u <= 0xDFFF)
                     {
                         error("unpaired surrogate UTF-16 value %04x", u);
-                        fatal();
+                        return null;
                     }
                     else if (u == 0xFFFE || u == 0xFFFF)
                     {
                         error("illegal UTF-16 value %04x", u);
-                        fatal();
+                        return null;
                     }
                     dbuf.writeUTF8(u);
                 }
@@ -899,7 +890,7 @@ extern (C++) final class Module : Package
                     if (buf[0] >= 0x80)
                     {
                         error("source file must start with BOM or ASCII character, not \\x%02X", buf[0]);
-                        fatal();
+                        return null;
                     }
                 }
             }
@@ -929,6 +920,8 @@ extern (C++) final class Module : Package
                       ? UTF32ToUTF8!(Endian.little)(buf)
                       : UTF32ToUTF8!(Endian.big)(buf);
             }
+            // an error happened on UTF conversion
+            if (buf is null) return null;
         }
 
         /* If it starts with the string "Ddoc", then it's a documentation
@@ -962,6 +955,16 @@ extern (C++) final class Module : Package
             isHdrFile = true;
         }
 
+        /// Promote `this` to a root module if requested via `-i`
+        void checkCompiledImport()
+        {
+            if (!this.isRoot() && Compiler.onImport(this))
+                this.importedFrom = this;
+        }
+
+        DsymbolTable dst;
+        Package ppack = null;
+
         /* If it has the extension ".c", it is a "C" file.
          * If it has the extension ".i", it is a preprocessed "C" file.
          */
@@ -971,33 +974,41 @@ extern (C++) final class Module : Package
 
             scope p = new CParser!AST(this, buf, cast(bool) docfile, target.c);
             p.nextToken();
+            checkCompiledImport();
             members = p.parseModule();
-            md = p.md;
+            assert(!p.md); // C doesn't have module declarations
             numlines = p.scanloc.linnum;
         }
         else
         {
             scope p = new Parser!AST(this, buf, cast(bool) docfile);
             p.nextToken();
-            members = p.parseModule();
+            p.parseModuleDeclaration();
             md = p.md;
+
+            if (md)
+            {
+                /* A ModuleDeclaration, md, was provided.
+                * The ModuleDeclaration sets the packages this module appears in, and
+                * the name of this module.
+                */
+                this.ident = md.id;
+                dst = Package.resolve(md.packages, &this.parent, &ppack);
+            }
+
+            // Done after parsing the module header because `module x.y.z` may override the file name
+            checkCompiledImport();
+
+            members = p.parseModuleContent();
             numlines = p.scanloc.linnum;
         }
         srcBuffer.destroy();
         srcBuffer = null;
         /* The symbol table into which the module is to be inserted.
          */
-        DsymbolTable dst;
+
         if (md)
         {
-            /* A ModuleDeclaration, md, was provided.
-             * The ModuleDeclaration sets the packages this module appears in, and
-             * the name of this module.
-             */
-            this.ident = md.id;
-            Package ppack = null;
-            dst = Package.resolve(md.packages, &this.parent, &ppack);
-
             // Mark the package path as accessible from the current module
             // https://issues.dlang.org/show_bug.cgi?id=21661
             // Code taken from Import.addPackageAccess()
@@ -1201,10 +1212,13 @@ extern (C++) final class Module : Package
             if (StringExp se = msg ? msg.toStringExp() : null)
             {
                 const slice = se.peekString();
-                deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr);
+                if (slice.length)
+                {
+                    deprecation(loc, "is deprecated - %.*s", cast(int)slice.length, slice.ptr);
+                    return;
+                }
             }
-            else
-                deprecation(loc, "is deprecated");
+            deprecation(loc, "is deprecated");
         }
     }
 
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 2a3777b3df0..936d19af623 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -692,7 +692,7 @@ struct Scope
     }
 
     /********************************************
-     * Search enclosing scopes for ClassDeclaration.
+     * Search enclosing scopes for ClassDeclaration or StructDeclaration.
      */
     extern (C++) AggregateDeclaration getStructClassScope()
     {
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 7823351b579..200cb7639c7 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -51,6 +51,7 @@ import dmd.root.rootobject;
 import dmd.root.speller;
 import dmd.root.string;
 import dmd.statement;
+import dmd.staticassert;
 import dmd.tokens;
 import dmd.visitor;
 
@@ -1305,9 +1306,10 @@ extern (C++) class Dsymbol : ASTNode
     inout(AttribDeclaration)           isAttribDeclaration()           inout { return null; }
     inout(AnonDeclaration)             isAnonDeclaration()             inout { return null; }
     inout(CPPNamespaceDeclaration)     isCPPNamespaceDeclaration()     inout { return null; }
-    inout(VisibilityDeclaration)             isVisibilityDeclaration()             inout { return null; }
+    inout(VisibilityDeclaration)       isVisibilityDeclaration()       inout { return null; }
     inout(OverloadSet)                 isOverloadSet()                 inout { return null; }
     inout(CompileDeclaration)          isCompileDeclaration()          inout { return null; }
+    inout(StaticAssert)                isStaticAssert()                inout { return null; }
 }
 
 /***********************************************************
@@ -2500,12 +2502,15 @@ Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
         if (fd.fbody)                   // fd is the definition
         {
             sds.symtab.update(fd);      // replace fd2 in symbol table with fd
+            fd.overnext = fd2;
             return fd;
         }
 
-        /* BUG: just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
-         * FuncDeclaration::semantic2() can detect this, but it relies overnext being set.
+        /* Just like with VarDeclaration, the types should match, which needs semantic() to be run on it.
+         * FuncDeclaration::semantic() detects this, but it relies on .overnext being set.
          */
+        fd2.overloadInsert(fd);
+
         return fd2;
     }
 
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index a6bd999ac0b..03d5c3d2e98 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -71,6 +71,7 @@ class Expression;
 class ExpressionDsymbol;
 class AliasAssign;
 class OverloadSet;
+class StaticAssert;
 struct AA;
 #ifdef IN_GCC
 typedef union tree_node Symbol;
@@ -307,6 +308,7 @@ public:
     virtual VisibilityDeclaration *isVisibilityDeclaration() { return NULL; }
     virtual OverloadSet *isOverloadSet() { return NULL; }
     virtual CompileDeclaration *isCompileDeclaration() { return NULL; }
+    virtual StaticAssert *isStaticAssert() { return NULL; }
     void accept(Visitor *v) { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 1cb167ae18c..8ad0178f814 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -847,11 +847,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 dsym.error("globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`");
             }
 
-            // @@@DEPRECATED@@@  https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+            // @@@DEPRECATED_2.097@@@  https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
             // Deprecated in 2.087
             // Remove this when the feature is removed from the language
-            if (0 &&          // deprecation disabled for now to accommodate existing extensive use
-               !(dsym.storage_class & STC.scope_))
+            if (!(dsym.storage_class & STC.scope_))
             {
                 if (!(dsym.storage_class & STC.parameter) && dsym.ident != Id.withSym)
                     dsym.error("reference to `scope class` must be `scope`");
@@ -1040,15 +1039,8 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                             // See if initializer is a NewExp that can be allocated on the stack
                             if (dsym.type.toBasetype().ty == Tclass)
                             {
-                                if (ne.newargs && ne.newargs.dim > 1)
-                                {
-                                    dsym.mynew = true;
-                                }
-                                else
-                                {
-                                    ne.onstack = 1;
-                                    dsym.onstack = true;
-                                }
+                                ne.onstack = 1;
+                                dsym.onstack = true;
                             }
                         }
                         else if (auto fe = ex.isFuncExp())
@@ -2438,8 +2430,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             Type tprev = eprev.type.toHeadMutable().equals(em.ed.type.toHeadMutable())
                 ? em.ed.memtype
                 : eprev.type;
-
-            Expression emax = tprev.getProperty(sc, em.ed.loc, Id.max, 0);
+            /*
+                https://issues.dlang.org/show_bug.cgi?id=20777
+                Previously this used getProperty, which doesn't consider anything user defined,
+                this construct does do that and thus fixes the bug.
+            */
+            Expression emax = DotIdExp.create(em.ed.loc, new TypeExp(em.ed.loc, tprev), Id.max);
             emax = emax.expressionSemantic(sc);
             emax = emax.ctfeInterpret();
 
@@ -2979,10 +2975,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     void funcDeclarationSemantic(FuncDeclaration funcdecl)
     {
-        TypeFunction f;
-        AggregateDeclaration ad;
-        InterfaceDeclaration id;
-
         version (none)
         {
             printf("FuncDeclaration::semantic(sc = %p, this = %p, '%s', linkage = %d)\n", sc, funcdecl, funcdecl.toPrettyChars(), sc.linkage);
@@ -3023,7 +3015,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         funcdecl.foverrides.setDim(0); // reset in case semantic() is being retried for this function
 
         funcdecl.storage_class |= sc.stc & ~STC.ref_;
-        ad = funcdecl.isThis();
+        AggregateDeclaration ad = funcdecl.isThis();
         // Don't nest structs b/c of generated methods which should not access the outer scopes.
         // https://issues.dlang.org/show_bug.cgi?id=16627
         if (ad && !funcdecl.generated)
@@ -3042,21 +3034,22 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if (sc.flags & SCOPE.compile)
             funcdecl.flags |= FUNCFLAG.compileTimeOnly; // don't emit code for this function
 
-        FuncLiteralDeclaration fld = funcdecl.isFuncLiteralDeclaration();
-        if (fld && fld.treq)
+        funcdecl.linkage = sc.linkage;
+        if (auto fld = funcdecl.isFuncLiteralDeclaration())
         {
-            Type treq = fld.treq;
-            assert(treq.nextOf().ty == Tfunction);
-            if (treq.ty == Tdelegate)
-                fld.tok = TOK.delegate_;
-            else if (treq.isPtrToFunction())
-                fld.tok = TOK.function_;
-            else
-                assert(0);
-            funcdecl.linkage = treq.nextOf().toTypeFunction().linkage;
+            if (fld.treq)
+            {
+                Type treq = fld.treq;
+                assert(treq.nextOf().ty == Tfunction);
+                if (treq.ty == Tdelegate)
+                    fld.tok = TOK.delegate_;
+                else if (treq.isPtrToFunction())
+                    fld.tok = TOK.function_;
+                else
+                    assert(0);
+                funcdecl.linkage = treq.nextOf().toTypeFunction().linkage;
+            }
         }
-        else
-            funcdecl.linkage = sc.linkage;
 
         // evaluate pragma(inline)
         if (auto pragmadecl = sc.inlining)
@@ -3078,16 +3071,24 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (!funcdecl.originalType)
             funcdecl.originalType = funcdecl.type.syntaxCopy();
-        if (funcdecl.type.ty != Tfunction)
+
+        static TypeFunction getFunctionType(FuncDeclaration fd)
         {
-            if (funcdecl.type.ty != Terror)
+            if (auto tf = fd.type.isTypeFunction())
+                return tf;
+
+            if (!fd.type.isTypeError())
             {
-                funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
-                funcdecl.type = Type.terror;
+                fd.error("`%s` must be a function instead of `%s`", fd.toChars(), fd.type.toChars());
+                fd.type = Type.terror;
             }
-            funcdecl.errors = true;
-            return;
+            fd.errors = true;
+            return null;
         }
+
+        if (!getFunctionType(funcdecl))
+            return;
+
         if (!funcdecl.type.deco)
         {
             sc = sc.push();
@@ -3147,14 +3148,17 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 sc.stc |= STC.property;
             if (tf.purity == PURE.fwdref)
                 sc.stc |= STC.pure_;
+
             if (tf.trust != TRUST.default_)
+            {
                 sc.stc &= ~STC.safeGroup;
-            if (tf.trust == TRUST.safe)
-                sc.stc |= STC.safe;
-            if (tf.trust == TRUST.system)
-                sc.stc |= STC.system;
-            if (tf.trust == TRUST.trusted)
-                sc.stc |= STC.trusted;
+                if (tf.trust == TRUST.safe)
+                    sc.stc |= STC.safe;
+                else if (tf.trust == TRUST.system)
+                    sc.stc |= STC.system;
+                else if (tf.trust == TRUST.trusted)
+                    sc.stc |= STC.trusted;
+            }
 
             if (funcdecl.isCtorDeclaration())
             {
@@ -3206,37 +3210,46 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             funcdecl.type = funcdecl.type.typeSemantic(funcdecl.loc, sc);
             sc = sc.pop();
         }
-        if (funcdecl.type.ty != Tfunction)
-        {
-            if (funcdecl.type.ty != Terror)
-            {
-                funcdecl.error("`%s` must be a function instead of `%s`", funcdecl.toChars(), funcdecl.type.toChars());
-                funcdecl.type = Type.terror;
-            }
-            funcdecl.errors = true;
-            return;
-        }
-        else
+
+        auto f = getFunctionType(funcdecl);
+        if (!f)
+            return;     // funcdecl's type is not a function
+
         {
             // Merge back function attributes into 'originalType'.
             // It's used for mangling, ddoc, and json output.
             TypeFunction tfo = funcdecl.originalType.toTypeFunction();
-            TypeFunction tfx = funcdecl.type.toTypeFunction();
-            tfo.mod = tfx.mod;
-            tfo.isScopeQual = tfx.isScopeQual;
-            tfo.isreturninferred = tfx.isreturninferred;
-            tfo.isscopeinferred = tfx.isscopeinferred;
-            tfo.isref = tfx.isref;
-            tfo.isnothrow = tfx.isnothrow;
-            tfo.isnogc = tfx.isnogc;
-            tfo.isproperty = tfx.isproperty;
-            tfo.purity = tfx.purity;
-            tfo.trust = tfx.trust;
+            tfo.mod = f.mod;
+            tfo.isScopeQual = f.isScopeQual;
+            tfo.isreturninferred = f.isreturninferred;
+            tfo.isscopeinferred = f.isscopeinferred;
+            tfo.isref = f.isref;
+            tfo.isnothrow = f.isnothrow;
+            tfo.isnogc = f.isnogc;
+            tfo.isproperty = f.isproperty;
+            tfo.purity = f.purity;
+            tfo.trust = f.trust;
 
             funcdecl.storage_class &= ~(STC.TYPECTOR | STC.FUNCATTR);
         }
 
-        f = cast(TypeFunction)funcdecl.type;
+        if (funcdecl.overnext && funcdecl.isCsymbol())
+        {
+            /* C does not allow function overloading, but it does allow
+             * redeclarations of the same function. If .overnext points
+             * to a redeclaration, ok. Error if it is an overload.
+             */
+            auto fnext = funcdecl.overnext.isFuncDeclaration();
+            funcDeclarationSemantic(fnext);
+            auto fn = fnext.type.isTypeFunction();
+            if (!fn || !cFuncEquivalence(f, fn))
+            {
+                funcdecl.error("redeclaration with different type");
+                //printf("t1: %s\n", f.toChars());
+                //printf("t2: %s\n", fn.toChars());
+            }
+            funcdecl.overnext = null;   // don't overload the redeclarations
+        }
 
         if ((funcdecl.storage_class & STC.auto_) && !f.isref && !funcdecl.inferRetType)
             funcdecl.error("storage class `auto` has no effect if return type is not inferred");
@@ -3355,8 +3368,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
-        id = parent.isInterfaceDeclaration();
-        if (id)
+        if (auto id = parent.isInterfaceDeclaration())
         {
             funcdecl.storage_class |= STC.abstract_;
             if (funcdecl.isCtorDeclaration() || funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration() || funcdecl.isNewDeclaration() || funcdecl.isDelete())
@@ -3364,6 +3376,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             if (funcdecl.fbody && funcdecl.isVirtual())
                 funcdecl.error("function body only allowed in `final` functions in interface `%s`", id.toChars());
         }
+
         if (UnionDeclaration ud = parent.isUnionDeclaration())
         {
             if (funcdecl.isPostBlitDeclaration() || funcdecl.isDtorDeclaration() || funcdecl.isInvariantDeclaration())
@@ -3449,8 +3462,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     Dsymbol s = cd.baseClass.search(funcdecl.loc, funcdecl.ident);
                     if (s)
                     {
-                        FuncDeclaration f2 = s.isFuncDeclaration();
-                        if (f2)
+                        if (auto f2 = s.isFuncDeclaration())
                         {
                             f2 = f2.overloadExactMatch(funcdecl.type);
                             if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
@@ -3802,11 +3814,9 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             {
                 if (b.sym)
                 {
-                    Dsymbol s = search_function(b.sym, funcdecl.ident);
-                    if (s)
+                    if (auto s = search_function(b.sym, funcdecl.ident))
                     {
-                        FuncDeclaration f2 = s.isFuncDeclaration();
-                        if (f2)
+                        if (auto f2 = s.isFuncDeclaration())
                         {
                             f2 = f2.overloadExactMatch(funcdecl.type);
                             if (f2 && f2.isFinalFunc() && f2.visible().kind != Visibility.Kind.private_)
@@ -3853,8 +3863,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
          */
         if (funcdecl.isVirtual())
         {
-            TemplateInstance ti = parent.isTemplateInstance();
-            if (ti)
+            if (auto ti = parent.isTemplateInstance())
             {
                 // Take care of nested templates
                 while (1)
@@ -4426,7 +4435,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return;
         int errors = global.errors;
 
-        //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", this, sd.toPrettyChars(), sd.sizeok);
+        //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
         Scope* scx = null;
         if (sd._scope)
         {
@@ -5275,7 +5284,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
         //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
 
-        // @@@DEPRECATED@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+        // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
         // Deprecated in 2.087
         // Make an error in 2.091
         // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
@@ -5582,12 +5591,12 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
         assert(idec.type.ty != Tclass || (cast(TypeClass)idec.type).sym == idec);
 
-        // @@@DEPRECATED@@@https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+        // @@@DEPRECATED_2.120@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
         // Deprecated in 2.087
-        // Remove in 2.091
+        // Made an error in 2.100, but removal depends on `scope class` being removed too
         // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
         if (idec.storage_class & STC.scope_)
-            deprecation(idec.loc, "`scope` as a type constraint is deprecated.  Use `scope` at the usage site.");
+            error(idec.loc, "`scope` as a type constraint is obsolete.  Use `scope` at the usage site.");
     }
 }
 
@@ -5879,13 +5888,16 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, Expressions*
             scope v = new InstMemberWalker(tempinst.inst);
             tempinst.inst.accept(v);
 
-            if (tempinst.minst) // if inst was not speculative
+            if (!global.params.allInst &&
+                tempinst.minst) // if inst was not speculative...
             {
-                /* Add 'inst' once again to the root module members[], then the
-                 * instance members will get codegen chances.
-                 */
+                assert(!tempinst.minst.isRoot()); // ... it was previously appended to a non-root module
+                // Append again to the root module members[], so that the instance will
+                // get codegen chances (depending on `tempinst.inst.needsCodegen()`).
                 tempinst.inst.appendToModuleMember();
             }
+
+            assert(tempinst.inst.memberOf && tempinst.inst.memberOf.isRoot(), "no codegen chances");
         }
 
         // modules imported by an existing instance should be added to the module
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 9fe8472b11e..457c5d12892 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -5125,15 +5125,6 @@ private bool reliesOnTemplateParameters(Expression e, TemplateParameter[] tparam
             //printf("NewExp.reliesOnTemplateParameters('%s')\n", e.toChars());
             if (e.thisexp)
                 e.thisexp.accept(this);
-            if (!result && e.newargs)
-            {
-                foreach (ea; *e.newargs)
-                {
-                    ea.accept(this);
-                    if (result)
-                        return;
-                }
-            }
             result = e.newtype.reliesOnTemplateParameters(tparams);
             if (!result && e.arguments)
             {
@@ -7351,12 +7342,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         //    toPrettyChars(),
         //    enclosing ? enclosing.toPrettyChars() : null,
         //    mi ? mi.toPrettyChars() : null);
-        if (!mi || mi.isRoot())
+        if (global.params.allInst || !mi || mi.isRoot())
         {
             /* If the instantiated module is speculative or root, insert to the
              * member of a root module. Then:
              *  - semantic3 pass will get called on the instance members.
-             *  - codegen pass will get a selection chance to do/skip it.
+             *  - codegen pass will get a selection chance to do/skip it (needsCodegen()).
              */
             static Dsymbol getStrictEnclosing(TemplateInstance ti)
             {
@@ -7374,8 +7365,18 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             // where tempdecl is declared.
             mi = (enc ? enc : tempdecl).getModule();
             if (!mi.isRoot())
-                mi = mi.importedFrom;
-            assert(mi.isRoot());
+            {
+                if (mi.importedFrom)
+                {
+                    mi = mi.importedFrom;
+                    assert(mi.isRoot());
+                }
+                else
+                {
+                    // This can happen when using the frontend as a library.
+                    // Append it to the non-root module.
+                }
+            }
         }
         else
         {
@@ -7383,24 +7384,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
              * non-root module. Then:
              *  - semantic3 pass won't be called on the instance.
              *  - codegen pass won't reach to the instance.
+             * Unless it is re-appended to a root module later (with changed minst).
              */
         }
         //printf("\t-. mi = %s\n", mi.toPrettyChars());
 
-        if (memberOf is mi)     // already a member
-        {
-            debug               // make sure it really is a member
-            {
-                auto a = mi.members;
-                for (size_t i = 0; 1; ++i)
-                {
-                    assert(i != a.dim);
-                    if (this == (*a)[i])
-                        break;
-                }
-            }
-            return null;
-        }
+        assert(!memberOf || (!memberOf.isRoot() && mi.isRoot()), "can only re-append from non-root to root module");
 
         Dsymbols* a = mi.members;
         a.push(this);
@@ -7801,15 +7790,22 @@ struct TemplateInstanceBox
     {
         bool res = void;
         if (ti.inst && s.ti.inst)
+        {
             /* This clause is only used when an instance with errors
              * is replaced with a correct instance.
              */
             res = ti is s.ti;
+        }
         else
+        {
             /* Used when a proposed instance is used to see if there's
              * an existing instance.
              */
-            res = (cast()s.ti).equalsx(cast()ti);
+            static if (__VERSION__ >= 2099)
+                res = (cast()ti).equalsx(cast()s.ti);
+            else // https://issues.dlang.org/show_bug.cgi?id=22717
+                res = (cast()s.ti).equalsx(cast()ti);
+        }
 
         debug (FindExistingInstance) ++(res ? nHits : nCollisions);
         return res;
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 5871ada466d..a34e2ccae28 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -2545,29 +2545,9 @@ public:
             buf.writeByte('U');
         buf.writeByte('"');
 
-        for (size_t i = 0; i < e.len; i++)
+        foreach (i; 0 .. e.len)
         {
-            uint c = e.charAt(i);
-            switch (c)
-            {
-                case '"':
-                case '\\':
-                    buf.writeByte('\\');
-                    goto default;
-                default:
-                    if (c <= 0xFF)
-                    {
-                        if (c >= 0x20 && c < 0x80)
-                            buf.writeByte(c);
-                        else
-                            buf.printf("\\x%02x", c);
-                    }
-                    else if (c <= 0xFFFF)
-                        buf.printf("\\u%04x", c);
-                    else
-                        buf.printf("\\U%08x", c);
-                    break;
-            }
+            writeCharLiteral(*buf, e.getCodeUnit(i));
         }
         buf.writeByte('"');
     }
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index d2a90609c16..35c1f76e600 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -380,7 +380,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
 
         notMaybeScope(v);
 
-        if (!v.isReference() && p == sc.func)
+        if (p == sc.func)
         {
             if (psr == ScopeRef.Scope ||
                 psr == ScopeRef.RefScope ||
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 4258e9ba49e..b3aa0b268b4 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -1742,11 +1742,21 @@ extern (C++) abstract class Expression : ASTNode
         inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
         inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
         inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
-    }
 
-    inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
-    {
-        return null;
+        inout(UnaExp) isUnaExp() pure inout nothrow @nogc
+        {
+            return exptab[op] & EXPFLAGS.unary ? cast(typeof(return))this : null;
+        }
+
+        inout(BinExp) isBinExp() pure inout nothrow @nogc
+        {
+            return exptab[op] & EXPFLAGS.binary ? cast(typeof(return))this : null;
+        }
+
+        inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
+        {
+            return exptab[op] & EXPFLAGS.binaryAssign ? cast(typeof(return))this : null;
+        }
     }
 
     override void accept(Visitor v)
@@ -2716,29 +2726,6 @@ extern (C++) final class StringExp : Expression
         return ErrorExp.get();
     }
 
-    uint charAt(uinteger_t i) const
-    {
-        uint value;
-        switch (sz)
-        {
-        case 1:
-            value = (cast(char*)string)[cast(size_t)i];
-            break;
-
-        case 2:
-            value = (cast(ushort*)string)[cast(size_t)i];
-            break;
-
-        case 4:
-            value = (cast(uint*)string)[cast(size_t)i];
-            break;
-
-        default:
-            assert(0);
-        }
-        return value;
-    }
-
     /********************************
      * Convert string contents to a 0 terminated string,
      * allocated by mem.xmalloc().
@@ -3516,12 +3503,11 @@ extern (C++) final class TemplateExp : Expression
 }
 
 /***********************************************************
- * thisexp.new(newargs) newtype(arguments)
+ * newtype(arguments)
  */
 extern (C++) final class NewExp : Expression
 {
     Expression thisexp;         // if !=null, 'this' for class being allocated
-    Expressions* newargs;       // Array of Expression's to call new operator
     Type newtype;
     Expressions* arguments;     // Array of Expression's
 
@@ -3530,25 +3516,23 @@ extern (C++) final class NewExp : Expression
     bool onstack;               // allocate on stack
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
-    extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+    extern (D) this(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
     {
         super(loc, EXP.new_, __traits(classInstanceSize, NewExp));
         this.thisexp = thisexp;
-        this.newargs = newargs;
         this.newtype = newtype;
         this.arguments = arguments;
     }
 
-    static NewExp create(const ref Loc loc, Expression thisexp, Expressions* newargs, Type newtype, Expressions* arguments)
+    static NewExp create(const ref Loc loc, Expression thisexp, Type newtype, Expressions* arguments)
     {
-        return new NewExp(loc, thisexp, newargs, newtype, arguments);
+        return new NewExp(loc, thisexp, newtype, arguments);
     }
 
     override NewExp syntaxCopy()
     {
         return new NewExp(loc,
             thisexp ? thisexp.syntaxCopy() : null,
-            arraySyntaxCopy(newargs),
             newtype.syntaxCopy(),
             arraySyntaxCopy(arguments));
     }
@@ -3560,27 +3544,25 @@ extern (C++) final class NewExp : Expression
 }
 
 /***********************************************************
- * thisexp.new(newargs) class baseclasses { } (arguments)
+ * class baseclasses { } (arguments)
  */
 extern (C++) final class NewAnonClassExp : Expression
 {
     Expression thisexp;     // if !=null, 'this' for class being allocated
-    Expressions* newargs;   // Array of Expression's to call new operator
     ClassDeclaration cd;    // class being instantiated
     Expressions* arguments; // Array of Expression's to call class constructor
 
-    extern (D) this(const ref Loc loc, Expression thisexp, Expressions* newargs, ClassDeclaration cd, Expressions* arguments)
+    extern (D) this(const ref Loc loc, Expression thisexp, ClassDeclaration cd, Expressions* arguments)
     {
         super(loc, EXP.newAnonymousClass, __traits(classInstanceSize, NewAnonClassExp));
         this.thisexp = thisexp;
-        this.newargs = newargs;
         this.cd = cd;
         this.arguments = arguments;
     }
 
     override NewAnonClassExp syntaxCopy()
     {
-        return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, arraySyntaxCopy(newargs), cd.syntaxCopy(null), arraySyntaxCopy(arguments));
+        return new NewAnonClassExp(loc, thisexp ? thisexp.syntaxCopy() : null, cd.syntaxCopy(null), arraySyntaxCopy(arguments));
     }
 
     override void accept(Visitor v)
@@ -4593,11 +4575,6 @@ extern (C++) class BinAssignExp : BinExp
         return toLvalue(sc, this);
     }
 
-    override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @safe
-    {
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -7055,3 +7032,53 @@ extern(D) Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag
             return exp.type ? Modifiable.yes : Modifiable.no; // default modifiable
     }
 }
+
+/******************************
+ * Provide efficient way to implement isUnaExp(), isBinExp(), isBinAssignExp()
+ */
+private immutable ubyte[EXP.max + 1] exptab =
+() {
+    ubyte[EXP.max + 1] tab;
+    with (EXPFLAGS)
+    {
+        foreach (i; Eunary)  { tab[i] |= unary;  }
+        foreach (i; Ebinary) { tab[i] |= unary | binary; }
+        foreach (i; EbinaryAssign) { tab[i] |= unary | binary | binaryAssign; }
+    }
+    return tab;
+} ();
+
+private enum EXPFLAGS : ubyte
+{
+    unary = 1,
+    binary = 2,
+    binaryAssign = 4,
+}
+
+private enum Eunary =
+    [
+        EXP.import_, EXP.assert_, EXP.throw_, EXP.dotIdentifier, EXP.dotTemplateDeclaration,
+        EXP.dotVariable, EXP.dotTemplateInstance, EXP.delegate_, EXP.dotType, EXP.call,
+        EXP.address, EXP.star, EXP.negate, EXP.uadd, EXP.tilde, EXP.not, EXP.delete_, EXP.cast_,
+        EXP.vector, EXP.vectorArray, EXP.slice, EXP.arrayLength, EXP.array, EXP.delegatePointer,
+        EXP.delegateFunctionPointer, EXP.preMinusMinus, EXP.prePlusPlus,
+    ];
+
+private enum Ebinary =
+    [
+        EXP.dot, EXP.comma, EXP.index, EXP.minusMinus, EXP.plusPlus, EXP.assign,
+        EXP.add, EXP.min, EXP.concatenate, EXP.mul, EXP.div, EXP.mod, EXP.pow, EXP.leftShift,
+        EXP.rightShift, EXP.unsignedRightShift, EXP.and, EXP.or, EXP.xor, EXP.andAnd, EXP.orOr,
+        EXP.lessThan, EXP.lessOrEqual, EXP.greaterThan, EXP.greaterOrEqual,
+        EXP.in_, EXP.remove, EXP.equal, EXP.notEqual, EXP.identity, EXP.notIdentity,
+        EXP.question,
+        EXP.construct, EXP.blit,
+    ];
+
+private enum EbinaryAssign =
+    [
+        EXP.addAssign, EXP.minAssign, EXP.mulAssign, EXP.divAssign, EXP.modAssign,
+        EXP.andAssign, EXP.orAssign, EXP.xorAssign, EXP.powAssign,
+        EXP.leftShiftAssign, EXP.rightShiftAssign, EXP.unsignedRightShiftAssign,
+        EXP.concatenateAssign, EXP.concatenateElemAssign, EXP.concatenateDcharAssign,
+    ];
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 18ef90a56a7..9522b23a3b1 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -234,7 +234,10 @@ public:
     FuncInitExp* isFuncInitExp();
     PrettyFuncInitExp* isPrettyFuncInitExp();
     ClassReferenceExp* isClassReferenceExp();
-    virtual BinAssignExp* isBinAssignExp();
+    ThrownExceptionExp* isThrownExceptionExp();
+    UnaExp* isUnaExp();
+    BinExp* isBinExp();
+    BinAssignExp* isBinAssignExp();
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -374,13 +377,14 @@ public:
     static StringExp *create(const Loc &loc, const void *s, size_t len);
     static void emplace(UnionExp *pue, const Loc &loc, const char *s);
     bool equals(const RootObject *o) const;
+    char32_t getCodeUnit(size_t i) const;
+    void setCodeUnit(size_t i, char32_t c);
     StringExp *toStringExp();
     StringExp *toUTF8(Scope *sc);
     Optional<bool> toBool();
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
-    unsigned charAt(uinteger_t i) const;
     void accept(Visitor *v) { v->visit(this); }
     size_t numberOfCodeUnits(int tynto = 0) const;
     void writeTo(void* dest, bool zero, int tyto = 0) const;
@@ -519,10 +523,9 @@ public:
 class NewExp : public Expression
 {
 public:
-    /* thisexp.new(newargs) newtype(arguments)
+    /* newtype(arguments)
      */
     Expression *thisexp;        // if !NULL, 'this' for class being allocated
-    Expressions *newargs;       // Array of Expression's to call new operator
     Type *newtype;
     Expressions *arguments;     // Array of Expression's
 
@@ -532,7 +535,7 @@ public:
     bool onstack;               // allocate on stack
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
-    static NewExp *create(const Loc &loc, Expression *thisexp, Expressions *newargs, Type *newtype, Expressions *arguments);
+    static NewExp *create(const Loc &loc, Expression *thisexp, Type *newtype, Expressions *arguments);
     NewExp *syntaxCopy();
 
     void accept(Visitor *v) { v->visit(this); }
@@ -541,10 +544,9 @@ public:
 class NewAnonClassExp : public Expression
 {
 public:
-    /* thisexp.new(newargs) class baseclasses { } (arguments)
+    /* class baseclasses { } (arguments)
      */
     Expression *thisexp;        // if !NULL, 'this' for class being allocated
-    Expressions *newargs;       // Array of Expression's to call new operator
     ClassDeclaration *cd;       // class being instantiated
     Expressions *arguments;     // Array of Expression's to call class constructor
 
@@ -716,7 +718,6 @@ public:
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *ex);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
-    BinAssignExp* isBinAssignExp();
     void accept(Visitor *v) { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 6eda6888077..0320f662bdf 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -1236,21 +1236,21 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         tthis = null;
         goto Lfd;
     }
-    else if (e1.op == EXP.dotVariable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(DotVarExp)e1).var.isOverDeclaration()))
+    else if (e1.isDotVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isDotVarExp().var.isOverDeclaration()))
     {
-        DotVarExp dve = cast(DotVarExp)e1;
+        DotVarExp dve = e1.isDotVarExp();
         s = dve.var;
         tiargs = null;
         tthis = dve.e1.type;
         goto Lfd;
     }
-    else if (sc && sc.flags & SCOPE.Cfile && e1.op == EXP.variable && !e2)
+    else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
     {
         // ImportC: do not implicitly call function if no ( ) are present
     }
-    else if (e1.op == EXP.variable && e1.type && (e1.type.toBasetype().ty == Tfunction || (cast(VarExp)e1).var.isOverDeclaration()))
+    else if (e1.isVarExp() && e1.type && (e1.type.toBasetype().isTypeFunction() || e1.isVarExp().var.isOverDeclaration()))
     {
-        s = (cast(VarExp)e1).var;
+        s = e1.isVarExp().var;
         tiargs = null;
         tthis = null;
     Lfd:
@@ -1272,9 +1272,9 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                     return ErrorExp.get();
                 if (!checkSymbolAccess(sc, fd))
                 {
-                    // @@@DEPRECATED_2020-10@@@
+                    // @@@DEPRECATED_2.105@@@
                     // When turning into error, uncomment the return statement
-                    TypeFunction tf = cast(TypeFunction)fd.type;
+                    TypeFunction tf = fd.type.isTypeFunction();
                     deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
                                 fd.toPrettyChars(), tf.toChars, sc._module.toChars);
                     //return ErrorExp.get();
@@ -1290,13 +1290,12 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
             {
                 if (fd.errors)
                     return ErrorExp.get();
-                assert(fd.type.ty == Tfunction);
-                TypeFunction tf = cast(TypeFunction)fd.type;
+                TypeFunction tf = fd.type.isTypeFunction();
                 if (!e2 || tf.isref)
                 {
                     if (!checkSymbolAccess(sc, fd))
                     {
-                        // @@@DEPRECATED_2020-10@@@
+                        // @@@DEPRECATED_2.105@@@
                         // When turning into error, uncomment the return statement
                         deprecation(loc, "Function `%s` of type `%s` is not accessible from module `%s`",
                                     fd.toPrettyChars(), tf.toChars, sc._module.toChars);
@@ -1319,17 +1318,18 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if (e2)
             goto Leprop;
     }
-    if (e1.op == EXP.variable)
+    if (auto ve = e1.isVarExp())
     {
-        VarExp ve = cast(VarExp)e1;
-        VarDeclaration v = ve.var.isVarDeclaration();
-        if (v && ve.checkPurity(sc, v))
-            return ErrorExp.get();
+        if (auto v = ve.var.isVarDeclaration())
+        {
+            if (ve.checkPurity(sc, v))
+                return ErrorExp.get();
+        }
     }
     if (e2)
         return null;
 
-    if (e1.type && e1.op != EXP.type) // function type is not a property
+    if (e1.type && !e1.isTypeExp()) // function type is not a property
     {
         /* Look for e1 being a lazy parameter; rewrite as delegate call
          * only if the symbol wasn't already treated as a delegate
@@ -1340,15 +1340,14 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                 Expression e = new CallExp(loc, e1);
                 return e.expressionSemantic(sc);
         }
-        else if (e1.op == EXP.dotVariable)
+        else if (e1.isDotVarExp())
         {
             // Check for reading overlapped pointer field in @safe code.
             if (checkUnsafeAccess(sc, e1, true, true))
                 return ErrorExp.get();
         }
-        else if (e1.op == EXP.call)
+        else if (auto ce = e1.isCallExp())
         {
-            CallExp ce = cast(CallExp)e1;
             // Check for reading overlapped pointer field in @safe code.
             if (checkUnsafeAccess(sc, ce.e1, true, true))
                 return ErrorExp.get();
@@ -1560,14 +1559,12 @@ private Expression opAssignToOp(const ref Loc loc, EXP op, Expression e1, Expres
  */
 private Expression rewriteOpAssign(BinExp exp)
 {
-    Expression e;
-
-    assert(exp.e1.op == EXP.arrayLength);
-    ArrayLengthExp ale = cast(ArrayLengthExp)exp.e1;
-    if (ale.e1.op == EXP.variable)
+    ArrayLengthExp ale = exp.e1.isArrayLengthExp();
+    if (ale.e1.isVarExp())
     {
-        e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
+        Expression e = opAssignToOp(exp.loc, exp.op, ale, exp.e2);
         e = new AssignExp(exp.loc, ale.syntaxCopy(), e);
+        return e;
     }
     else
     {
@@ -1578,11 +1575,11 @@ private Expression rewriteOpAssign(BinExp exp)
 
         Expression e1 = new ArrayLengthExp(ale.loc, new PtrExp(ale.loc, new VarExp(ale.loc, tmp)));
         Expression elvalue = e1.syntaxCopy();
-        e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
+        Expression e = opAssignToOp(exp.loc, exp.op, e1, exp.e2);
         e = new AssignExp(exp.loc, elvalue, e);
         e = new CommaExp(exp.loc, new DeclarationExp(ale.loc, tmp), e);
+        return e;
     }
-    return e;
 }
 
 /****************************************
@@ -1650,10 +1647,9 @@ private bool preFunctionParameters(Scope* sc, Expressions* exps, const bool repo
  */
 private bool checkDefCtor(Loc loc, Type t)
 {
-    t = t.baseElemOf();
-    if (t.ty == Tstruct)
+    if (auto ts = t.baseElemOf().isTypeStruct())
     {
-        StructDeclaration sd = (cast(TypeStruct)t).sym;
+        StructDeclaration sd = ts.sym;
         if (sd.noDefaultCtor)
         {
             sd.error(loc, "default construction is disabled");
@@ -1846,7 +1842,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                         auto args = new Expressions(nargs - i);
                         foreach (u; i .. nargs)
                             (*args)[u - i] = (*arguments)[u];
-                        arg = new NewExp(loc, null, null, p.type, args);
+                        arg = new NewExp(loc, null, p.type, args);
                         break;
                     }
                 default:
@@ -1923,7 +1919,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     }
                     else if (auto ff = s.isFuncDeclaration())
                     {
-                        if ((cast(TypeFunction)ff.type).iswild)
+                        if (ff.type.isTypeFunction().iswild)
                             return errorInout(wildmatch);
 
                         if (ff.isNested() || ff.isThis())
@@ -1969,7 +1965,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     ? p.type.substWildTo(wildmatch)
                     : p.type;
 
-                const hasCopyCtor = (arg.type.ty == Tstruct) && (cast(TypeStruct)arg.type).sym.hasCopyCtor;
+                const hasCopyCtor = arg.type.isTypeStruct() && arg.type.isTypeStruct().sym.hasCopyCtor;
                 const typesMatch = arg.type.mutableOf().unSharedOf().equals(tprm.mutableOf().unSharedOf());
                 if (!((hasCopyCtor && typesMatch) || tprm.equals(arg.type)))
                 {
@@ -2059,8 +2055,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 /* Argument value cannot escape from the called function.
                  */
                 Expression a = arg;
-                if (a.op == EXP.cast_)
-                    a = (cast(CastExp)a).e1;
+                if (auto ce = a.isCastExp())
+                    a = ce.e1;
 
                 ArrayLiteralExp ale;
                 if (p.type.toBasetype().ty == Tarray &&
@@ -2074,26 +2070,22 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     arg = CommaExp.combine(declareTmp, castToSlice);
                     arg = arg.expressionSemantic(sc);
                 }
-                else if (a.op == EXP.function_)
+                else if (auto fe = a.isFuncExp())
                 {
                     /* Function literals can only appear once, so if this
                      * appearance was scoped, there cannot be any others.
                      */
-                    FuncExp fe = cast(FuncExp)a;
                     fe.fd.tookAddressOf = 0;
                 }
-                else if (a.op == EXP.delegate_)
+                else if (auto de = a.isDelegateExp())
                 {
                     /* For passing a delegate to a scoped parameter,
                      * this doesn't count as taking the address of it.
                      * We only worry about 'escaping' references to the function.
                      */
-                    DelegateExp de = cast(DelegateExp)a;
-                    if (de.e1.op == EXP.variable)
+                    if (auto ve = de.e1.isVarExp())
                     {
-                        VarExp ve = cast(VarExp)de.e1;
-                        FuncDeclaration f = ve.var.isFuncDeclaration();
-                        if (f)
+                        if (auto f = ve.var.isFuncDeclaration())
                         {
                             if (f.tookAddressOf)
                                 --f.tookAddressOf;
@@ -2174,9 +2166,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
             // Convert static arrays to dynamic arrays
             // BUG: I don't think this is right for D2
             Type tb = arg.type.toBasetype();
-            if (tb.ty == Tsarray)
+            if (auto ts = tb.isTypeSArray())
             {
-                TypeSArray ts = cast(TypeSArray)tb;
                 Type ta = ts.next.arrayOf();
                 if (ts.size(arg.loc) == 0)
                     arg = new NullExp(arg.loc, ta);
@@ -2188,9 +2179,8 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 //arg = callCpCtor(sc, arg);
             }
             // Give error for overloaded function addresses
-            if (arg.op == EXP.symbolOffset)
+            if (auto se = arg.isSymOffExp())
             {
-                SymOffExp se = cast(SymOffExp)arg;
                 if (se.hasOverloads && !se.var.isFuncDeclaration().isUnique())
                 {
                     arg.error("function `%s` is overloaded", arg.toChars());
@@ -3469,10 +3459,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // T should be analyzed first and edim should go into arguments iff it's
         // not a tuple.
         Expression edim = null;
-        if (!exp.arguments && exp.newtype.ty == Tsarray)
+        if (!exp.arguments && exp.newtype.isTypeSArray())
         {
-            edim = (cast(TypeSArray)exp.newtype).dim;
-            exp.newtype = (cast(TypeNext)exp.newtype).next;
+            auto ts = exp.newtype.isTypeSArray();
+            edim = ts.dim;
+            exp.newtype = ts.next;
         }
 
         ClassDeclaration cdthis = null;
@@ -3522,11 +3513,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         exp.newtype = exp.type; // in case type gets cast to something else
         Type tb = exp.type.toBasetype();
         //printf("tb: %s, deco = %s\n", tb.toChars(), tb.deco);
-        if (arrayExpressionSemantic(exp.newargs, sc) ||
-            preFunctionParameters(sc, exp.newargs))
-        {
-            return setError();
-        }
         if (arrayExpressionSemantic(exp.arguments, sc))
         {
             return setError();
@@ -3556,9 +3542,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         const size_t nargs = exp.arguments ? exp.arguments.dim : 0;
         Expression newprefix = null;
 
-        if (tb.ty == Tclass)
+        if (auto tc = tb.isTypeClass())
         {
-            auto cd = (cast(TypeClass)tb).sym;
+            auto cd = tc.sym;
             cd.size(exp.loc);
             if (cd.sizeok != Sizeok.done)
                 return setError();
@@ -3692,14 +3678,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                           originalNewtype.toChars());
                 return setError();
             }
-            else
-            {
-                if (exp.newargs && exp.newargs.dim)
-                {
-                    exp.error("no allocator for `%s`", cd.toChars());
-                    return setError();
-                }
-            }
 
             if (cd.ctor)
             {
@@ -3710,7 +3688,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 checkFunctionAttributes(exp, sc, f);
                 checkAccess(cd, exp.loc, sc, f);
 
-                TypeFunction tf = cast(TypeFunction)f.type;
+                TypeFunction tf = f.type.isTypeFunction();
                 if (!exp.arguments)
                     exp.arguments = new Expressions();
                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
@@ -3744,9 +3722,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
-        else if (tb.ty == Tstruct)
+        else if (auto ts = tb.isTypeStruct())
         {
-            auto sd = (cast(TypeStruct)tb).sym;
+            auto sd = ts.sym;
             sd.size(exp.loc);
             if (sd.sizeok != Sizeok.done)
                 return setError();
@@ -3765,14 +3743,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                           originalNewtype.toChars());
                 return setError();
             }
-            else
-            {
-                if (exp.newargs && exp.newargs.dim)
-                {
-                    exp.error("no allocator for `%s`", sd.toChars());
-                    return setError();
-                }
-            }
 
             if (sd.hasRegularCtor() && nargs)
             {
@@ -3783,7 +3753,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 checkFunctionAttributes(exp, sc, f);
                 checkAccess(sd, exp.loc, sc, f);
 
-                TypeFunction tf = cast(TypeFunction)f.type;
+                TypeFunction tf = f.type.isTypeFunction();
                 if (!exp.arguments)
                     exp.arguments = new Expressions();
                 if (functionParameters(exp.loc, sc, tf, null, exp.type, exp.arguments, f, &exp.type, &exp.argprefix))
@@ -3861,7 +3831,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
                 }
                 (*exp.arguments)[i] = arg;
-                tb = (cast(TypeDArray)tb).next.toBasetype();
+                tb = tb.isTypeDArray().next.toBasetype();
             }
         }
         else if (tb.isscalar())
@@ -3924,7 +3894,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             sds.members.push(e.cd);
         }
 
-        Expression n = new NewExp(e.loc, e.thisexp, e.newargs, e.cd.type, e.arguments);
+        Expression n = new NewExp(e.loc, e.thisexp, e.cd.type, e.arguments);
 
         Expression c = new CommaExp(e.loc, d, n);
         result = c.expressionSemantic(sc);
@@ -4097,6 +4067,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // Type is a "delegate to" or "pointer to" the function literal
         if ((exp.fd.isNested() && exp.fd.tok == TOK.delegate_) || (exp.tok == TOK.reserved && exp.fd.treq && exp.fd.treq.ty == Tdelegate))
         {
+            // https://issues.dlang.org/show_bug.cgi?id=22686
+            // if the delegate return type is an error
+            // abort semantic of the FuncExp and propagate
+            // the error
+            if (exp.fd.type.isTypeError())
+            {
+                e = ErrorExp.get();
+                goto Ldone;
+            }
             exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
             exp.type = exp.type.typeSemantic(exp.loc, sc);
 
@@ -5239,21 +5218,21 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             break;
         }
 
-        VarDeclaration v = s.isVarDeclaration();
-        if (v)
-        {
-            // Do semantic() on initializer first, so:
-            //      int a = a;
-            // will be illegal.
-            e.declaration.dsymbolSemantic(sc);
-            s.parent = sc.parent;
-        }
-
         //printf("inserting '%s' %p into sc = %p\n", s.toChars(), s, sc);
         // Insert into both local scope and function scope.
         // Must be unique in both.
         if (s.ident)
         {
+            VarDeclaration v = s.isVarDeclaration();
+            if (v && !(sc.flags & SCOPE.Cfile))
+            {
+                /* Do semantic() on initializer first so this will be illegal:
+                 *      int a = a;
+                 */
+                e.declaration.dsymbolSemantic(sc);
+                s.parent = sc.parent;
+            }
+
             if (!sc.insert(s))
             {
                 auto conflict = sc.search(Loc.initial, s.ident, null);
@@ -5262,7 +5241,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                                   conflict.kind(), conflict.toChars());
                 return setError();
             }
-            else if (sc.func)
+
+            if (v && (sc.flags & SCOPE.Cfile))
+            {
+                /* Do semantic() on initializer last so this will be legal:
+                 *      int a = a;
+                 */
+                e.declaration.dsymbolSemantic(sc);
+                s.parent = sc.parent;
+            }
+
+            if (sc.func)
             {
                 // https://issues.dlang.org/show_bug.cgi?id=11720
                 if ((s.isFuncDeclaration() ||
@@ -5278,14 +5267,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // Perturb the name mangling so that the symbols can co-exist
                     // instead of colliding
                     s.localNum = cast(ushort)(originalSymbol.localNum + 1);
-                    assert(s.localNum);         // 65535 should be enough for anyone
+                    // 65535 should be enough for anyone
+                    if (!s.localNum)
+                    {
+                        e.error("more than 65535 symbols with name `%s` generated", s.ident.toChars());
+                        return setError();
+                    }
 
                     // Replace originalSymbol with s, which updates the localCount
                     sc.func.localsymtab.update(s);
 
                     // The mangling change only works for D mangling
                 }
-//              else
+
                 {
                     /* https://issues.dlang.org/show_bug.cgi?id=21272
                      * If we are in a foreach body we need to extract the
@@ -6943,15 +6937,19 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else if (!exp.e1.type.deco)
         {
-            if (exp.e1.op == EXP.variable)
+            // try to resolve the type
+            exp.e1.type = exp.e1.type.typeSemantic(exp.e1.loc, null);
+            if (!exp.e1.type.deco)  // still couldn't resolve it
             {
-                VarExp ve = cast(VarExp)exp.e1;
-                Declaration d = ve.var;
-                exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
+                if (auto ve = exp.e1.isVarExp())
+                {
+                    Declaration d = ve.var;
+                    exp.error("forward reference to %s `%s`", d.kind(), d.toChars());
+                }
+                else
+                    exp.error("forward reference to type `%s` of expression `%s`", exp.e1.type.toChars(), exp.e1.toChars());
+                return setError();
             }
-            else
-                exp.error("forward reference to `%s`", exp.e1.toChars());
-            return setError();
         }
 
         exp.type = exp.e1.type.pointerTo();
@@ -7327,14 +7325,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
     override void visit(DeleteExp exp)
     {
-        if (!sc.isDeprecated)
+        // @@@DEPRECATED_2.109@@@
+        // 1. Deprecated since 2.079
+        // 2. Error since 2.099
+        // 3. Removal of keyword, "delete" can be used for other identities
+        if (!exp.isRAII)
         {
-            // @@@DEPRECATED_2019-02@@@
-            // 1. Deprecation for 1 year
-            // 2. Error for 1 year
-            // 3. Removal of keyword, "delete" can be used for other identities
-            if (!exp.isRAII)
-                deprecation(exp.loc, "The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
+            error(exp.loc, "The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.");
+            return setError();
         }
 
         Expression e = exp;
@@ -7353,89 +7351,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         exp.type = Type.tvoid;
 
-        AggregateDeclaration ad = null;
         Type tb = exp.e1.type.toBasetype();
-        switch (tb.ty)
-        {
-        case Tclass:
-            {
-                auto cd = (cast(TypeClass)tb).sym;
-                if (cd.isCOMinterface())
-                {
-                    /* Because COM classes are deleted by IUnknown.Release()
-                     */
-                    exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
-                    return setError();
-                }
-                ad = cd;
-                break;
-            }
-        case Tpointer:
-            tb = (cast(TypePointer)tb).next.toBasetype();
-            if (tb.ty == Tstruct)
-            {
-                ad = (cast(TypeStruct)tb).sym;
-
-                Identifier hook = global.params.tracegc ? Id._d_delstructTrace : Id._d_delstruct;
-                if (!verifyHookExist(exp.loc, *sc, Id._d_delstructImpl, "deleting struct with dtor", Id.object))
-                    return setError();
 
-                // Lower to .object._d_delstruct{,Trace}(exp.e1)
-                Expression id = new IdentifierExp(exp.loc, Id.empty);
-                id = new DotIdExp(exp.loc, id, Id.object);
-
-                auto tiargs = new Objects();
-                tiargs.push(exp.e1.type);
-                id = new DotTemplateInstanceExp(exp.loc, id, Id._d_delstructImpl, tiargs);
-                id = new DotIdExp(exp.loc, id, hook);
-
-                e = new CallExp(exp.loc, id, exp.e1);
-                /* Gag errors generated by calls to `_d_delstruct`, because they display
-                 * internal compiler information, which is unnecessary to the user.
-                 */
-                uint errors = global.startGagging();
-                e = e.expressionSemantic(sc);
-                global.endGagging(errors);
-            }
-            break;
-
-        case Tarray:
-            {
-                Type tv = tb.nextOf().baseElemOf();
-                if (tv.ty == Tstruct)
-                {
-                    ad = (cast(TypeStruct)tv).sym;
-                    if (ad.dtor)
-                        semanticTypeInfo(sc, ad.type);
-                }
-                break;
-            }
-        default:
+        /* Now that `delete` in user code is an error, we only get here when
+         * `isRAII` has been set to true for the deletion of a `scope class`.  */
+        if (tb.ty != Tclass)
+        {
             exp.error("cannot delete type `%s`", exp.e1.type.toChars());
             return setError();
         }
 
-        bool err = false;
-        if (ad)
+        ClassDeclaration cd = (cast(TypeClass)tb).sym;
+        if (cd.isCOMinterface())
         {
-            if (ad.dtor)
-            {
-                err |= !ad.dtor.functionSemantic();
-                err |= exp.checkPurity(sc, ad.dtor);
-                err |= exp.checkSafety(sc, ad.dtor);
-                err |= exp.checkNogc(sc, ad.dtor);
-            }
-            if (err)
-                return setError();
+            /* Because COM classes are deleted by IUnknown.Release()
+             */
+            exp.error("cannot `delete` instance of COM interface `%s`", cd.toChars());
+            return setError();
         }
 
-        if (!sc.intypeof && sc.func &&
-            !exp.isRAII &&
-            !(sc.flags & SCOPE.debug_) &&
-            sc.func.setUnsafe())
+        bool err = false;
+        if (cd.dtor)
         {
-            exp.error("`%s` is not `@safe` but is used in `@safe` function `%s`", exp.toChars(), sc.func.toChars());
-            err = true;
+            err |= !cd.dtor.functionSemantic();
+            err |= exp.checkPurity(sc, cd.dtor);
+            err |= exp.checkSafety(sc, cd.dtor);
+            err |= exp.checkNogc(sc, cd.dtor);
         }
         if (err)
             return setError();
@@ -7457,12 +7398,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         if ((sc && sc.flags & SCOPE.Cfile) &&
-            exp.to && exp.to.ty == Tident &&
+            exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
             (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
              exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
         {
             /* Ambiguous cases arise from CParser if type-name is just an identifier.
              *   ( identifier ) cast-expression
+             *   ( identifier [expression]) cast-expression
              * If we determine that `identifier` is a variable, and cast-expression
              * is one of the unary operators (& * + -), then rewrite this cast
              * as a binary expression.
@@ -9858,7 +9800,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             VarExp ve = cast(VarExp)exp.e1;
             VarDeclaration vd = ve.var.isVarDeclaration();
-            if (vd && (vd.onstack || vd.mynew))
+            if (vd && vd.onstack)
             {
                 assert(t1.ty == Tclass);
                 exp.error("cannot rebind scope variables");
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index f3aeb0ff3dc..39cb8456fda 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -567,7 +567,8 @@ extern (C++) class FuncDeclaration : Declaration
              * do existing practice. But we should examine how TypeFunction does
              * it, for consistency.
              */
-            if (!tf.isref && isRefReturnScope(vthis.storage_class))
+            if (global.params.useDIP1000 != FeatureState.enabled &&
+                !tf.isref && isRefReturnScope(vthis.storage_class))
             {
                 /* if `ref return scope`, evaluate to `ref` `return scope`
                  */
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 43b63f147ce..6b8ecc5c07f 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -991,8 +991,9 @@ public:
     override void visit(VisibilityDeclaration d)
     {
         visibilityToBuffer(buf, d.visibility);
-        buf.writeByte(' ');
         AttribDeclaration ad = cast(AttribDeclaration)d;
+        if (ad.decl.dim <= 1)
+            buf.writeByte(' ');
         if (ad.decl.dim == 1 && (*ad.decl)[0].isVisibilityDeclaration)
             visit(cast(AttribDeclaration)(*ad.decl)[0]);
         else
@@ -1693,17 +1694,8 @@ public:
 
     override void visit(DtorDeclaration d)
     {
-        if (d.storage_class & STC.trusted)
-            buf.writestring("@trusted ");
-        if (d.storage_class & STC.safe)
-            buf.writestring("@safe ");
-        if (d.storage_class & STC.nogc)
-            buf.writestring("@nogc ");
-        if (d.storage_class & STC.live)
-            buf.writestring("@live ");
-        if (d.storage_class & STC.disable)
-            buf.writestring("@disable ");
-
+        if (stcToBuffer(buf, d.storage_class))
+            buf.writeByte(' ');
         buf.writestring("~this()");
         bodyToBuffer(d);
     }
@@ -1992,29 +1984,9 @@ public:
     {
         buf.writeByte('"');
         const o = buf.length;
-        for (size_t i = 0; i < e.len; i++)
+        foreach (i; 0 .. e.len)
         {
-            const c = e.charAt(i);
-            switch (c)
-            {
-            case '"':
-            case '\\':
-                buf.writeByte('\\');
-                goto default;
-            default:
-                if (c <= 0xFF)
-                {
-                    if (c <= 0x7F && isprint(c))
-                        buf.writeByte(c);
-                    else
-                        buf.printf("\\x%02x", c);
-                }
-                else if (c <= 0xFFFF)
-                    buf.printf("\\x%02x\\x%02x", c & 0xFF, c >> 8);
-                else
-                    buf.printf("\\x%02x\\x%02x\\x%02x\\x%02x", c & 0xFF, (c >> 8) & 0xFF, (c >> 16) & 0xFF, c >> 24);
-                break;
-            }
+            writeCharLiteral(*buf, e.getCodeUnit(i));
         }
         if (hgs.ddoc)
             escapeDdocString(buf, o);
@@ -2113,12 +2085,6 @@ public:
             buf.writeByte('.');
         }
         buf.writestring("new ");
-        if (e.newargs && e.newargs.dim)
-        {
-            buf.writeByte('(');
-            argsToBuffer(e.newargs, buf, hgs);
-            buf.writeByte(')');
-        }
         typeToBuffer(e.newtype, null, buf, hgs);
         if (e.arguments && e.arguments.dim)
         {
@@ -2136,12 +2102,6 @@ public:
             buf.writeByte('.');
         }
         buf.writestring("new");
-        if (e.newargs && e.newargs.dim)
-        {
-            buf.writeByte('(');
-            argsToBuffer(e.newargs, buf, hgs);
-            buf.writeByte(')');
-        }
         buf.writestring(" class ");
         if (e.arguments && e.arguments.dim)
         {
@@ -2909,22 +2869,6 @@ string stcToString(ref StorageClass stc)
     return null;
 }
 
-/// Ditto
-extern (D) string trustToString(TRUST trust) pure nothrow
-{
-    final switch (trust)
-    {
-    case TRUST.default_:
-        return null;
-    case TRUST.system:
-        return "@system";
-    case TRUST.trusted:
-        return "@trusted";
-    case TRUST.safe:
-        return "@safe";
-    }
-}
-
 private void linkageToBuffer(OutBuffer* buf, LINK linkage)
 {
     const s = linkageToString(linkage);
@@ -3902,7 +3846,7 @@ private void typeToBufferx(Type t, OutBuffer* buf, HdrGenState* hgs)
         buf.writeByte(' ');
         if (t.id)
             buf.writestring(t.id.toChars());
-        if (t.base.ty != TY.Tint32)
+        if (t.tok == TOK.enum_ && t.base.ty != TY.Tint32)
         {
             buf.writestring(" : ");
             visitWithMask(t.base, t.mod, buf, hgs);
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index 495126de54f..7d4fbc3e45b 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -84,7 +84,7 @@ int parseExtAsmOperands(Parser)(Parser p, GccAsmStatement s)
 
             case TOK.string_:
                 constraint = p.parsePrimaryExp();
-                // @@@DEPRECATED@@@
+                // @@@DEPRECATED_2.101@@@
                 // Old parser allowed omitting parentheses around the expression.
                 // Deprecated in 2.091. Can be made permanent error after 2.100
                 if (p.token.value != TOK.leftParenthesis)
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 7f51e929ad4..31a44db2542 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -115,7 +115,6 @@ immutable Msgtable[] msgtable =
     { "line" },
     { "empty", "" },
     { "p" },
-    { "q" },
     { "__vptr" },
     { "__monitor" },
     { "gate", "__gate" },
@@ -311,9 +310,6 @@ immutable Msgtable[] msgtable =
     { "__ArrayPostblit" },
     { "__ArrayDtor" },
     { "_d_delThrowable" },
-    { "_d_delstructImpl" },
-    { "_d_delstruct" },
-    { "_d_delstructTrace" },
     { "_d_assert_fail" },
     { "dup" },
     { "_aaApply" },
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index 1b92386c328..a48b339bf50 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -260,3 +260,50 @@ Expression castCallAmbiguity(Expression e, Scope* sc)
     }
 }
 
+/********************************************
+ * Implement the C11 notion of function equivalence,
+ * which allows prototyped functions to match K+R functions,
+ * even though they are different.
+ * Params:
+ *      tf1 = type of first function
+ *      tf2 = type of second function
+ * Returns:
+ *      true if C11 considers them equivalent
+ */
+
+bool cFuncEquivalence(TypeFunction tf1, TypeFunction tf2)
+{
+    if (tf1.equals(tf2))
+        return true;
+
+    if (tf1.linkage != tf2.linkage)
+        return false;
+
+    // Allow func(void) to match func()
+    if (tf1.parameterList.length == 0 && tf2.parameterList.length == 0)
+        return true;
+
+    if (!tf1.parameterList.hasIdentifierList &&
+        !tf2.parameterList.hasIdentifierList)
+        return false;   // both functions are prototyped
+
+    // Otherwise ignore variadicness, as K+R functions are all variadic
+
+    if (!tf1.nextOf().equals(tf2.nextOf()))
+        return false;   // function return types don't match
+
+    if (tf1.parameterList.length != tf2.parameterList.length)
+        return false;
+
+    foreach (i, fparam ; tf1.parameterList)
+    {
+        Type t1 = fparam.type;
+        Type t2 = tf2.parameterList[i].type;
+        if (!t1.equals(t2))
+            return false;
+    }
+
+    //printf("t1: %s\n", tf1.toChars());
+    //printf("t2: %s\n", tf2.toChars());
+    return true;
+}
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 6b10ace4e01..bc02bf93476 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -590,7 +590,11 @@ extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                     i.exp = ErrorExp.get();
                 }
             }
+            Type et = i.exp.type;
+            const errors = global.startGagging();
             i.exp = i.exp.implicitCastTo(sc, t);
+            if (global.endGagging(errors))
+                currExp.error("cannot implicitly convert expression `%s` of type `%s` to `%s`", currExp.toChars(), et.toChars(), t.toChars());
         }
     L1:
         if (i.exp.op == EXP.error)
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index e74b1921760..7c8b504f419 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -38,172 +38,6 @@ import dmd.utils;
 
 nothrow:
 
-private enum LS = 0x2028;       // UTF line separator
-private enum PS = 0x2029;       // UTF paragraph separator
-
-/********************************************
- * Do our own char maps
- */
-private static immutable cmtable = () {
-    ubyte[256] table;
-    foreach (const c; 0 .. table.length)
-    {
-        if ('0' <= c && c <= '7')
-            table[c] |= CMoctal;
-        if (c_isxdigit(c))
-            table[c] |= CMhex;
-        if (c_isalnum(c) || c == '_')
-            table[c] |= CMidchar;
-
-        switch (c)
-        {
-            case 'x': case 'X':
-            case 'b': case 'B':
-                table[c] |= CMzerosecond;
-                break;
-
-            case '0': .. case '9':
-            case 'e': case 'E':
-            case 'f': case 'F':
-            case 'l': case 'L':
-            case 'p': case 'P':
-            case 'u': case 'U':
-            case 'i':
-            case '.':
-            case '_':
-                table[c] |= CMzerosecond | CMdigitsecond;
-                break;
-
-            default:
-                break;
-        }
-
-        switch (c)
-        {
-            case '\\':
-            case '\n':
-            case '\r':
-            case 0:
-            case 0x1A:
-            case '\'':
-                break;
-            default:
-                if (!(c & 0x80))
-                    table[c] |= CMsinglechar;
-                break;
-        }
-    }
-    return table;
-}();
-
-private
-{
-    enum CMoctal  = 0x1;
-    enum CMhex    = 0x2;
-    enum CMidchar = 0x4;
-    enum CMzerosecond = 0x8;
-    enum CMdigitsecond = 0x10;
-    enum CMsinglechar = 0x20;
-}
-
-private bool isoctal(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMoctal) != 0;
-}
-
-private bool ishex(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMhex) != 0;
-}
-
-private bool isidchar(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMidchar) != 0;
-}
-
-private bool isZeroSecond(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMzerosecond) != 0;
-}
-
-private bool isDigitSecond(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMdigitsecond) != 0;
-}
-
-private bool issinglechar(const char c) pure @nogc @safe
-{
-    return (cmtable[c] & CMsinglechar) != 0;
-}
-
-private bool c_isxdigit(const int c) pure @nogc @safe
-{
-    return (( c >= '0' && c <= '9') ||
-            ( c >= 'a' && c <= 'f') ||
-            ( c >= 'A' && c <= 'F'));
-}
-
-private bool c_isalnum(const int c) pure @nogc @safe
-{
-    return (( c >= '0' && c <= '9') ||
-            ( c >= 'a' && c <= 'z') ||
-            ( c >= 'A' && c <= 'Z'));
-}
-
-unittest
-{
-    //printf("lexer.unittest\n");
-    /* Not much here, just trying things out.
-     */
-    string text = "int"; // We rely on the implicit null-terminator
-    scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0);
-    TOK tok;
-    tok = lex1.nextToken();
-    //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
-    assert(tok == TOK.int32);
-    tok = lex1.nextToken();
-    assert(tok == TOK.endOfFile);
-    tok = lex1.nextToken();
-    assert(tok == TOK.endOfFile);
-    tok = lex1.nextToken();
-    assert(tok == TOK.endOfFile);
-}
-
-unittest
-{
-    // We don't want to see Lexer error output during these tests.
-    uint errors = global.startGagging();
-    scope(exit) global.endGagging(errors);
-
-    // Test malformed input: even malformed input should end in a TOK.endOfFile.
-    static immutable char[][] testcases =
-    [   // Testcase must end with 0 or 0x1A.
-        [0], // not malformed, but pathological
-        ['\'', 0],
-        ['\'', 0x1A],
-        ['{', '{', 'q', '{', 0],
-        [0xFF, 0],
-        [0xFF, 0x80, 0],
-        [0xFF, 0xFF, 0],
-        [0xFF, 0xFF, 0],
-        ['x', '"', 0x1A],
-    ];
-
-    foreach (testcase; testcases)
-    {
-        scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
-        TOK tok = lex2.nextToken();
-        size_t iterations = 1;
-        while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
-        {
-            tok = lex2.nextToken();
-        }
-        assert(tok == TOK.endOfFile);
-        tok = lex2.nextToken();
-        assert(tok == TOK.endOfFile);
-    }
-}
-
 version (DMDLIB)
 {
     version = LocOffset;
@@ -440,7 +274,7 @@ class Lexer
                 if (issinglechar(p[1]) && p[2] == '\'')
                 {
                     t.unsvalue = p[1];        // simple one character literal
-                    t.value = Ccompile ? TOK.int32Literal : TOK.charLiteral;
+                    t.value = TOK.charLiteral;
                     p += 3;
                 }
                 else if (Ccompile)
@@ -1716,9 +1550,11 @@ class Lexer
         if (*p == '"')
             p++;
         else if (hereid)
-            error("delimited string must end in %s\"", hereid.toChars());
+            error("delimited string must end in `%s\"`", hereid.toChars());
+        else if (isspace(delimright))
+            error("delimited string must end in `\"`");
         else
-            error("delimited string must end in %c\"", delimright);
+            error("delimited string must end in `%c\"`", delimright);
         result.setString(stringbuffer);
         stringPostfix(result);
     }
@@ -2030,7 +1866,7 @@ class Lexer
             default:
                 assert(0);
         }
-        t.value = TOK.int32Literal;
+        t.value = n == 1 ? TOK.charLiteral : TOK.int32Literal;
         t.unsvalue = u;
     }
 
@@ -2113,7 +1949,11 @@ class Lexer
                 if (p[1] == '.')
                     goto Ldone; // if ".."
                 if (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80)
+                {
+                    if (Ccompile && (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
+                        goto Lreal;  // if `0.f` or `0.L`
                     goto Ldone; // if ".identifier" or ".unicode"
+                }
                 goto Lreal; // '.' is part of current token
             case 'i':
             case 'f':
@@ -2182,7 +2022,12 @@ class Lexer
                 if (p[1] == '.')
                     goto Ldone; // if ".."
                 if (base <= 10 && n > 0 && (isalpha(p[1]) || p[1] == '_' || p[1] & 0x80))
+                {
+                    if (Ccompile && base == 10 &&
+                        (p[1] == 'f' || p[1] == 'F' || p[1] == 'l' || p[1] == 'L'))
+                        goto Lreal;  // if `1.f` or `1.L`
                     goto Ldone; // if ".identifier" or ".unicode"
+                }
                 if (base == 16 && (!ishex(p[1]) || p[1] == '_' || p[1] & 0x80))
                     goto Ldone; // if ".identifier" or ".unicode"
                 if (base == 2)
@@ -2421,11 +2266,6 @@ class Lexer
             flags = cast(FLAGS)(flags | f);
         }
 
-        void overflow()
-        {
-            error("integer overflow");
-        }
-
         TOK result = TOK.int32Literal;     // default
         switch (flags)
         {
@@ -2438,71 +2278,35 @@ class Lexer
                  * First that fits: int, unsigned, long, unsigned long,
                  * long long, unsigned long long
                  */
-                if (longsize == 4)
-                {
-                    if (n & 0x8000000000000000L)
-                        result = TOK.uns64Literal;
-                    else if (n & 0xFFFFFFFF00000000L)
-                        result = TOK.int64Literal;
-                    else if (n & 0x80000000)
-                        result = TOK.uns32Literal;
-                    else
-                        result = TOK.int32Literal;
-                }
+                if (n & 0x8000000000000000L)
+                    result = TOK.uns64Literal;      // unsigned long
+                else if (n & 0xFFFFFFFF00000000L)
+                    result = TOK.int64Literal;      // long
+                else if (n & 0x80000000)
+                    result = TOK.uns32Literal;
                 else
-                {
-                    if (n & 0x8000000000000000L)
-                        result = TOK.uns64Literal;      // unsigned long
-                    else if (n & 0xFFFFFFFF00000000L)
-                        result = TOK.int64Literal;      // long
-                    else if (n & 0x80000000)
-                        result = TOK.uns32Literal;
-                    else
-                        result = TOK.int32Literal;
-                }
+                    result = TOK.int32Literal;
                 break;
 
             case FLAGS.decimal:
                 /* First that fits: int, long, long long
                  */
-                if (longsize == 4)
-                {
-                    if (n & 0x8000000000000000L)
-                        result = TOK.uns64Literal;
-                    else if (n & 0xFFFFFFFF80000000L)
-                        result = TOK.int64Literal;
-                    else
-                        result = TOK.int32Literal;
-                }
+                if (n & 0x8000000000000000L)
+                    result = TOK.uns64Literal;      // unsigned long
+                else if (n & 0xFFFFFFFF80000000L)
+                    result = TOK.int64Literal;      // long
                 else
-                {
-                    if (n & 0x8000000000000000L)
-                        result = TOK.uns64Literal;      // unsigned long
-                    else if (n & 0xFFFFFFFF80000000L)
-                        result = TOK.int64Literal;      // long
-                    else
-                        result = TOK.int32Literal;
-                }
+                    result = TOK.int32Literal;
                 break;
 
             case FLAGS.octalhex | FLAGS.unsigned:
             case FLAGS.decimal | FLAGS.unsigned:
                 /* First that fits: unsigned, unsigned long, unsigned long long
                  */
-                if (longsize == 4)
-                {
-                    if (n & 0xFFFFFFFF00000000L)
-                        result = TOK.uns64Literal;
-                    else
-                        result = TOK.uns32Literal;
-                }
+                if (n & 0xFFFFFFFF00000000L)
+                    result = TOK.uns64Literal;      // unsigned long
                 else
-                {
-                    if (n & 0xFFFFFFFF00000000L)
-                        result = TOK.uns64Literal;      // unsigned long
-                    else
-                        result = TOK.uns32Literal;
-                }
+                    result = TOK.uns32Literal;
                 break;
 
             case FLAGS.decimal | FLAGS.long_:
@@ -2510,19 +2314,14 @@ class Lexer
                  */
                 if (longsize == 4)
                 {
-                    if (n & 0x8000000000000000L)
-                        overflow();
-                    else if (n & 0xFFFFFFFF_80000000L)
+                    if (n & 0xFFFFFFFF_80000000L)
                         result = TOK.int64Literal;
                     else
-                        result = TOK.int32Literal;      // long
+                        result = TOK.int32Literal;  // long
                 }
                 else
                 {
-                    if (n & 0x8000000000000000L)
-                        overflow();
-                    else
-                        result = TOK.int64Literal;      // long
+                    result = TOK.int64Literal;      // long
                 }
                 break;
 
@@ -3353,6 +3152,11 @@ class Lexer
     }
 }
 
+
+/******************************* Private *****************************************/
+
+private:
+
 /// Support for `__DATE__`, `__TIME__`, and `__TIMESTAMP__`
 private struct TimeStampInfo
 {
@@ -3389,6 +3193,121 @@ private struct TimeStampInfo
     }
 }
 
+private enum LS = 0x2028;       // UTF line separator
+private enum PS = 0x2029;       // UTF paragraph separator
+
+/********************************************
+ * Do our own char maps
+ */
+private static immutable cmtable = ()
+{
+    ubyte[256] table;
+    foreach (const c; 0 .. table.length)
+    {
+        if ('0' <= c && c <= '7')
+            table[c] |= CMoctal;
+        if (c_isxdigit(c))
+            table[c] |= CMhex;
+        if (c_isalnum(c) || c == '_')
+            table[c] |= CMidchar;
+
+        switch (c)
+        {
+            case 'x': case 'X':
+            case 'b': case 'B':
+                table[c] |= CMzerosecond;
+                break;
+
+            case '0': .. case '9':
+            case 'e': case 'E':
+            case 'f': case 'F':
+            case 'l': case 'L':
+            case 'p': case 'P':
+            case 'u': case 'U':
+            case 'i':
+            case '.':
+            case '_':
+                table[c] |= CMzerosecond | CMdigitsecond;
+                break;
+
+            default:
+                break;
+        }
+
+        switch (c)
+        {
+            case '\\':
+            case '\n':
+            case '\r':
+            case 0:
+            case 0x1A:
+            case '\'':
+                break;
+            default:
+                if (!(c & 0x80))
+                    table[c] |= CMsinglechar;
+                break;
+        }
+    }
+    return table;
+}();
+
+private
+{
+    enum CMoctal  = 0x1;
+    enum CMhex    = 0x2;
+    enum CMidchar = 0x4;
+    enum CMzerosecond = 0x8;
+    enum CMdigitsecond = 0x10;
+    enum CMsinglechar = 0x20;
+}
+
+private bool isoctal(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMoctal) != 0;
+}
+
+private bool ishex(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMhex) != 0;
+}
+
+private bool isidchar(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMidchar) != 0;
+}
+
+private bool isZeroSecond(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMzerosecond) != 0;
+}
+
+private bool isDigitSecond(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMdigitsecond) != 0;
+}
+
+private bool issinglechar(const char c) pure @nogc @safe
+{
+    return (cmtable[c] & CMsinglechar) != 0;
+}
+
+private bool c_isxdigit(const int c) pure @nogc @safe
+{
+    return (( c >= '0' && c <= '9') ||
+            ( c >= 'a' && c <= 'f') ||
+            ( c >= 'A' && c <= 'F'));
+}
+
+private bool c_isalnum(const int c) pure @nogc @safe
+{
+    return (( c >= '0' && c <= '9') ||
+            ( c >= 'a' && c <= 'z') ||
+            ( c >= 'A' && c <= 'Z'));
+}
+
+/******************************* Unittest *****************************************/
+
 unittest
 {
     import dmd.console;
@@ -3441,6 +3360,7 @@ unittest
 
     diagnosticHandler = null;
 }
+
 unittest
 {
     import dmd.console;
@@ -3510,3 +3430,59 @@ unittest
 
     diagnosticHandler = null;
 }
+
+unittest
+{
+    //printf("lexer.unittest\n");
+    /* Not much here, just trying things out.
+     */
+    string text = "int"; // We rely on the implicit null-terminator
+    scope Lexer lex1 = new Lexer(null, text.ptr, 0, text.length, 0, 0);
+    TOK tok;
+    tok = lex1.nextToken();
+    //printf("tok == %s, %d, %d\n", Token::toChars(tok), tok, TOK.int32);
+    assert(tok == TOK.int32);
+    tok = lex1.nextToken();
+    assert(tok == TOK.endOfFile);
+    tok = lex1.nextToken();
+    assert(tok == TOK.endOfFile);
+    tok = lex1.nextToken();
+    assert(tok == TOK.endOfFile);
+}
+
+unittest
+{
+    // We don't want to see Lexer error output during these tests.
+    uint errors = global.startGagging();
+    scope(exit) global.endGagging(errors);
+
+    // Test malformed input: even malformed input should end in a TOK.endOfFile.
+    static immutable char[][] testcases =
+    [   // Testcase must end with 0 or 0x1A.
+        [0], // not malformed, but pathological
+        ['\'', 0],
+        ['\'', 0x1A],
+        ['{', '{', 'q', '{', 0],
+        [0xFF, 0],
+        [0xFF, 0x80, 0],
+        [0xFF, 0xFF, 0],
+        [0xFF, 0xFF, 0],
+        ['x', '"', 0x1A],
+    ];
+
+    foreach (testcase; testcases)
+    {
+        scope Lexer lex2 = new Lexer(null, testcase.ptr, 0, testcase.length-1, 0, 0);
+        TOK tok = lex2.nextToken();
+        size_t iterations = 1;
+        while ((tok != TOK.endOfFile) && (iterations++ < testcase.length))
+        {
+            tok = lex2.nextToken();
+        }
+        assert(tok == TOK.endOfFile);
+        tok = lex2.nextToken();
+        assert(tok == TOK.endOfFile);
+    }
+}
+
+
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index fefad2823fe..28978776e03 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -206,6 +206,32 @@ string MODtoString(MOD mod) nothrow pure
     }
 }
 
+/*************************************************
+ * Pick off one of the trust flags from trust,
+ * and return a string representation of it.
+ */
+string trustToString(TRUST trust) pure nothrow @nogc @safe
+{
+    final switch (trust)
+    {
+    case TRUST.default_:
+        return null;
+    case TRUST.system:
+        return "@system";
+    case TRUST.trusted:
+        return "@trusted";
+    case TRUST.safe:
+        return "@safe";
+    }
+}
+
+unittest
+{
+    assert(trustToString(TRUST.default_) == "");
+    assert(trustToString(TRUST.system) == "@system");
+    assert(trustToString(TRUST.trusted) == "@trusted");
+    assert(trustToString(TRUST.safe) == "@safe");
+}
 
 /************************************
  * Convert MODxxxx to STCxxx
@@ -400,7 +426,7 @@ extern (C++) abstract class Type : ASTNode
     extern (C++) __gshared Type[TMAX] basic;
 
     extern (D) __gshared StringTable!Type stringtable;
-    extern (D) private __gshared ubyte[TMAX] sizeTy = ()
+    extern (D) private static immutable ubyte[TMAX] sizeTy = ()
         {
             ubyte[TMAX] sizeTy = __traits(classInstanceSize, TypeBasic);
             sizeTy[Tsarray] = __traits(classInstanceSize, TypeSArray);
@@ -2604,6 +2630,10 @@ extern (C++) abstract class Type : ASTNode
             default:
                 assert(0);
             }
+            // @@@DEPRECATED_2.117@@@
+            // Deprecated in 2.097 - Can be made an error from 2.117.
+            // The deprecation period is longer than usual as `cfloat`,
+            // `cdouble`, and `creal` were quite widely used.
             if (t.iscomplex())
             {
                 deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
@@ -4219,9 +4249,9 @@ extern (C++) final class TypeFunction : TypeNext
         this.trust = TRUST.default_;
         if (stc & STC.safe)
             this.trust = TRUST.safe;
-        if (stc & STC.system)
+        else if (stc & STC.system)
             this.trust = TRUST.system;
-        if (stc & STC.trusted)
+        else if (stc & STC.trusted)
             this.trust = TRUST.trusted;
     }
 
@@ -6346,7 +6376,7 @@ extern (C++) final class TypeClass : Type
         /* Conversion derived to const(base)
          */
         int offset = 0;
-        if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
+        if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod))
         {
             // Disallow:
             //  derived to base
@@ -7253,10 +7283,9 @@ void attributesApply(const TypeFunction tf, void delegate(string) dg, TRUSTforma
 
     if (trustAttrib == TRUST.default_)
     {
-        if (trustFormat == TRUSTformatSystem)
-            trustAttrib = TRUST.system;
-        else
-            return; // avoid calling with an empty string
+        if (trustFormat != TRUSTformatSystem)
+            return;
+        trustAttrib = TRUST.system; // avoid calling with an empty string
     }
 
     dg(trustToString(trustAttrib));
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index f25e779a689..d6735d45099 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -84,20 +84,6 @@ public:
             }
             f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
         }
-        else if (fd.ident == Id._d_delstruct)
-        {
-            // In expressionsem.d, `delete s` was lowererd to `_d_delstruct(s)`.
-            // The following code handles the call like the original expression,
-            // so the error is menaningful to the user.
-            if (f.setGC())
-            {
-                e.error("cannot use `delete` in `@nogc` %s `%s`", f.kind(),
-                    f.toPrettyChars());
-                err = true;
-                return;
-            }
-            f.printGCUsage(e.loc, "`delete` requires the GC");
-        }
     }
 
     override void visit(ArrayLiteralExp e)
@@ -158,32 +144,8 @@ public:
                 return; // delete for scope allocated class object
         }
 
-        Type tb = e.e1.type.toBasetype();
-        AggregateDeclaration ad = null;
-        switch (tb.ty)
-        {
-        case Tclass:
-            ad = (cast(TypeClass)tb).sym;
-            break;
-
-        case Tpointer:
-            tb = (cast(TypePointer)tb).next.toBasetype();
-            if (tb.ty == Tstruct)
-                ad = (cast(TypeStruct)tb).sym;
-            break;
-
-        default:
-            break;
-        }
-
-        if (f.setGC())
-        {
-            e.error("cannot use `delete` in `@nogc` %s `%s`",
-                f.kind(), f.toPrettyChars());
-            err = true;
-            return;
-        }
-        f.printGCUsage(e.loc, "`delete` requires the GC");
+        // Semantic should have already handled this case.
+        assert(0);
     }
 
     override void visit(IndexExp e)
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 5d6128b014c..01708d65655 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -272,31 +272,17 @@ private Expression checkAliasThisForRhs(AggregateDeclaration ad, Scope* sc, BinE
  */
 Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
 {
-    extern (C++) final class OpOverload : Visitor
-    {
-        alias visit = Visitor.visit;
-    public:
-        Scope* sc;
-        EXP* pop;
-        Expression result;
-
-        extern (D) this(Scope* sc, EXP* pop)
-        {
-            this.sc = sc;
-            this.pop = pop;
-        }
-
-        override void visit(Expression e)
+        Expression visit(Expression e)
         {
             assert(0);
         }
 
-        override void visit(UnaExp e)
+        Expression visitUna(UnaExp e)
         {
             //printf("UnaExp::op_overload() (%s)\n", e.toChars());
-            if (e.e1.op == EXP.array)
+            Expression result;
+            if (auto ae = e.e1.isArrayExp())
             {
-                ArrayExp ae = cast(ArrayExp)e.e1;
                 ae.e1 = ae.e1.expressionSemantic(sc);
                 ae.e1 = resolveProperties(sc, ae.e1);
                 Expression ae1old = ae.e1;
@@ -304,15 +290,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 IntervalExp ie = null;
                 if (maybeSlice && ae.arguments.dim)
                 {
-                    assert((*ae.arguments)[0].op == EXP.interval);
-                    ie = cast(IntervalExp)(*ae.arguments)[0];
+                    ie = (*ae.arguments)[0].isIntervalExp();
                 }
                 while (true)
                 {
                     if (ae.e1.op == EXP.error)
                     {
-                        result = ae.e1;
-                        return;
+                        return ae.e1;
                     }
                     Expression e0 = null;
                     Expression ae1save = ae.e1;
@@ -328,7 +312,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (!result) // op(a[i..j]) might be: a.opSliceUnary!(op)(i, j)
                             goto Lfallback;
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         /* Rewrite op(a[arguments]) as:
                          *      a.opIndexUnary!(op)(arguments)
                          */
@@ -342,8 +326,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                             result = result.expressionSemantic(sc);
                         if (result)
                         {
-                            result = Expression.combine(e0, result);
-                            return;
+                            return Expression.combine(e0, result);
                         }
                     }
                 Lfallback:
@@ -352,7 +335,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         // Deal with $
                         result = resolveOpDollar(sc, ae, ie, &e0);
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         /* Rewrite op(a[i..j]) as:
                          *      a.opSliceUnary!(op)(i, j)
                          */
@@ -367,7 +350,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         result = new CallExp(e.loc, result, a);
                         result = result.expressionSemantic(sc);
                         result = Expression.combine(e0, result);
-                        return;
+                        return result;
                     }
                     // Didn't find it. Forward to aliasthis
                     if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@@ -388,8 +371,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
             e.e1 = resolveProperties(sc, e.e1);
             if (e.e1.op == EXP.error)
             {
-                result = e.e1;
-                return;
+                return e.e1;
             }
             AggregateDeclaration ad = isAggregate(e.e1.type);
             if (ad)
@@ -405,7 +387,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
                     result = new CallExp(e.loc, result);
                     result = result.expressionSemantic(sc);
-                    return;
+                    return result;
                 }
                 // D1-style operator overloads, deprecated
                 if (e.op != EXP.prePlusPlus && e.op != EXP.preMinusMinus)
@@ -420,7 +402,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
                         // Rewrite +e1 as e1.add()
                         result = build_overload(e.loc, sc, e.e1, null, fd);
-                        return;
+                        return result;
                     }
                 }
                 // Didn't find it. Forward to aliasthis
@@ -434,12 +416,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     UnaExp ue = cast(UnaExp)e.copy();
                     ue.e1 = e1;
                     result = ue.trySemantic(sc);
-                    return;
+                    return result;
                 }
             }
+            return result;
         }
 
-        override void visit(ArrayExp ae)
+        Expression visitArray(ArrayExp ae)
         {
             //printf("ArrayExp::op_overload() (%s)\n", ae.toChars());
             ae.e1 = ae.e1.expressionSemantic(sc);
@@ -449,15 +432,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
             IntervalExp ie = null;
             if (maybeSlice && ae.arguments.dim)
             {
-                assert((*ae.arguments)[0].op == EXP.interval);
-                ie = cast(IntervalExp)(*ae.arguments)[0];
+                ie = (*ae.arguments)[0].isIntervalExp();
             }
+            Expression result;
             while (true)
             {
                 if (ae.e1.op == EXP.error)
                 {
-                    result = ae.e1;
-                    return;
+                    return ae.e1;
                 }
                 Expression e0 = null;
                 Expression ae1save = ae.e1;
@@ -475,14 +457,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         {
                             result = new SliceExp(ae.loc, ae.e1, ie);
                             result = result.expressionSemantic(sc);
-                            return;
+                            return result;
                         }
                         // Convert to IndexExp
                         if (ae.arguments.dim == 1)
                         {
                             result = new IndexExp(ae.loc, ae.e1, (*ae.arguments)[0]);
                             result = result.expressionSemantic(sc);
-                            return;
+                            return result;
                         }
                     }
                     break;
@@ -494,7 +476,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     if (!result) // a[i..j] might be: a.opSlice(i, j)
                         goto Lfallback;
                     if (result.op == EXP.error)
-                        return;
+                        return result;
                     /* Rewrite e1[arguments] as:
                      *      e1.opIndex(arguments)
                      */
@@ -507,8 +489,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         result = result.expressionSemantic(sc);
                     if (result)
                     {
-                        result = Expression.combine(e0, result);
-                        return;
+                        return Expression.combine(e0, result);
                     }
                 }
             Lfallback:
@@ -517,7 +498,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     result = new SliceExp(ae.loc, ae.e1, ie);
                     result = result.expressionSemantic(sc);
                     result = Expression.combine(e0, result);
-                    return;
+                    return result;
                 }
                 if (maybeSlice && search_function(ad, Id.slice))
                 {
@@ -529,7 +510,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (!e0 && !search_function(ad, Id.dollar)) {
                             ae.loc.errorSupplemental("Aggregate declaration '%s' does not define 'opDollar'", ae.e1.toChars());
                         }
-                        return;
+                        return result;
                     }
                     /* Rewrite a[i..j] as:
                      *      a.opSlice(i, j)
@@ -544,7 +525,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     result = new CallExp(ae.loc, result, a);
                     result = result.expressionSemantic(sc);
                     result = Expression.combine(e0, result);
-                    return;
+                    return result;
                 }
                 // Didn't find it. Forward to aliasthis
                 if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@@ -561,15 +542,17 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
             }
             ae.e1 = ae1old; // recovery
             ae.lengthVar = null;
+            return result;
         }
 
         /***********************************************
          * This is mostly the same as UnaryExp::op_overload(), but has
          * a different rewrite.
          */
-        override void visit(CastExp e)
+        Expression visitCast(CastExp e)
         {
             //printf("CastExp::op_overload() (%s)\n", e.toChars());
+            Expression result;
             AggregateDeclaration ad = isAggregate(e.e1.type);
             if (ad)
             {
@@ -586,8 +569,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (fd.isFuncDeclaration())
                         {
                             // Rewrite as:  e1.opCast()
-                            result = build_overload(e.loc, sc, e.e1, null, fd);
-                            return;
+                            return build_overload(e.loc, sc, e.e1, null, fd);
                         }
                     }
                     auto tiargs = new Objects();
@@ -595,7 +577,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     result = new DotTemplateInstanceExp(e.loc, e.e1, fd.ident, tiargs);
                     result = new CallExp(e.loc, result);
                     result = result.expressionSemantic(sc);
-                    return;
+                    return result;
                 }
                 // Didn't find it. Forward to aliasthis
                 if (ad.aliasthis && !isRecursiveAliasThis(e.att1, e.e1.type))
@@ -608,13 +590,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         result = e.copy();
                         (cast(UnaExp)result).e1 = e1;
                         result = result.op_overload(sc);
-                        return;
+                        return result;
                     }
                 }
             }
+            return result;
         }
 
-        override void visit(BinExp e)
+        Expression visitBin(BinExp e)
         {
             //printf("BinExp::op_overload() (%s)\n", e.toChars());
             Identifier id = opId(e);
@@ -635,7 +618,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                      (sd.hasBlitAssign && !e.e2.isLvalue())))
                 {
                     /* This is bitwise struct assignment. */
-                    return;
+                    return null;
                 }
             }
             Dsymbol s = null;
@@ -645,7 +628,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
             {
                 // Bug4099 fix
                 if (ad1 && search_function(ad1, Id.opUnary))
-                    return;
+                    return null;
             }
             if (e.op != EXP.equal && e.op != EXP.notEqual && e.op != EXP.assign && e.op != EXP.plusPlus && e.op != EXP.minusMinus)
             {
@@ -657,8 +640,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     if (s && !s.isTemplateDeclaration())
                     {
                         e.e1.error("`%s.opBinary` isn't a template", e.e1.toChars());
-                        result = ErrorExp.get();
-                        return;
+                        return ErrorExp.get();
                     }
                 }
                 if (ad2)
@@ -667,8 +649,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     if (s_r && !s_r.isTemplateDeclaration())
                     {
                         e.e2.error("`%s.opBinaryRight` isn't a template", e.e2.toChars());
-                        result = ErrorExp.get();
-                        return;
+                        return ErrorExp.get();
                     }
                     if (s_r && s_r == s) // https://issues.dlang.org/show_bug.cgi?id=12778
                         s_r = null;
@@ -735,8 +716,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
                     if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
                     {
-                        result = ErrorExp.get();
-                        return;
+                        return ErrorExp.get();
                     }
                 }
                 FuncDeclaration lastf = m.lastf;
@@ -745,8 +725,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     functionResolve(m, s_r, e.loc, sc, tiargs, e.e2.type, &args1);
                     if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
                     {
-                        result = ErrorExp.get();
-                        return;
+                        return ErrorExp.get();
                     }
                 }
                 if (m.count > 1)
@@ -766,19 +745,18 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     // as unary, but it's implemented as a binary.
                     // Rewrite (e1 ++ e2) as e1.postinc()
                     // Rewrite (e1 -- e2) as e1.postdec()
-                    result = build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
+                    return build_overload(e.loc, sc, e.e1, null, m.lastf ? m.lastf : s);
                 }
                 else if (lastf && m.lastf == lastf || !s_r && m.last == MATCH.nomatch)
                 {
                     // Rewrite (e1 op e2) as e1.opfunc(e2)
-                    result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
+                    return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
                 }
                 else
                 {
                     // Rewrite (e1 op e2) as e2.opfunc_r(e1)
-                    result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
+                    return build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s_r);
                 }
-                return;
             }
         L1:
             version (all)
@@ -820,8 +798,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                             functionResolve(m, s_r, e.loc, sc, tiargs, e.e1.type, &args2);
                             if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
                             {
-                                result = ErrorExp.get();
-                                return;
+                                return ErrorExp.get();
                             }
                         }
                         FuncDeclaration lastf = m.lastf;
@@ -830,8 +807,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                             functionResolve(m, s, e.loc, sc, tiargs, e.e2.type, &args1);
                             if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
                             {
-                                result = ErrorExp.get();
-                                return;
+                                return ErrorExp.get();
                             }
                         }
                         if (m.count > 1)
@@ -847,27 +823,26 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         if (lastf && m.lastf == lastf || !s && m.last == MATCH.nomatch)
                         {
                             // Rewrite (e1 op e2) as e1.opfunc_r(e2)
-                            result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
+                            return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s_r);
                         }
                         else
                         {
                             // Rewrite (e1 op e2) as e2.opfunc(e1)
-                            result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
+                            Expression result = build_overload(e.loc, sc, e.e2, e.e1, m.lastf ? m.lastf : s);
                             // When reversing operands of comparison operators,
                             // need to reverse the sense of the op
                             if (pop)
                                 *pop = reverseRelation(e.op);
+                            return result;
                         }
-                        return;
                     }
                 }
             }
 
-            Expression tempResult;
+            Expression rewrittenLhs;
             if (!(e.op == EXP.assign && ad2 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
             {
-                result = checkAliasThisForLhs(ad1, sc, e);
-                if (result)
+                if (Expression result = checkAliasThisForLhs(ad1, sc, e))
                 {
                     /* https://issues.dlang.org/show_bug.cgi?id=19441
                      *
@@ -880,43 +855,42 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                      * one of the members, hence the `ad1.fields.dim == 2 && ad1.vthis`
                      * condition.
                      */
-                    if (e.op != EXP.assign || e.e1.op == EXP.type)
-                        return;
+                    if (result.op != EXP.assign)
+                        return result;     // i.e: Rewrote `e1 = e2` -> `e1(e2)`
+
+                    auto ae = result.isAssignExp();
+                    if (ae.e1.op != EXP.dotVariable)
+                        return result;     // i.e: Rewrote `e1 = e2` -> `e1() = e2`
 
-                    if (ad1.fields.dim == 1 || (ad1.fields.dim == 2 && ad1.vthis))
+                    auto dve = ae.e1.isDotVarExp();
+                    if (auto ad = dve.var.isMember2())
                     {
-                        auto var = ad1.aliasthis.sym.isVarDeclaration();
-                        if (var && var.type == ad1.fields[0].type)
-                            return;
-
-                        auto func = ad1.aliasthis.sym.isFuncDeclaration();
-                        auto tf = cast(TypeFunction)(func.type);
-                        if (tf.isref && ad1.fields[0].type == tf.next)
-                            return;
+                        // i.e: Rewrote `e1 = e2` -> `e1.some.var = e2`
+                        // Ensure that `var` is the only field member in `ad`
+                        if (ad.fields.dim == 1 || (ad.fields.dim == 2 && ad.vthis))
+                        {
+                            if (dve.var == ad.aliasthis.sym)
+                                return result;
+                        }
                     }
-                    tempResult = result;
+                    rewrittenLhs = ae.e1;
                 }
             }
             if (!(e.op == EXP.assign && ad1 && ad1 == ad2)) // https://issues.dlang.org/show_bug.cgi?id=2943
             {
-                result = checkAliasThisForRhs(ad2, sc, e);
-                if (result)
-                    return;
+                if (Expression result = checkAliasThisForRhs(ad2, sc, e))
+                    return result;
             }
-
-            // @@@DEPRECATED_2019-02@@@
-            // 1. Deprecation for 1 year
-            // 2. Turn to error after
-            if (tempResult)
+            if (rewrittenLhs)
             {
-                // move this line where tempResult is assigned to result and turn to error when derecation period is over
-                e.deprecation("Cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`", e.e1.toChars(), ad1.toChars(), (cast(BinExp)tempResult).e1.toChars());
-                // delete this line when deprecation period is over
-                result = tempResult;
+                e.error("cannot use `alias this` to partially initialize variable `%s` of type `%s`. Use `%s`",
+                        e.e1.toChars(), ad1.toChars(), rewrittenLhs.toChars());
+                return ErrorExp.get();
             }
+            return null;
         }
 
-        override void visit(EqualExp e)
+        Expression visitEqual(EqualExp e)
         {
             //printf("EqualExp::op_overload() (%s)\n", e.toChars());
             Type t1 = e.e1.type.toBasetype();
@@ -929,7 +903,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
             if ((t1.ty == Tarray || t1.ty == Tsarray) &&
                 (t2.ty == Tarray || t2.ty == Tsarray))
             {
-                return;
+                return null;
             }
 
             /* Check for class equality with null literal or typeof(null).
@@ -940,14 +914,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 e.error("use `%s` instead of `%s` when comparing with `null`",
                     EXPtoString(e.op == EXP.equal ? EXP.identity : EXP.notIdentity).ptr,
                     EXPtoString(e.op).ptr);
-                result = ErrorExp.get();
-                return;
+                return ErrorExp.get();
             }
             if (t1.ty == Tclass && t2.ty == Tnull ||
                 t1.ty == Tnull && t2.ty == Tclass)
             {
                 // Comparing a class with typeof(null) should not call opEquals
-                return;
+                return null;
             }
 
             /* Check for class equality.
@@ -973,26 +946,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     if (cd2.isInterfaceDeclaration())
                         e2x = new CastExp(e.loc, e.e2, t2.isMutable() ? to : to.constOf());
 
-                    result = new IdentifierExp(e.loc, Id.empty);
+                    Expression result = new IdentifierExp(e.loc, Id.empty);
                     result = new DotIdExp(e.loc, result, Id.object);
                     result = new DotIdExp(e.loc, result, Id.eq);
                     result = new CallExp(e.loc, result, e1x, e2x);
                     if (e.op == EXP.notEqual)
                         result = new NotExp(e.loc, result);
                     result = result.expressionSemantic(sc);
-                    return;
+                    return result;
                 }
             }
 
-            result = compare_overload(e, sc, Id.eq, null);
-            if (result)
+            if (Expression result = compare_overload(e, sc, Id.eq, null))
             {
                 if (lastComma(result).op == EXP.call && e.op == EXP.notEqual)
                 {
                     result = new NotExp(result.loc, result);
                     result = result.expressionSemantic(sc);
                 }
-                return;
+                return result;
             }
 
             /* Check for pointer equality.
@@ -1008,27 +980,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                  * as the backend input.
                  */
                 auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
-                result = new IdentityExp(op2, e.loc, e.e1, e.e2);
-                result = result.expressionSemantic(sc);
-                return;
+                Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
+                return r.expressionSemantic(sc);
             }
 
             /* Check for struct equality without opEquals.
              */
             if (t1.ty == Tstruct && t2.ty == Tstruct)
             {
-                auto sd = (cast(TypeStruct)t1).sym;
-                if (sd != (cast(TypeStruct)t2).sym)
-                    return;
+                auto sd = t1.isTypeStruct().sym;
+                if (sd != t2.isTypeStruct().sym)
+                    return null;
 
                 import dmd.clone : needOpEquals;
                 if (!global.params.fieldwise && !needOpEquals(sd))
                 {
                     // Use bitwise equality.
                     auto op2 = e.op == EXP.equal ? EXP.identity : EXP.notIdentity;
-                    result = new IdentityExp(op2, e.loc, e.e1, e.e2);
-                    result = result.expressionSemantic(sc);
-                    return;
+                    Expression r = new IdentityExp(op2, e.loc, e.e1, e.e2);
+                    return r.expressionSemantic(sc);
                 }
 
                 /* Do memberwise equality.
@@ -1042,10 +1012,10 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                  * also compare the parent class's equality. Otherwise, compares
                  * the identity of parent context through void*.
                  */
-                if (e.att1 && t1.equivalent(e.att1)) return;
-                if (e.att2 && t2.equivalent(e.att2)) return;
+                if (e.att1 && t1.equivalent(e.att1)) return null;
+                if (e.att2 && t2.equivalent(e.att2)) return null;
 
-                e = cast(EqualExp)e.copy();
+                e = e.copy().isEqualExp();
                 if (!e.att1) e.att1 = t1;
                 if (!e.att2) e.att2 = t2;
                 e.e1 = new DotIdExp(e.loc, e.e1, Id._tupleof);
@@ -1053,38 +1023,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
 
                 auto sc2 = sc.push();
                 sc2.flags |= SCOPE.noaccesscheck;
-                result = e.expressionSemantic(sc2);
+                Expression r = e.expressionSemantic(sc2);
                 sc2.pop();
 
                 /* https://issues.dlang.org/show_bug.cgi?id=15292
                  * if the rewrite result is same with the original,
                  * the equality is unresolvable because it has recursive definition.
                  */
-                if (result.op == e.op &&
-                    (cast(EqualExp)result).e1.type.toBasetype() == t1)
+                if (r.op == e.op &&
+                    r.isEqualExp().e1.type.toBasetype() == t1)
                 {
                     e.error("cannot compare `%s` because its auto generated member-wise equality has recursive definition",
                         t1.toChars());
-                    result = ErrorExp.get();
+                    return ErrorExp.get();
                 }
-                return;
+                return r;
             }
 
             /* Check for tuple equality.
              */
             if (e.e1.op == EXP.tuple && e.e2.op == EXP.tuple)
             {
-                auto tup1 = cast(TupleExp)e.e1;
-                auto tup2 = cast(TupleExp)e.e2;
+                auto tup1 = e.e1.isTupleExp();
+                auto tup2 = e.e2.isTupleExp();
                 size_t dim = tup1.exps.dim;
                 if (dim != tup2.exps.dim)
                 {
                     e.error("mismatched tuple lengths, `%d` and `%d`",
                         cast(int)dim, cast(int)tup2.exps.dim);
-                    result = ErrorExp.get();
-                    return;
+                    return ErrorExp.get();
                 }
 
+                Expression result;
                 if (dim == 0)
                 {
                     // zero-length tuple comparison should always return true or false.
@@ -1112,25 +1082,25 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 result = Expression.combine(tup1.e0, tup2.e0, result);
                 result = result.expressionSemantic(sc);
 
-                return;
+                return result;
             }
+            return null;
         }
 
-        override void visit(CmpExp e)
+        Expression visitCmp(CmpExp e)
         {
             //printf("CmpExp:: () (%s)\n", e.toChars());
-            result = compare_overload(e, sc, Id.cmp, pop);
+            return compare_overload(e, sc, Id.cmp, pop);
         }
 
         /*********************************
          * Operator overloading for op=
          */
-        override void visit(BinAssignExp e)
+        Expression visitBinAssign(BinAssignExp e)
         {
             //printf("BinAssignExp::op_overload() (%s)\n", e.toChars());
-            if (e.e1.op == EXP.array)
+            if (auto ae = e.e1.isArrayExp())
             {
-                ArrayExp ae = cast(ArrayExp)e.e1;
                 ae.e1 = ae.e1.expressionSemantic(sc);
                 ae.e1 = resolveProperties(sc, ae.e1);
                 Expression ae1old = ae.e1;
@@ -1138,15 +1108,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 IntervalExp ie = null;
                 if (maybeSlice && ae.arguments.dim)
                 {
-                    assert((*ae.arguments)[0].op == EXP.interval);
-                    ie = cast(IntervalExp)(*ae.arguments)[0];
+                    ie = (*ae.arguments)[0].isIntervalExp();
                 }
                 while (true)
                 {
                     if (ae.e1.op == EXP.error)
                     {
-                        result = ae.e1;
-                        return;
+                        return ae.e1;
                     }
                     Expression e0 = null;
                     Expression ae1save = ae.e1;
@@ -1158,14 +1126,14 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     if (search_function(ad, Id.opIndexOpAssign))
                     {
                         // Deal with $
-                        result = resolveOpDollar(sc, ae, &e0);
+                        Expression result = resolveOpDollar(sc, ae, &e0);
                         if (!result) // (a[i..j] op= e2) might be: a.opSliceOpAssign!(op)(e2, i, j)
                             goto Lfallback;
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         result = e.e2.expressionSemantic(sc);
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         e.e2 = result;
                         /* Rewrite a[arguments] op= e2 as:
                          *      a.opIndexOpAssign!(op)(e2, arguments)
@@ -1181,20 +1149,19 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                             result = result.expressionSemantic(sc);
                         if (result)
                         {
-                            result = Expression.combine(e0, result);
-                            return;
+                            return Expression.combine(e0, result);
                         }
                     }
                 Lfallback:
                     if (maybeSlice && search_function(ad, Id.opSliceOpAssign))
                     {
                         // Deal with $
-                        result = resolveOpDollar(sc, ae, ie, &e0);
+                        Expression result = resolveOpDollar(sc, ae, ie, &e0);
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         result = e.e2.expressionSemantic(sc);
                         if (result.op == EXP.error)
-                            return;
+                            return result;
                         e.e2 = result;
                         /* Rewrite (a[i..j] op= e2) as:
                          *      a.opSliceOpAssign!(op)(e2, i, j)
@@ -1211,7 +1178,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         result = new CallExp(e.loc, result, a);
                         result = result.expressionSemantic(sc);
                         result = Expression.combine(e0, result);
-                        return;
+                        return result;
                     }
                     // Didn't find it. Forward to aliasthis
                     if (ad.aliasthis && !isRecursiveAliasThis(ae.att1, ae.e1.type))
@@ -1228,14 +1195,13 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 ae.e1 = ae1old; // recovery
                 ae.lengthVar = null;
             }
-            result = e.binSemanticProp(sc);
+            Expression result = e.binSemanticProp(sc);
             if (result)
-                return;
+                return result;
             // Don't attempt 'alias this' if an error occurred
             if (e.e1.type.ty == Terror || e.e2.type.ty == Terror)
             {
-                result = ErrorExp.get();
-                return;
+                return ErrorExp.get();
             }
             Identifier id = opId(e);
             Expressions args2;
@@ -1250,8 +1216,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 if (s && !s.isTemplateDeclaration())
                 {
                     e.error("`%s.opOpAssign` isn't a template", e.e1.toChars());
-                    result = ErrorExp.get();
-                    return;
+                    return ErrorExp.get();
                 }
             }
             // Set tiargs, the template argument list, which will be the operator string
@@ -1290,8 +1255,7 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     functionResolve(m, s, e.loc, sc, tiargs, e.e1.type, &args2);
                     if (m.lastf && (m.lastf.errors || m.lastf.semantic3Errors))
                     {
-                        result = ErrorExp.get();
-                        return;
+                        return ErrorExp.get();
                     }
                 }
                 if (m.count > 1)
@@ -1306,23 +1270,38 @@ Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     m.lastf = null;
                 }
                 // Rewrite (e1 op e2) as e1.opOpAssign(e2)
-                result = build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
-                return;
+                return build_overload(e.loc, sc, e.e1, e.e2, m.lastf ? m.lastf : s);
             }
         L1:
             result = checkAliasThisForLhs(ad1, sc, e);
             if (result || !s) // no point in trying Rhs alias-this if there's no overload of any kind in lhs
-                return;
+                return result;
 
-            result = checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
+            return checkAliasThisForRhs(isAggregate(e.e2.type), sc, e);
         }
-    }
 
     if (pop)
         *pop = e.op;
-    scope OpOverload v = new OpOverload(sc, pop);
-    e.accept(v);
-    return v.result;
+
+    switch (e.op)
+    {
+        case EXP.cast_         : return visitCast(e.isCastExp());
+        case EXP.array         : return visitArray(e.isArrayExp());
+
+        case EXP.notEqual      :
+        case EXP.equal         : return visitEqual(e.isEqualExp());
+
+        case EXP.lessOrEqual   :
+        case EXP.greaterThan   :
+        case EXP.greaterOrEqual:
+        case EXP.lessThan      : return visitCmp(cast(CmpExp)e);
+
+        default:
+            if (auto ex = e.isBinAssignExp()) return visitBinAssign(ex);
+            if (auto ex = e.isBinExp())       return visitBin(ex);
+            if (auto ex = e.isUnaExp())       return visitUna(ex);
+            return visit(e);
+    }
 }
 
 /******************************************
@@ -1505,8 +1484,8 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
         case Tclass:
         case Tstruct:
         {
-            AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
-                                                         : (cast(TypeStruct)tab).sym;
+            AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
+                                                         : tab.isTypeStruct().sym;
             if (!sliced)
             {
                 sapply = search_function(ad, isForeach ? Id.apply : Id.applyReverse);
@@ -1547,9 +1526,9 @@ bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
         }
 
         case Tdelegate:        // https://dlang.org/spec/statement.html#foreach_over_delegates
-            if (aggr.op == EXP.delegate_)
+            if (auto de = aggr.isDelegateExp())
             {
-                sapply = (cast(DelegateExp)aggr).func;
+                sapply = de.func;
             }
             break;
 
@@ -1600,7 +1579,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
         else
         {
             assert(tab.ty == Tdelegate && fes.aggr.op == EXP.delegate_);
-            ethis = (cast(DelegateExp)fes.aggr).e1;
+            ethis = fes.aggr.isDelegateExp().e1;
         }
 
         /* Look for like an
@@ -1613,7 +1592,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
             if (fdapply)
             {
                 // Fill in any missing types on foreach parameters[]
-                matchParamsToOpApply(cast(TypeFunction)fdapply.type, fes.parameters, true);
+                matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true);
                 sapply = fdapply;
                 return true;
             }
@@ -1649,7 +1628,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
 
     case Taarray:
         {
-            TypeAArray taa = cast(TypeAArray)tab;
+            TypeAArray taa = tab.isTypeAArray();
             if (fes.parameters.dim == 2)
             {
                 if (!p.type)
@@ -1672,8 +1651,8 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
     case Tclass:
     case Tstruct:
     {
-        AggregateDeclaration ad = (tab.ty == Tclass) ? (cast(TypeClass)tab).sym
-                                                     : (cast(TypeStruct)tab).sym;
+        AggregateDeclaration ad = (tab.ty == Tclass) ? tab.isTypeClass().sym
+                                                     : tab.isTypeStruct().sym;
         if (fes.parameters.dim == 1)
         {
             if (!p.type)
@@ -1697,7 +1676,7 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
                 {
                 }
                 else if (s && s.isDeclaration())
-                    p.type = (cast(Declaration)s).type;
+                    p.type = s.isDeclaration().type;
                 else
                     break;
             }
@@ -1707,9 +1686,12 @@ bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
     }
 
     case Tdelegate:
-        if (!matchParamsToOpApply(cast(TypeFunction)tab.nextOf(), fes.parameters, true))
+    {
+        auto td = tab.isTypeDelegate();
+        if (!matchParamsToOpApply(td.next.isTypeFunction(), fes.parameters, true))
             return false;
         break;
+    }
 
     default:
         break; // ignore error, caught later
@@ -1738,7 +1720,7 @@ private FuncDeclaration findBestOpApplyMatch(Expression ethis, FuncDeclaration f
         auto f = s.isFuncDeclaration();
         if (!f)
             return 0;           // continue
-        auto tf = cast(TypeFunction)f.type;
+        auto tf = f.type.isTypeFunction();
         MATCH m = MATCH.exact;
         if (f.isThis())
         {
@@ -1825,10 +1807,10 @@ private bool matchParamsToOpApply(TypeFunction tf, Parameters* parameters, bool
     /* Get the type of opApply's dg parameter
      */
     Parameter p0 = tf.parameterList[0];
-    if (p0.type.ty != Tdelegate)
+    auto de = p0.type.isTypeDelegate();
+    if (!de)
         return nomatch;
-    TypeFunction tdg = cast(TypeFunction)p0.type.nextOf();
-    assert(tdg.ty == Tfunction);
+    TypeFunction tdg = de.next.isTypeFunction();
 
     /* We now have tdg, the type of the delegate.
      * tdg's parameters must match that of the foreach arglist (i.e. parameters).
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 5b4ebd78223..3653aa8b06b 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -631,13 +631,6 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
     {
         expOptimize(e.thisexp, WANTvalue);
         // Optimize parameters
-        if (e.newargs)
-        {
-            for (size_t i = 0; i < e.newargs.dim; i++)
-            {
-                expOptimize((*e.newargs)[i], WANTvalue);
-            }
-        }
         if (e.arguments)
         {
             for (size_t i = 0; i < e.arguments.dim; i++)
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 63afeb22a4b..e83b326c7e3 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -28,268 +28,6 @@ import dmd.root.rootobject;
 import dmd.root.string;
 import dmd.tokens;
 
-// How multiple declarations are parsed.
-// If 1, treat as C.
-// If 0, treat:
-//      int *p, i;
-// as:
-//      int* p;
-//      int* i;
-private enum CDECLSYNTAX = 0;
-
-// Support C cast syntax:
-//      (type)(expression)
-private enum CCASTSYNTAX = 1;
-
-// Support postfix C array declarations, such as
-//      int a[3][4];
-private enum CARRAYDECL = 1;
-
-/**********************************
- * Set operator precedence for each operator.
- *
- * Used by hdrgen
- */
-immutable PREC[EXP.max + 1] precedence =
-[
-    EXP.type : PREC.expr,
-    EXP.error : PREC.expr,
-    EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
-
-    EXP.typeof_ : PREC.primary,
-    EXP.mixin_ : PREC.primary,
-
-    EXP.import_ : PREC.primary,
-    EXP.dotVariable : PREC.primary,
-    EXP.scope_ : PREC.primary,
-    EXP.identifier : PREC.primary,
-    EXP.this_ : PREC.primary,
-    EXP.super_ : PREC.primary,
-    EXP.int64 : PREC.primary,
-    EXP.float64 : PREC.primary,
-    EXP.complex80 : PREC.primary,
-    EXP.null_ : PREC.primary,
-    EXP.string_ : PREC.primary,
-    EXP.arrayLiteral : PREC.primary,
-    EXP.assocArrayLiteral : PREC.primary,
-    EXP.classReference : PREC.primary,
-    EXP.file : PREC.primary,
-    EXP.fileFullPath : PREC.primary,
-    EXP.line : PREC.primary,
-    EXP.moduleString : PREC.primary,
-    EXP.functionString : PREC.primary,
-    EXP.prettyFunction : PREC.primary,
-    EXP.typeid_ : PREC.primary,
-    EXP.is_ : PREC.primary,
-    EXP.assert_ : PREC.primary,
-    EXP.halt : PREC.primary,
-    EXP.template_ : PREC.primary,
-    EXP.dSymbol : PREC.primary,
-    EXP.function_ : PREC.primary,
-    EXP.variable : PREC.primary,
-    EXP.symbolOffset : PREC.primary,
-    EXP.structLiteral : PREC.primary,
-    EXP.compoundLiteral : PREC.primary,
-    EXP.arrayLength : PREC.primary,
-    EXP.delegatePointer : PREC.primary,
-    EXP.delegateFunctionPointer : PREC.primary,
-    EXP.remove : PREC.primary,
-    EXP.tuple : PREC.primary,
-    EXP.traits : PREC.primary,
-    EXP.default_ : PREC.primary,
-    EXP.overloadSet : PREC.primary,
-    EXP.void_ : PREC.primary,
-    EXP.vectorArray : PREC.primary,
-    EXP._Generic : PREC.primary,
-
-    // post
-    EXP.dotTemplateInstance : PREC.primary,
-    EXP.dotIdentifier : PREC.primary,
-    EXP.dotTemplateDeclaration : PREC.primary,
-    EXP.dot : PREC.primary,
-    EXP.dotType : PREC.primary,
-    EXP.plusPlus : PREC.primary,
-    EXP.minusMinus : PREC.primary,
-    EXP.prePlusPlus : PREC.primary,
-    EXP.preMinusMinus : PREC.primary,
-    EXP.call : PREC.primary,
-    EXP.slice : PREC.primary,
-    EXP.array : PREC.primary,
-    EXP.index : PREC.primary,
-
-    EXP.delegate_ : PREC.unary,
-    EXP.address : PREC.unary,
-    EXP.star : PREC.unary,
-    EXP.negate : PREC.unary,
-    EXP.uadd : PREC.unary,
-    EXP.not : PREC.unary,
-    EXP.tilde : PREC.unary,
-    EXP.delete_ : PREC.unary,
-    EXP.new_ : PREC.unary,
-    EXP.newAnonymousClass : PREC.unary,
-    EXP.cast_ : PREC.unary,
-    EXP.throw_ : PREC.unary,
-
-    EXP.vector : PREC.unary,
-    EXP.pow : PREC.pow,
-
-    EXP.mul : PREC.mul,
-    EXP.div : PREC.mul,
-    EXP.mod : PREC.mul,
-
-    EXP.add : PREC.add,
-    EXP.min : PREC.add,
-    EXP.concatenate : PREC.add,
-
-    EXP.leftShift : PREC.shift,
-    EXP.rightShift : PREC.shift,
-    EXP.unsignedRightShift : PREC.shift,
-
-    EXP.lessThan : PREC.rel,
-    EXP.lessOrEqual : PREC.rel,
-    EXP.greaterThan : PREC.rel,
-    EXP.greaterOrEqual : PREC.rel,
-    EXP.in_ : PREC.rel,
-
-    /* Note that we changed precedence, so that < and != have the same
-     * precedence. This change is in the parser, too.
-     */
-    EXP.equal : PREC.rel,
-    EXP.notEqual : PREC.rel,
-    EXP.identity : PREC.rel,
-    EXP.notIdentity : PREC.rel,
-
-    EXP.and : PREC.and,
-    EXP.xor : PREC.xor,
-    EXP.or : PREC.or,
-
-    EXP.andAnd : PREC.andand,
-    EXP.orOr : PREC.oror,
-
-    EXP.question : PREC.cond,
-
-    EXP.assign : PREC.assign,
-    EXP.construct : PREC.assign,
-    EXP.blit : PREC.assign,
-    EXP.addAssign : PREC.assign,
-    EXP.minAssign : PREC.assign,
-    EXP.concatenateAssign : PREC.assign,
-    EXP.concatenateElemAssign : PREC.assign,
-    EXP.concatenateDcharAssign : PREC.assign,
-    EXP.mulAssign : PREC.assign,
-    EXP.divAssign : PREC.assign,
-    EXP.modAssign : PREC.assign,
-    EXP.powAssign : PREC.assign,
-    EXP.leftShiftAssign : PREC.assign,
-    EXP.rightShiftAssign : PREC.assign,
-    EXP.unsignedRightShiftAssign : PREC.assign,
-    EXP.andAssign : PREC.assign,
-    EXP.orAssign : PREC.assign,
-    EXP.xorAssign : PREC.assign,
-
-    EXP.comma : PREC.expr,
-    EXP.declaration : PREC.expr,
-
-    EXP.interval : PREC.assign,
-];
-
-enum ParseStatementFlags : int
-{
-    semi          = 1,        // empty ';' statements are allowed, but deprecated
-    scope_        = 2,        // start a new scope
-    curly         = 4,        // { } statement is required
-    curlyScope    = 8,        // { } starts a new scope
-    semiOk        = 0x10,     // empty ';' are really ok
-}
-
-struct PrefixAttributes(AST)
-{
-    StorageClass storageClass;
-    AST.Expression depmsg;
-    LINK link;
-    AST.Visibility visibility;
-    bool setAlignment;
-    AST.Expression ealign;
-    AST.Expressions* udas;
-    const(char)* comment;
-}
-
-/// The result of the `ParseLinkage` function
-struct ParsedLinkage(AST)
-{
-    /// What linkage was specified
-    LINK link;
-    /// If `extern(C++, class|struct)`, contains the `class|struct`
-    CPPMANGLE cppmangle;
-    /// If `extern(C++, some.identifier)`, will be the identifiers
-    AST.Identifiers* idents;
-    /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
-    AST.Expressions* identExps;
-}
-
-/*****************************
- * Destructively extract storage class from pAttrs.
- */
-private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
-{
-    StorageClass stc = STC.undefined_;
-    if (pAttrs)
-    {
-        stc = pAttrs.storageClass;
-        pAttrs.storageClass = STC.undefined_;
-    }
-    return stc;
-}
-
-/**************************************
- * dump mixin expansion to file for better debugging
- */
-private bool writeMixin(const(char)[] s, ref Loc loc)
-{
-    if (!global.params.mixinOut)
-        return false;
-
-    OutBuffer* ob = global.params.mixinOut;
-
-    ob.writestring("// expansion at ");
-    ob.writestring(loc.toChars());
-    ob.writenl();
-
-    global.params.mixinLines++;
-
-    loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
-
-    // write by line to create consistent line endings
-    size_t lastpos = 0;
-    for (size_t i = 0; i < s.length; ++i)
-    {
-        // detect LF and CRLF
-        const c = s[i];
-        if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
-        {
-            ob.writestring(s[lastpos .. i]);
-            ob.writenl();
-            global.params.mixinLines++;
-            if (c == '\r')
-                ++i;
-            lastpos = i + 1;
-        }
-    }
-
-    if(lastpos < s.length)
-        ob.writestring(s[lastpos .. $]);
-
-    if (s.length == 0 || s[$-1] != '\n')
-    {
-        ob.writenl(); // ensure empty line after expansion
-        global.params.mixinLines++;
-    }
-    ob.writenl();
-    global.params.mixinLines++;
-
-    return true;
-}
-
 /***********************************************************
  */
 class Parser(AST) : Lexer
@@ -344,80 +82,49 @@ class Parser(AST) : Lexer
         //nextToken();              // start up the scanner
     }
 
+    /++
+     + Parse a module, i.e. the optional `module x.y.z` declaration and all declarations
+     + found in the current file.
+     +
+     + Returns: the list of declarations or an empty list in case of malformed declarations,
+     +          the module declaration will be stored as `this.md` if found
+     +/
     AST.Dsymbols* parseModule()
+    {
+        if (!parseModuleDeclaration())
+            return errorReturn();
+
+        return parseModuleContent();
+    }
+
+    /++
+     + Parse the optional module declaration
+     +
+     + Returns: false if a malformed module declaration was found
+     +/
+    final bool parseModuleDeclaration()
     {
         const comment = token.blockComment;
         bool isdeprecated = false;
         AST.Expression msg = null;
-        AST.Expressions* udas = null;
-        AST.Dsymbols* decldefs;
-        AST.Dsymbol lastDecl = mod; // for attaching ddoc unittests to module decl
-
-        Token* tk;
-        if (skipAttributes(&token, &tk) && tk.value == TOK.module_)
-        {
-            while (token.value != TOK.module_)
-            {
-                switch (token.value)
-                {
-                case TOK.deprecated_:
-                    {
-                        // deprecated (...) module ...
-                        if (isdeprecated)
-                            error("there is only one deprecation attribute allowed for module declaration");
-                        isdeprecated = true;
-                        nextToken();
-                        if (token.value == TOK.leftParenthesis)
-                        {
-                            check(TOK.leftParenthesis);
-                            msg = parseAssignExp();
-                            check(TOK.rightParenthesis);
-                        }
-                        break;
-                    }
-                case TOK.at:
-                    {
-                        AST.Expressions* exps = null;
-                        const stc = parseAttribute(exps);
-                        if (stc & atAttrGroup)
-                        {
-                            error("`@%s` attribute for module declaration is not supported", token.toChars());
-                        }
-                        else
-                        {
-                            udas = AST.UserAttributeDeclaration.concat(udas, exps);
-                        }
-                        if (stc)
-                            nextToken();
-                        break;
-                    }
-                default:
-                    {
-                        error("`module` expected instead of `%s`", token.toChars());
-                        nextToken();
-                        break;
-                    }
-                }
-            }
-        }
 
-        if (udas)
-        {
-            auto a = new AST.Dsymbols();
-            auto udad = new AST.UserAttributeDeclaration(udas, a);
-            mod.userAttribDecl = udad;
-        }
+        // Parse optional module attributes
+        parseModuleAttributes(msg, isdeprecated);
 
-        // ModuleDeclation leads off
+        // ModuleDeclaration leads off
         if (token.value == TOK.module_)
         {
             const loc = token.loc;
-
             nextToken();
+
+            /* parse ModuleFullyQualifiedName
+             * https://dlang.org/spec/module.html#ModuleFullyQualifiedName
+             */
+
             if (token.value != TOK.identifier)
             {
                 error("identifier expected following `module`");
-                goto Lerr;
+                return false;
             }
 
             Identifier[] a;
@@ -430,7 +137,7 @@ class Parser(AST) : Lexer
                 if (token.value != TOK.identifier)
                 {
                     error("identifier expected following `package`");
-                    goto Lerr;
+                    return false;
                 }
                 id = token.ident;
             }
@@ -442,29 +149,115 @@ class Parser(AST) : Lexer
             nextToken();
             addComment(mod, comment);
         }
+        return true;
+    }
 
-        decldefs = parseDeclDefs(0, &lastDecl);
+    /++
+     + Parse the content of a module, i.e. all declarations found until the end of file.
+     +
+     + Returns: the list of declarations or an empty list in case of malformed declarations
+     +/
+    final AST.Dsymbols* parseModuleContent()
+    {
+        AST.Dsymbol lastDecl = mod;
+        AST.Dsymbols* decldefs = parseDeclDefs(0, &lastDecl);
 
         if (token.value == TOK.rightCurly)
         {
             error(token.loc, "unmatched closing brace");
-            goto Lerr;
+            return errorReturn();
         }
 
         if (token.value != TOK.endOfFile)
         {
             error(token.loc, "unrecognized declaration");
-            goto Lerr;
+            return errorReturn();
         }
         return decldefs;
+    }
 
-    Lerr:
+    /++
+     + Skips to the end of the current declaration - denoted by either `;` or EOF
+     +
+     + Returns: An empty list of Dsymbols
+     +/
+    private AST.Dsymbols* errorReturn()
+    {
         while (token.value != TOK.semicolon && token.value != TOK.endOfFile)
             nextToken();
         nextToken();
         return new AST.Dsymbols();
     }
 
+    /**********************************
+     * Parse the ModuleAttributes preceding a module declaration.
+     * ModuleDeclaration:
+     *    ModuleAttributes(opt) module ModuleFullyQualifiedName ;
+     * https://dlang.org/spec/module.html#ModuleAttributes
+     * Params:
+     *  msg = set to the AssignExpression from DeprecatedAttribute https://dlang.org/spec/module.html#DeprecatedAttribute
+     *  isdeprecated = set to true if a DeprecatedAttribute is seen
+     */
+    private
+    void parseModuleAttributes(out AST.Expression msg, out bool isdeprecated)
+    {
+        Token* tk;
+        if (!(skipAttributes(&token, &tk) && tk.value == TOK.module_))
+            return;             // no module attributes
+
+        AST.Expressions* udas = null;
+        while (token.value != TOK.module_)
+        {
+            switch (token.value)
+            {
+            case TOK.deprecated_:
+                {
+                    // deprecated (...) module ...
+                    if (isdeprecated)
+                        error("there is only one deprecation attribute allowed for module declaration");
+                    isdeprecated = true;
+                    nextToken();
+                    if (token.value == TOK.leftParenthesis)
+                    {
+                        check(TOK.leftParenthesis);
+                        msg = parseAssignExp();
+                        check(TOK.rightParenthesis);
+                    }
+                    break;
+                }
+            case TOK.at:
+                {
+                    AST.Expressions* exps = null;
+                    const stc = parseAttribute(exps);
+                    if (stc & atAttrGroup)
+                    {
+                        error("`@%s` attribute for module declaration is not supported", token.toChars());
+                    }
+                    else
+                    {
+                        udas = AST.UserAttributeDeclaration.concat(udas, exps);
+                    }
+                    if (stc)
+                        nextToken();
+                    break;
+                }
+            default:
+                {
+                    error("`module` expected instead of `%s`", token.toChars());
+                    nextToken();
+                    break;
+                }
+            }
+        }
+
+        if (udas)
+        {
+            auto a = new AST.Dsymbols();
+            auto udad = new AST.UserAttributeDeclaration(udas, a);
+            mod.userAttribDecl = udad;
+        }
+    }
+
   final:
 
     /**
@@ -914,7 +707,7 @@ class Parser(AST) : Lexer
                      tk.value == TOK.out_ || tk.value == TOK.do_ || tk.value == TOK.goesTo ||
                      tk.value == TOK.identifier && tk.ident == Id._body))
                 {
-                    // @@@DEPRECATED@@@
+                    // @@@DEPRECATED_2.117@@@
                     // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
                     // Deprecated in 2.097 - Can be removed from 2.117
                     // The deprecation period is longer than usual as `body`
@@ -1418,6 +1211,15 @@ class Parser(AST) : Lexer
      */
     private StorageClass appendStorageClass(StorageClass orig, StorageClass added)
     {
+        void checkConflictSTCGroup(bool at = false)(StorageClass group)
+        {
+            if (added & group && orig & group & ((orig & group) - 1))
+                error(
+                    at ? "conflicting attribute `@%s`"
+                       : "conflicting attribute `%s`",
+                    token.toChars());
+        }
+
         if (orig & added)
         {
             OutBuffer buf;
@@ -1460,24 +1262,9 @@ class Parser(AST) : Lexer
             return orig;
         }
 
-        if (added & (STC.const_ | STC.immutable_ | STC.manifest))
-        {
-            StorageClass u = orig & (STC.const_ | STC.immutable_ | STC.manifest);
-            if (u & (u - 1))
-                error("conflicting attribute `%s`", Token.toChars(token.value));
-        }
-        if (added & (STC.gshared | STC.shared_ | STC.tls))
-        {
-            StorageClass u = orig & (STC.gshared | STC.shared_ | STC.tls);
-            if (u & (u - 1))
-                error("conflicting attribute `%s`", Token.toChars(token.value));
-        }
-        if (added & STC.safeGroup)
-        {
-            StorageClass u = orig & STC.safeGroup;
-            if (u & (u - 1))
-                error("conflicting attribute `@%s`", token.toChars());
-        }
+        checkConflictSTCGroup(STC.const_ | STC.immutable_ | STC.manifest);
+        checkConflictSTCGroup(STC.gshared | STC.shared_ | STC.tls);
+        checkConflictSTCGroup!true(STC.safeGroup);
 
         return orig;
     }
@@ -2885,7 +2672,7 @@ class Parser(AST) : Lexer
         }
         nextToken();
 
-        /* @@@DEPRECATED_2.098@@@
+        /* @@@DEPRECATED_2.108@@@
          * After deprecation period (2.108), remove all code in the version(all) block.
          */
         version (all)
@@ -4614,7 +4401,7 @@ class Parser(AST) : Lexer
                     (tk.value == TOK.leftParenthesis || tk.value == TOK.leftCurly || tk.value == TOK.in_ || tk.value == TOK.out_ || tk.value == TOK.goesTo ||
                      tk.value == TOK.do_ || tk.value == TOK.identifier && tk.ident == Id._body))
                 {
-                    // @@@DEPRECATED@@@
+                    // @@@DEPRECATED_2.117@@@
                     // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
                     // Deprecated in 2.097 - Can be removed from 2.117
                     // The deprecation period is longer than usual as `body`
@@ -5028,12 +4815,18 @@ class Parser(AST) : Lexer
                         // parseAttributes shouldn't have set these variables
                         assert(link == linkage && !setAlignment && ealign is null);
                         auto tpl_ = cast(AST.TemplateDeclaration) s;
-                        assert(tpl_ !is null && tpl_.members.dim == 1);
-                        auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
-                        auto tf = cast(AST.TypeFunction) fd.type;
-                        assert(tf.parameterList.parameters.dim > 0);
-                        auto as = new AST.Dsymbols();
-                        (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
+                        if (tpl_ is null || tpl_.members.dim != 1)
+                        {
+                            error("user-defined attributes are not allowed on `alias` declarations");
+                        }
+                        else
+                        {
+                            auto fd = cast(AST.FuncLiteralDeclaration) (*tpl_.members)[0];
+                            auto tf = cast(AST.TypeFunction) fd.type;
+                            assert(tf.parameterList.parameters.dim > 0);
+                            auto as = new AST.Dsymbols();
+                            (*tf.parameterList.parameters)[0].userAttribDecl = new AST.UserAttributeDeclaration(udas, as);
+                        }
                     }
 
                     v = new AST.AliasDeclaration(loc, ident, s);
@@ -5060,7 +4853,7 @@ class Parser(AST) : Lexer
                         {
                             OutBuffer buf;
                             AST.stcToBuffer(&buf, remStc);
-                            // @@@DEPRECATED_2.093@@@
+                            // @@@DEPRECATED_2.103@@@
                             // Deprecated in 2020-07, can be made an error in 2.103
                             deprecation("storage class `%s` has no effect in type aliases", buf.peekChars());
                         }
@@ -5287,7 +5080,7 @@ class Parser(AST) : Lexer
         case TOK.identifier:
             if (token.ident == Id._body)
             {
-                // @@@DEPRECATED@@@
+                // @@@DEPRECATED_2.117@@@
                 // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
                 // Deprecated in 2.097 - Can be removed from 2.117
                 // The deprecation period is longer than usual as `body`
@@ -7607,7 +7400,7 @@ LagainStc:
             case TOK.identifier:
                 if (t.ident == Id._body)
                 {
-                    // @@@DEPRECATED@@@
+                    // @@@DEPRECATED_2.117@@@
                     // https://github.com/dlang/DIPs/blob/1f5959abe482b1f9094f6484a7d0a3ade77fc2fc/DIPs/accepted/DIP1003.md
                     // Deprecated in 2.097 - Can be removed from 2.117
                     // The deprecation period is longer than usual as `body`
@@ -8652,6 +8445,9 @@ LagainStc:
             break;
 
         case TOK.delete_:
+            // @@@DEPRECATED_2.109@@@
+            // Use of `delete` keyword has been an error since 2.099.
+            // Remove from the parser after 2.109.
             nextToken();
             e = parseUnaryExp();
             e = new AST.DeleteExp(loc, e, false);
@@ -9409,12 +9205,7 @@ LagainStc:
         const loc = token.loc;
 
         nextToken();
-        AST.Expressions* newargs = null;
         AST.Expressions* arguments = null;
-        if (token.value == TOK.leftParenthesis)
-        {
-            newargs = parseArguments();
-        }
 
         // An anonymous nested class starts with "class"
         if (token.value == TOK.class_)
@@ -9444,7 +9235,7 @@ LagainStc:
             }
 
             auto cd = new AST.ClassDeclaration(loc, id, baseclasses, members, false);
-            auto e = new AST.NewAnonClassExp(loc, thisexp, newargs, cd, arguments);
+            auto e = new AST.NewAnonClassExp(loc, thisexp, cd, arguments);
             return e;
         }
 
@@ -9469,7 +9260,7 @@ LagainStc:
             arguments = parseArguments();
         }
 
-        auto e = new AST.NewExp(loc, thisexp, newargs, t, arguments);
+        auto e = new AST.NewExp(loc, thisexp, t, arguments);
         return e;
     }
 
@@ -9519,7 +9310,7 @@ LagainStc:
                 STC.live     |
                 /*STC.future   |*/ // probably should be included
                 STC.disable;
-    }
+}
 
 enum PREC : int
 {
@@ -9541,3 +9332,276 @@ enum PREC : int
     unary,
     primary,
 }
+
+/**********************************
+ * Set operator precedence for each operator.
+ *
+ * Used by hdrgen
+ */
+immutable PREC[EXP.max + 1] precedence =
+[
+    EXP.type : PREC.expr,
+    EXP.error : PREC.expr,
+    EXP.objcClassReference : PREC.expr, // Objective-C class reference, same as EXP.type
+
+    EXP.typeof_ : PREC.primary,
+    EXP.mixin_ : PREC.primary,
+
+    EXP.import_ : PREC.primary,
+    EXP.dotVariable : PREC.primary,
+    EXP.scope_ : PREC.primary,
+    EXP.identifier : PREC.primary,
+    EXP.this_ : PREC.primary,
+    EXP.super_ : PREC.primary,
+    EXP.int64 : PREC.primary,
+    EXP.float64 : PREC.primary,
+    EXP.complex80 : PREC.primary,
+    EXP.null_ : PREC.primary,
+    EXP.string_ : PREC.primary,
+    EXP.arrayLiteral : PREC.primary,
+    EXP.assocArrayLiteral : PREC.primary,
+    EXP.classReference : PREC.primary,
+    EXP.file : PREC.primary,
+    EXP.fileFullPath : PREC.primary,
+    EXP.line : PREC.primary,
+    EXP.moduleString : PREC.primary,
+    EXP.functionString : PREC.primary,
+    EXP.prettyFunction : PREC.primary,
+    EXP.typeid_ : PREC.primary,
+    EXP.is_ : PREC.primary,
+    EXP.assert_ : PREC.primary,
+    EXP.halt : PREC.primary,
+    EXP.template_ : PREC.primary,
+    EXP.dSymbol : PREC.primary,
+    EXP.function_ : PREC.primary,
+    EXP.variable : PREC.primary,
+    EXP.symbolOffset : PREC.primary,
+    EXP.structLiteral : PREC.primary,
+    EXP.compoundLiteral : PREC.primary,
+    EXP.arrayLength : PREC.primary,
+    EXP.delegatePointer : PREC.primary,
+    EXP.delegateFunctionPointer : PREC.primary,
+    EXP.remove : PREC.primary,
+    EXP.tuple : PREC.primary,
+    EXP.traits : PREC.primary,
+    EXP.default_ : PREC.primary,
+    EXP.overloadSet : PREC.primary,
+    EXP.void_ : PREC.primary,
+    EXP.vectorArray : PREC.primary,
+    EXP._Generic : PREC.primary,
+
+    // post
+    EXP.dotTemplateInstance : PREC.primary,
+    EXP.dotIdentifier : PREC.primary,
+    EXP.dotTemplateDeclaration : PREC.primary,
+    EXP.dot : PREC.primary,
+    EXP.dotType : PREC.primary,
+    EXP.plusPlus : PREC.primary,
+    EXP.minusMinus : PREC.primary,
+    EXP.prePlusPlus : PREC.primary,
+    EXP.preMinusMinus : PREC.primary,
+    EXP.call : PREC.primary,
+    EXP.slice : PREC.primary,
+    EXP.array : PREC.primary,
+    EXP.index : PREC.primary,
+
+    EXP.delegate_ : PREC.unary,
+    EXP.address : PREC.unary,
+    EXP.star : PREC.unary,
+    EXP.negate : PREC.unary,
+    EXP.uadd : PREC.unary,
+    EXP.not : PREC.unary,
+    EXP.tilde : PREC.unary,
+    EXP.delete_ : PREC.unary,
+    EXP.new_ : PREC.unary,
+    EXP.newAnonymousClass : PREC.unary,
+    EXP.cast_ : PREC.unary,
+    EXP.throw_ : PREC.unary,
+
+    EXP.vector : PREC.unary,
+    EXP.pow : PREC.pow,
+
+    EXP.mul : PREC.mul,
+    EXP.div : PREC.mul,
+    EXP.mod : PREC.mul,
+
+    EXP.add : PREC.add,
+    EXP.min : PREC.add,
+    EXP.concatenate : PREC.add,
+
+    EXP.leftShift : PREC.shift,
+    EXP.rightShift : PREC.shift,
+    EXP.unsignedRightShift : PREC.shift,
+
+    EXP.lessThan : PREC.rel,
+    EXP.lessOrEqual : PREC.rel,
+    EXP.greaterThan : PREC.rel,
+    EXP.greaterOrEqual : PREC.rel,
+    EXP.in_ : PREC.rel,
+
+    /* Note that we changed precedence, so that < and != have the same
+     * precedence. This change is in the parser, too.
+     */
+    EXP.equal : PREC.rel,
+    EXP.notEqual : PREC.rel,
+    EXP.identity : PREC.rel,
+    EXP.notIdentity : PREC.rel,
+
+    EXP.and : PREC.and,
+    EXP.xor : PREC.xor,
+    EXP.or : PREC.or,
+
+    EXP.andAnd : PREC.andand,
+    EXP.orOr : PREC.oror,
+
+    EXP.question : PREC.cond,
+
+    EXP.assign : PREC.assign,
+    EXP.construct : PREC.assign,
+    EXP.blit : PREC.assign,
+    EXP.addAssign : PREC.assign,
+    EXP.minAssign : PREC.assign,
+    EXP.concatenateAssign : PREC.assign,
+    EXP.concatenateElemAssign : PREC.assign,
+    EXP.concatenateDcharAssign : PREC.assign,
+    EXP.mulAssign : PREC.assign,
+    EXP.divAssign : PREC.assign,
+    EXP.modAssign : PREC.assign,
+    EXP.powAssign : PREC.assign,
+    EXP.leftShiftAssign : PREC.assign,
+    EXP.rightShiftAssign : PREC.assign,
+    EXP.unsignedRightShiftAssign : PREC.assign,
+    EXP.andAssign : PREC.assign,
+    EXP.orAssign : PREC.assign,
+    EXP.xorAssign : PREC.assign,
+
+    EXP.comma : PREC.expr,
+    EXP.declaration : PREC.expr,
+
+    EXP.interval : PREC.assign,
+];
+
+enum ParseStatementFlags : int
+{
+    semi          = 1,        // empty ';' statements are allowed, but deprecated
+    scope_        = 2,        // start a new scope
+    curly         = 4,        // { } statement is required
+    curlyScope    = 8,        // { } starts a new scope
+    semiOk        = 0x10,     // empty ';' are really ok
+}
+
+struct PrefixAttributes(AST)
+{
+    StorageClass storageClass;
+    AST.Expression depmsg;
+    LINK link;
+    AST.Visibility visibility;
+    bool setAlignment;
+    AST.Expression ealign;
+    AST.Expressions* udas;
+    const(char)* comment;
+}
+
+/// The result of the `ParseLinkage` function
+struct ParsedLinkage(AST)
+{
+    /// What linkage was specified
+    LINK link;
+    /// If `extern(C++, class|struct)`, contains the `class|struct`
+    CPPMANGLE cppmangle;
+    /// If `extern(C++, some.identifier)`, will be the identifiers
+    AST.Identifiers* idents;
+    /// If `extern(C++, (some_tuple_expression)|"string"), will be the expressions
+    AST.Expressions* identExps;
+}
+
+
+/*********************************** Private *************************************/
+
+/***********************
+ * How multiple declarations are parsed.
+ * If 1, treat as C.
+ * If 0, treat:
+ *      int *p, i;
+ * as:
+ *      int* p;
+ *      int* i;
+ */
+private enum CDECLSYNTAX = 0;
+
+/*****
+ * Support C cast syntax:
+ *      (type)(expression)
+ */
+private enum CCASTSYNTAX = 1;
+
+/*****
+ * Support postfix C array declarations, such as
+ *      int a[3][4];
+ */
+private enum CARRAYDECL = 1;
+
+/*****************************
+ * Destructively extract storage class from pAttrs.
+ */
+private StorageClass getStorageClass(AST)(PrefixAttributes!(AST)* pAttrs)
+{
+    StorageClass stc = STC.undefined_;
+    if (pAttrs)
+    {
+        stc = pAttrs.storageClass;
+        pAttrs.storageClass = STC.undefined_;
+    }
+    return stc;
+}
+
+/**************************************
+ * dump mixin expansion to file for better debugging
+ */
+private bool writeMixin(const(char)[] s, ref Loc loc)
+{
+    if (!global.params.mixinOut)
+        return false;
+
+    OutBuffer* ob = global.params.mixinOut;
+
+    ob.writestring("// expansion at ");
+    ob.writestring(loc.toChars());
+    ob.writenl();
+
+    global.params.mixinLines++;
+
+    loc = Loc(global.params.mixinFile, global.params.mixinLines + 1, loc.charnum);
+
+    // write by line to create consistent line endings
+    size_t lastpos = 0;
+    for (size_t i = 0; i < s.length; ++i)
+    {
+        // detect LF and CRLF
+        const c = s[i];
+        if (c == '\n' || (c == '\r' && i+1 < s.length && s[i+1] == '\n'))
+        {
+            ob.writestring(s[lastpos .. i]);
+            ob.writenl();
+            global.params.mixinLines++;
+            if (c == '\r')
+                ++i;
+            lastpos = i + 1;
+        }
+    }
+
+    if(lastpos < s.length)
+        ob.writestring(s[lastpos .. $]);
+
+    if (s.length == 0 || s[$-1] != '\n')
+    {
+        ob.writenl(); // ensure empty line after expansion
+        global.params.mixinLines++;
+    }
+    ob.writenl();
+    global.params.mixinLines++;
+
+    return true;
+}
+
+
diff --git a/gcc/d/dmd/printast.d b/gcc/d/dmd/printast.d
index 61331453ebc..571c3fc4cc7 100644
--- a/gcc/d/dmd/printast.d
+++ b/gcc/d/dmd/printast.d
@@ -122,6 +122,16 @@ extern (C++) final class PrintASTVisitor : Visitor
         printAST(e.e1, indent + 2);
     }
 
+    override void visit(CastExp e)
+    {
+        printIndent(indent);
+        auto s = EXPtoString(e.op);
+        printf("%.*s %s\n", cast(int)s.length, s.ptr, e.type ? e.type.toChars() : "");
+        printIndent(indent + 2);
+        printf(".to: %s\n", e.to.toChars());
+        printAST(e.e1, indent + 2);
+    }
+
     override void visit(VectorExp e)
     {
         printIndent(indent);
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index f36cdc9c4bc..85c4d5bf6a5 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -422,7 +422,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
                 const sameParams = tf1.parameterList == tf2.parameterList;
 
                 // Allow the hack to declare overloads with different parameters/STC's
-                // @@@DEPRECATED_2.094@@@
+                // @@@DEPRECATED_2.104@@@
                 // Deprecated in 2020-08, make this an error in 2.104
                 if (parent1.isModule() &&
                     f1.linkage != LINK.d && f1.linkage != LINK.cpp &&
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 7bcb7ec1dc0..3f019669400 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -377,6 +377,12 @@ private extern(C++) final class Semantic3Visitor : Visitor
 
             // Reverts: https://issues.dlang.org/show_bug.cgi?id=5710
             // No compiler supports this, and there was never any spec for it.
+            // @@@DEPRECATED_2.116@@@
+            // Deprecated in 2.096, can be made an error in 2.116.
+            // The deprecation period is longer than usual as dual-context
+            // functions may be widely used by dmd-compiled projects.
+            // It also gives more time for the implementation of dual-context
+            // functions to be reworked as a frontend-only feature.
             if (funcdecl.isThis2)
             {
                 funcdecl.deprecation("function requires a dual-context, which is deprecated");
@@ -746,7 +752,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 // Check for errors related to 'nothrow'.
                 const blockexit = funcdecl.fbody.blockExit(funcdecl, f.isnothrow);
                 if (f.isnothrow && blockexit & BE.throw_)
-                    error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
+                    error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
 
                 if (!(blockexit & (BE.throw_ | BE.halt) || funcdecl.flags & FUNCFLAG.hasCatches))
                 {
@@ -1146,14 +1152,16 @@ private extern(C++) final class Semantic3Visitor : Visitor
 
                             s = s.statementSemantic(sc2);
 
-                            bool isnothrow = f.isnothrow & !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
+                            immutable bool isnothrow = f.isnothrow && !(funcdecl.flags & FUNCFLAG.nothrowInprocess);
                             const blockexit = s.blockExit(funcdecl, isnothrow);
                             if (blockexit & BE.throw_)
+                            {
                                 funcdecl.eh_none = false;
-                            if (f.isnothrow && isnothrow && blockexit & BE.throw_)
-                                error(funcdecl.loc, "`nothrow` %s `%s` may throw", funcdecl.kind(), funcdecl.toPrettyChars());
-                            if (funcdecl.flags & FUNCFLAG.nothrowInprocess && blockexit & BE.throw_)
-                                f.isnothrow = false;
+                                if (isnothrow)
+                                    error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
+                                else if (funcdecl.flags & FUNCFLAG.nothrowInprocess)
+                                    f.isnothrow = false;
+                            }
 
                             if (sbody.blockExit(funcdecl, f.isnothrow) == BE.fallthru)
                                 sbody = new CompoundStatement(Loc.initial, sbody, s);
@@ -1402,7 +1410,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
         auto sexp = new ExpStatement(ctor.loc, ce);
         auto ss = new ScopeStatement(ctor.loc, sexp, ctor.loc);
 
-        // @@@DEPRECATED_2096@@@
+        // @@@DEPRECATED_2.106@@@
         // Allow negligible attribute violations to allow for a smooth
         // transition. Remove this after the usual deprecation period
         // after 2.106.
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 1f7f3e4bc80..5dbe5b66d3e 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -1608,7 +1608,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
      * Params:
      *  sc = context
      *  fs = ForeachStatement
-     *  tfld = type of function literal to be created, can be null
+     *  tfld = type of function literal to be created (type of opApply() function if any), can be null
      * Returns:
      *  Function literal created, as an expression
      *  null if error.
@@ -1619,7 +1619,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
         foreach (i; 0 .. fs.parameters.dim)
         {
             Parameter p = (*fs.parameters)[i];
-            StorageClass stc = STC.ref_;
+            StorageClass stc = STC.ref_ | (p.storageClass & STC.scope_);
             Identifier id;
 
             p.type = p.type.typeSemantic(fs.loc, sc);
@@ -1628,17 +1628,17 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             {
                 Parameter prm = tfld.parameterList[i];
                 //printf("\tprm = %s%s\n", (prm.storageClass&STC.ref_?"ref ":"").ptr, prm.ident.toChars());
-                stc = prm.storageClass & STC.ref_;
-                id = p.ident; // argument copy is not need.
-                if ((p.storageClass & STC.ref_) != stc)
+                stc = (prm.storageClass & STC.ref_) | (p.storageClass & STC.scope_);
+                if ((p.storageClass & STC.ref_) != (prm.storageClass & STC.ref_))
                 {
-                    if (!stc)
+                    if (!(prm.storageClass & STC.ref_))
                     {
                         fs.error("`foreach`: cannot make `%s` `ref`", p.ident.toChars());
                         return null;
                     }
                     goto LcopyArg;
                 }
+                id = p.ident; // argument copy is not need.
             }
             else if (p.storageClass & STC.ref_)
             {
@@ -1655,7 +1655,7 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
 
                 Initializer ie = new ExpInitializer(fs.loc, new IdentifierExp(fs.loc, id));
                 auto v = new VarDeclaration(fs.loc, p.type, p.ident, ie);
-                v.storage_class |= STC.temp;
+                v.storage_class |= STC.temp | (stc & STC.scope_);
                 Statement s = new ExpStatement(fs.loc, v);
                 fs._body = new CompoundStatement(fs.loc, s, fs._body);
             }
@@ -3567,7 +3567,6 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
 
         tcs.tryBody = sc.tryBody;   // chain on the in-flight tryBody
         tcs._body = tcs._body.semanticScope(sc, null, null, tcs);
-        assert(tcs._body);
 
         /* Even if body is empty, still do semantic analysis on catches
          */
@@ -3610,6 +3609,11 @@ package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
         if (catchErrors)
             return setError();
 
+        // No actual code in the try (i.e. omitted any conditionally compiled code)
+        // Could also be extended to check for hasCode
+        if (!tcs._body)
+            return;
+
         if (tcs._body.isErrorStatement())
         {
             result = tcs._body;
@@ -4764,161 +4768,71 @@ private Statements* flatten(Statement statement, Scope* sc)
 }
 
 /***********************************************************
- * Convert TemplateMixin members (== Dsymbols) to Statements.
+ * Convert TemplateMixin members (which are Dsymbols) to Statements.
+ * Params:
+ *    s = the symbol to convert to a Statement
+ * Returns:
+ *    s redone as a Statement
  */
 private Statement toStatement(Dsymbol s)
 {
-    extern (C++) final class ToStmt : Visitor
-    {
-        alias visit = Visitor.visit;
-    public:
-        Statement result;
-
-        Statement visitMembers(Loc loc, Dsymbols* a)
-        {
-            if (!a)
-                return null;
-
-            auto statements = new Statements();
-            foreach (s; *a)
-            {
-                statements.push(toStatement(s));
-            }
-            return new CompoundStatement(loc, statements);
-        }
+    Statement result;
 
-        override void visit(Dsymbol s)
+    if (auto tm = s.isTemplateMixin())
+    {
+        auto a = new Statements();
+        foreach (m; *tm.members)
         {
-            .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
-            result = new ErrorStatement();
+            if (Statement sx = toStatement(m))
+                a.push(sx);
         }
-
-        override void visit(TemplateMixin tm)
-        {
-            auto a = new Statements();
-            foreach (m; *tm.members)
-            {
-                Statement s = toStatement(m);
-                if (s)
-                    a.push(s);
-            }
-            result = new CompoundStatement(tm.loc, a);
-        }
-
+        result = new CompoundStatement(tm.loc, a);
+    }
+    else if (s.isVarDeclaration()       ||
+             s.isAggregateDeclaration() ||
+             s.isFuncDeclaration()      ||
+             s.isEnumDeclaration()      ||
+             s.isAliasDeclaration()     ||
+             s.isTemplateDeclaration())
+    {
+        /* Perhaps replace the above with isScopeDsymbol() || isDeclaration()
+         */
         /* An actual declaration symbol will be converted to DeclarationExp
          * with ExpStatement.
          */
-        Statement declStmt(Dsymbol s)
-        {
-            auto de = new DeclarationExp(s.loc, s);
-            de.type = Type.tvoid; // avoid repeated semantic
-            return new ExpStatement(s.loc, de);
-        }
-
-        override void visit(VarDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
-        override void visit(AggregateDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
-        override void visit(FuncDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
-        override void visit(EnumDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
-        override void visit(AliasDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
-        override void visit(TemplateDeclaration d)
-        {
-            result = declStmt(d);
-        }
-
+        auto de = new DeclarationExp(s.loc, s);
+        de.type = Type.tvoid; // avoid repeated semantic
+        result = new ExpStatement(s.loc, de);
+    }
+    else if (auto d = s.isAttribDeclaration())
+    {
         /* All attributes have been already picked by the semantic analysis of
          * 'bottom' declarations (function, struct, class, etc).
          * So we don't have to copy them.
          */
-        override void visit(StorageClassDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(DeprecatedDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(LinkDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(VisibilityDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(AlignDeclaration d)
+        if (Dsymbols* a = d.include(null))
         {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(UserAttributeDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(ForwardingAttribDeclaration d)
-        {
-            result = visitMembers(d.loc, d.decl);
-        }
-
-        override void visit(StaticAssert s)
-        {
-        }
-
-        override void visit(Import s)
-        {
-        }
-
-        override void visit(PragmaDeclaration d)
-        {
-        }
-
-        override void visit(ConditionalDeclaration d)
-        {
-            result = visitMembers(d.loc, d.include(null));
-        }
-
-        override void visit(StaticForeachDeclaration d)
-        {
-            assert(d.sfe && !!d.sfe.aggrfe ^ !!d.sfe.rangefe);
-            result = visitMembers(d.loc, d.include(null));
-        }
-
-        override void visit(CompileDeclaration d)
-        {
-            result = visitMembers(d.loc, d.include(null));
+            auto statements = new Statements();
+            foreach (sx; *a)
+            {
+                statements.push(toStatement(sx));
+            }
+            result = new CompoundStatement(d.loc, statements);
         }
     }
+    else if (s.isStaticAssert() ||
+             s.isImport())
+    {
+        /* Ignore as they are not Statements
+         */
+    }
+    else
+    {
+        .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
+        result = new ErrorStatement();
+    }
 
-    if (!s)
-        return null;
-
-    scope ToStmt v = new ToStmt();
-    s.accept(v);
-    return v.result;
+    return result;
 }
 
 /**
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
index 7daf7cdcec1..c7d314808ef 100644
--- a/gcc/d/dmd/staticassert.d
+++ b/gcc/d/dmd/staticassert.d
@@ -59,6 +59,11 @@ extern (C++) final class StaticAssert : Dsymbol
         return "static assert";
     }
 
+    override inout(StaticAssert) isStaticAssert() inout
+    {
+        return this;
+    }
+
     override void accept(Visitor v)
     {
         v.visit(this);
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
index 5c00b464f64..38142bc6efc 100644
--- a/gcc/d/dmd/staticassert.h
+++ b/gcc/d/dmd/staticassert.h
@@ -24,5 +24,6 @@ public:
     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); }
 };
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 20b8711a1cf..9c24df06530 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -35,7 +35,6 @@ enum TOK : ubyte
     leftCurly,
     rightCurly,
     colon,
-    negate,
     semicolon,
     dotDotDot,
     endOfFile,
@@ -44,26 +43,18 @@ enum TOK : ubyte
     assert_,
     true_,
     false_,
-    array,
-    call,
-    address,
-    type,
     throw_,
     new_,
     delete_,
-    star,
     variable,
     slice,
     version_,
     module_,
     dollar,
     template_,
-    declaration,
     typeof_,
     pragma_,
     typeid_,
-    uadd,
-    remove,
     comment,
 
     // Operators
@@ -75,7 +66,6 @@ enum TOK : ubyte
     notEqual,
     identity,
     notIdentity,
-    index,
     is_,
 
     leftShift,
@@ -281,6 +271,7 @@ enum TOK : ubyte
     _import,
     __cdecl,
     __declspec,
+    __stdcall,
     __attribute__,
 }
 
@@ -589,6 +580,7 @@ private immutable TOK[] keywords =
     TOK._import,
     TOK.__cdecl,
     TOK.__declspec,
+    TOK.__stdcall,
     TOK.__attribute__,
 ];
 
@@ -617,7 +609,7 @@ static immutable TOK[TOK.max + 1] Ckeywords =
                        restrict, return_, int16, signed, sizeof_, static_, struct_, switch_, typedef_,
                        union_, unsigned, void_, volatile, while_, asm_,
                        _Alignas, _Alignof, _Atomic, _Bool, _Complex, _Generic, _Imaginary, _Noreturn,
-                       _Static_assert, _Thread_local, _import, __cdecl, __declspec, __attribute__ ];
+                       _Static_assert, _Thread_local, _import, __cdecl, __declspec, __stdcall, __attribute__ ];
 
         foreach (kw; Ckwds)
             tab[kw] = cast(TOK) kw;
@@ -805,18 +797,11 @@ extern (C++) struct Token
         TOK.andAnd: "&&",
         TOK.or: "|",
         TOK.orOr: "||",
-        TOK.array: "[]",
-        TOK.index: "[i]",
-        TOK.address: "&",
-        TOK.star: "*",
         TOK.tilde: "~",
         TOK.dollar: "$",
         TOK.plusPlus: "++",
         TOK.minusMinus: "--",
-        TOK.type: "type",
         TOK.question: "?",
-        TOK.negate: "-",
-        TOK.uadd: "+",
         TOK.variable: "var",
         TOK.addAssign: "+=",
         TOK.minAssign: "-=",
@@ -829,7 +814,6 @@ extern (C++) struct Token
         TOK.andAssign: "&=",
         TOK.orAssign: "|=",
         TOK.concatenateAssign: "~=",
-        TOK.call: "call",
         TOK.identity: "is",
         TOK.notIdentity: "!is",
         TOK.identifier: "identifier",
@@ -844,14 +828,12 @@ extern (C++) struct Token
         // For debugging
         TOK.error: "error",
         TOK.string_: "string",
-        TOK.declaration: "declaration",
         TOK.onScopeExit: "scope(exit)",
         TOK.onScopeSuccess: "scope(success)",
         TOK.onScopeFailure: "scope(failure)",
 
         // Finish up
         TOK.reserved: "reserved",
-        TOK.remove: "remove",
         TOK.comment: "comment",
         TOK.int32Literal: "int32v",
         TOK.uns32Literal: "uns32v",
@@ -896,6 +878,7 @@ extern (C++) struct Token
         TOK._import       : "__import",
         TOK.__cdecl        : "__cdecl",
         TOK.__declspec     : "__declspec",
+        TOK.__stdcall      : "__stdcall",
         TOK.__attribute__  : "__attribute__",
     ];
 
@@ -963,12 +946,20 @@ nothrow:
             sprintf(&buffer[0], "%d", cast(d_int32)intvalue);
             break;
         case TOK.uns32Literal:
-        case TOK.charLiteral:
         case TOK.wcharLiteral:
         case TOK.dcharLiteral:
         case TOK.wchar_tLiteral:
             sprintf(&buffer[0], "%uU", cast(d_uns32)unsvalue);
             break;
+        case TOK.charLiteral:
+        {
+            const v = cast(d_int32)intvalue;
+            if (v >= ' ' && v <= '~')
+                sprintf(&buffer[0], "'%c'", v);
+            else
+                sprintf(&buffer[0], "'\\x%02x'", v);
+            break;
+        }
         case TOK.int64Literal:
             sprintf(&buffer[0], "%lldL", cast(long)intvalue);
             break;
@@ -1006,29 +997,7 @@ nothrow:
                 {
                     dchar c;
                     utf_decodeChar(ustring[0 .. len], i, c);
-                    switch (c)
-                    {
-                    case 0:
-                        break;
-                    case '"':
-                    case '\\':
-                        buf.writeByte('\\');
-                        goto default;
-                    default:
-                        if (c <= 0x7F)
-                        {
-                            if (isprint(c))
-                                buf.writeByte(c);
-                            else
-                                buf.printf("\\x%02x", c);
-                        }
-                        else if (c <= 0xFFFF)
-                            buf.printf("\\u%04x", c);
-                        else
-                            buf.printf("\\U%08x", c);
-                        continue;
-                    }
-                    break;
+                    writeCharLiteral(buf, c);
                 }
                 buf.writeByte('"');
                 if (postfix)
@@ -1103,3 +1072,64 @@ nothrow:
     }
 }
 
+/**
+ * Write a character, using a readable escape sequence if needed
+ *
+ * Useful for printing "" string literals in e.g. error messages, ddoc, or the `.stringof` property
+ *
+ * Params:
+ *   buf = buffer to append character in
+ *   c = code point to write
+ */
+nothrow
+void writeCharLiteral(ref OutBuffer buf, dchar c)
+{
+    switch (c)
+    {
+        case '\0':
+            buf.writestring("\\0");
+            break;
+        case '\n':
+            buf.writestring("\\n");
+            break;
+        case '\r':
+            buf.writestring("\\r");
+            break;
+        case '\t':
+            buf.writestring("\\t");
+            break;
+        case '\b':
+            buf.writestring("\\b");
+            break;
+        case '\f':
+            buf.writestring("\\f");
+            break;
+        case '"':
+        case '\\':
+            buf.writeByte('\\');
+            goto default;
+        default:
+            if (c <= 0x7F)
+            {
+                if (isprint(c))
+                    buf.writeByte(c);
+                else
+                    buf.printf("\\x%02x", c);
+            }
+            else if (c <= 0xFFFF)
+                buf.printf("\\u%04x", c);
+            else
+                buf.printf("\\U%08x", c);
+            break;
+    }
+}
+
+unittest
+{
+    OutBuffer buf;
+    foreach(dchar d; "a\n\r\t\b\f\0\x11\u7233\U00017233"d)
+    {
+        writeCharLiteral(buf, d);
+    }
+    assert(buf.extractSlice() == `a\n\r\t\b\f\0\x11\u7233\U00017233`);
+}
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index a7c9aa55bba..a9f5028038e 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -44,7 +44,6 @@ enum class TOK : unsigned char
     leftCurly,
     rightCurly,
     colon,
-    negate,
     semicolon,
     dotDotDot,
     endOfFile,
@@ -53,26 +52,18 @@ enum class TOK : unsigned char
     assert_,
     true_,
     false_,
-    array,
-    call,
-    address,
-    type,
     throw_,
     new_,
     delete_,
-    star,
     variable,
     slice,
     version_,
     module_,
     dollar,
     template_,
-    declaration,
     typeof_,
     pragma_,
     typeid_,
-    uadd,
-    remove,
     comment,
 
     // Operators
@@ -84,7 +75,6 @@ enum class TOK : unsigned char
     notEqual,
     identity,
     notIdentity,
-    index,
     is_,
 
     leftShift,      // 64
@@ -288,8 +278,9 @@ enum class TOK : unsigned char
 
     // C only extended keywords
     _import,
-    cdecl,
+    cdecl_,
     declspec,
+    stdcall,
     attribute__,
 
     MAX,
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 8b6ca6545d6..615c49fd623 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -961,8 +961,6 @@ package mixin template ParseVisitMethods(AST)
         //printf("Visiting NewExp\n");
         if (e.thisexp)
             e.thisexp.accept(this);
-        if (e.newargs && e.newargs.dim)
-            visitArgs(e.newargs);
         visitType(e.newtype);
         if (e.arguments && e.arguments.dim)
             visitArgs(e.arguments);
@@ -973,8 +971,6 @@ package mixin template ParseVisitMethods(AST)
         //printf("Visiting NewAnonClassExp\n");
         if (e.thisexp)
             e.thisexp.accept(this);
-        if (e.newargs && e.newargs.dim)
-            visitArgs(e.newargs);
         if (e.arguments && e.arguments.dim)
             visitArgs(e.arguments);
         if (e.cd)
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index e11f1f7810c..637b32ecdad 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -210,6 +210,9 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
             error(loc, "undefined identifier `%s`, did you mean %s `%s`?", p, s2.kind(), s2.toChars());
         else if (const q = Scope.search_correct_C(id))
             error(loc, "undefined identifier `%s`, did you mean `%s`?", p, q);
+        else if ((id == Id.This   && sc.getStructClassScope()) ||
+                 (id == Id._super && sc.getClassScope()))
+            error(loc, "undefined identifier `%s`, did you mean `typeof(%s)`?", p, p);
         else
             error(loc, "undefined identifier `%s`", p);
 
@@ -273,7 +276,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
             // Same check as in Expression.semanticY(DotIdExp)
             else if (sm.isPackage() && checkAccess(sc, sm.isPackage()))
             {
-                // @@@DEPRECATED_2.096@@@
+                // @@@DEPRECATED_2.106@@@
                 // Should be an error in 2.106. Just remove the deprecation call
                 // and uncomment the null assignment
                 deprecation(loc, "%s %s is not accessible here, perhaps add 'static import %s;'", sm.kind(), sm.toPrettyChars(), sm.toPrettyChars());
@@ -2040,6 +2043,22 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             return mtype.resolved;
         }
 
+        /* Find the current scope by skipping tag scopes.
+         * In C, tag scopes aren't considered scopes.
+         */
+        Scope* sc2 = sc;
+        while (1)
+        {
+            sc2 = sc2.inner();
+            auto scopesym = sc2.scopesym;
+            if (scopesym.isStructDeclaration())
+            {
+                sc2 = sc2.enclosing;
+                continue;
+            }
+            break;
+        }
+
         /* Declare mtype as a struct/union/enum declaration
          */
         void declareTag()
@@ -2047,16 +2066,16 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             void declare(ScopeDsymbol sd)
             {
                 sd.members = mtype.members;
-                auto scopesym = sc.inner().scopesym;
+                auto scopesym = sc2.inner().scopesym;
                 if (scopesym.members)
                     scopesym.members.push(sd);
                 if (scopesym.symtab && !scopesym.symtabInsert(sd))
                 {
                     Dsymbol s2 = scopesym.symtabLookup(sd, mtype.id);
-                    handleTagSymbols(*sc, sd, s2, scopesym);
+                    handleTagSymbols(*sc2, sd, s2, scopesym);
                 }
-                sd.parent = sc.parent;
-                sd.dsymbolSemantic(sc);
+                sd.parent = sc2.parent;
+                sd.dsymbolSemantic(sc2);
             }
 
             switch (mtype.tok)
@@ -2098,7 +2117,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         /* look for pre-existing declaration
          */
         Dsymbol scopesym;
-        auto s = sc.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
+        auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
         if (!s || s.isModule())
         {
             // no pre-existing declaration, so declare it
@@ -2111,7 +2130,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         /* A redeclaration only happens if both declarations are in
          * the same scope
          */
-        const bool redeclar = (scopesym == sc.inner().scopesym);
+        const bool redeclar = (scopesym == sc2.inner().scopesym);
 
         if (redeclar)
         {
@@ -2154,7 +2173,7 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                          * picked up and added to the symtab.
                          */
                         sd.semanticRun = PASS.semantic;
-                        sd.dsymbolSemantic(sc);
+                        sd.dsymbolSemantic(sc2);
                     }
                 }
                 else
@@ -2985,44 +3004,21 @@ void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
     void visitIdentifier(TypeIdentifier mt)
     {
         //printf("TypeIdentifier::resolve(sc = %p, idents = '%s')\n", sc, mt.toChars());
-        if ((mt.ident.equals(Id._super) || mt.ident.equals(Id.This)) && !hasThis(sc))
-        {
-            // @@@DEPRECATED_v2.091@@@.
-            // Made an error in 2.086.
-            // Eligible for removal in 2.091.
-            if (mt.ident.equals(Id._super))
-            {
-                error(mt.loc, "Using `super` as a type is obsolete. Use `typeof(super)` instead");
-            }
-             // @@@DEPRECATED_v2.091@@@.
-            // Made an error in 2.086.
-            // Eligible for removal in 2.091.
-            if (mt.ident.equals(Id.This))
-            {
-                error(mt.loc, "Using `this` as a type is obsolete. Use `typeof(this)` instead");
-            }
-            if (AggregateDeclaration ad = sc.getStructClassScope())
-            {
-                if (ClassDeclaration cd = ad.isClassDeclaration())
-                {
-                    if (mt.ident.equals(Id.This))
-                        mt.ident = cd.ident;
-                    else if (cd.baseClass && mt.ident.equals(Id._super))
-                        mt.ident = cd.baseClass.ident;
-                }
-                else
-                {
-                    StructDeclaration sd = ad.isStructDeclaration();
-                    if (sd && mt.ident.equals(Id.This))
-                        mt.ident = sd.ident;
-                }
-            }
-        }
         if (mt.ident == Id.ctfe)
         {
             error(loc, "variable `__ctfe` cannot be read at compile time");
             return returnError();
         }
+        if (mt.ident == Id.builtin_va_list) // gcc has __builtin_va_xxxx for stdarg.h
+        {
+            /* Since we don't support __builtin_va_start, -arg, -end, we don't
+             * have to actually care what -list is. A void* will do.
+             * If we ever do care, import core.stdc.stdarg and pull
+             * the definition out of that, similarly to how std.math is handled for PowExp
+             */
+            pt = target.va_listType(loc, sc);
+            return;
+        }
 
         Dsymbol scopesym;
         Dsymbol s = sc.search(loc, mt.ident, &scopesym);
@@ -3821,7 +3817,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                  *  e.opDot().ident
                  */
                 e = build_overload(e.loc, sc, e, null, fd);
-                // @@@DEPRECATED_2.087@@@.
+                // @@@DEPRECATED_2.092@@@.
                 e.deprecation("`opDot` is deprecated. Use `alias this`");
                 e = new DotIdExp(e.loc, e, ident);
                 return returnExp(e.expressionSemantic(sc));
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index dd7ebc842a8..d5e4df7f563 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -22,6 +22,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dmd/aggregate.h"
 #include "dmd/ctfe.h"
 #include "dmd/declaration.h"
+#include "dmd/enum.h"
 #include "dmd/expression.h"
 #include "dmd/identifier.h"
 #include "dmd/init.h"
@@ -1460,40 +1461,6 @@ public:
 	t1 = build_address (t1);
 	this->result_ = build_libcall (libcall, Type::tvoid, 1, t1);
       }
-    else if (tb1->ty == TY::Tarray)
-      {
-	/* For dynamic arrays, the garbage collector is called to immediately
-	   release the memory.  */
-	Type *telem = tb1->nextOf ()->baseElemOf ();
-	tree ti = null_pointer_node;
-
-	if (TypeStruct *ts = telem->isTypeStruct ())
-	  {
-	    /* Might need to run destructor on array contents.  */
-	    if (ts->sym->dtor)
-	      ti = build_typeinfo (e->loc, tb1->nextOf ());
-	  }
-
-	/* Generate: _delarray_t (&t1, ti);  */
-	this->result_ = build_libcall (LIBCALL_DELARRAYT, Type::tvoid, 2,
-				       build_address (t1), ti);
-      }
-    else if (tb1->ty == TY::Tpointer)
-      {
-	/* For pointers to a struct instance, if the struct has overloaded
-	   operator delete, then that operator is called.  */
-	t1 = build_address (t1);
-	Type *tnext = tb1->isTypePointer ()->next->toBasetype ();
-
-	/* This case should have been rewritten to `_d_delstruct` in the
-	   semantic phase.  */
-	if (TypeStruct *ts = tnext->isTypeStruct ())
-	  gcc_assert (!ts->sym->dtor);
-
-	/* Otherwise, the garbage collector is called to immediately free the
-	   memory allocated for the pointer.  */
-	this->result_ = build_libcall (LIBCALL_DELMEMORY, Type::tvoid, 1, t1);
-      }
     else
       {
 	error ("don%'t know how to delete %qs", e->e1->toChars ());
@@ -1936,10 +1903,17 @@ public:
 	else
 	  {
 	    tree object = build_expr (e->e1);
+	    Type *tb = e->e1->type->toBasetype ();
 
-	    if (e->e1->type->toBasetype ()->ty != TY::Tstruct)
+	    if (tb->ty != TY::Tstruct)
 	      object = build_deref (object);
 
+	    /* __complex is represented as a struct in the front-end, but
+	       underlying is really a complex type.  */
+	    if (e->e1->type->ty == TY::Tenum
+		&& e->e1->type->isTypeEnum ()->sym->isSpecial ())
+	      object = build_vconvert (build_ctype (tb), object);
+
 	    this->result_ = component_ref (object, get_symbol_decl (vd));
 	  }
       }
@@ -2604,7 +2578,7 @@ public:
 
 	for (size_t i = 0; i < e->len; i++)
 	  {
-	    tree value = build_integer_cst (e->charAt (i), etype);
+	    tree value = build_integer_cst (e->getCodeUnit (i), etype);
 	    CONSTRUCTOR_APPEND_ELT (elms, size_int (i), value);
 	  }
 
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index d6e0c7b86ce..acb610f71f0 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -83,9 +83,6 @@ DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
 DEF_D_RUNTIME (NEWITEMT, "_d_newitemT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
 DEF_D_RUNTIME (NEWITEMIT, "_d_newitemiT", RT(VOIDPTR), P1(CONST_TYPEINFO), 0)
 
-/* Used when calling delete on a pointer.  */
-DEF_D_RUNTIME (DELMEMORY, "_d_delmemory", RT(VOID), P1(POINTER_VOIDPTR), 0)
-
 /* Used when calling new on an array.  The `i' variant is for when the
    initializer is nonzero, and the `m' variant is when initializing a
    multi-dimensional array.  */
@@ -102,10 +99,6 @@ DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
 DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
 	       P2(CONST_TYPEINFO, SIZE_T), 0)
 
-/* Used when calling delete on an array.  */
-DEF_D_RUNTIME (DELARRAYT, "_d_delarray_t", RT(VOID),
-	       P2(ARRAYPTR_VOID, CONST_TYPEINFO), 0)
-
 /* Used for value equality (x == y) and comparisons (x < y) of non-trivial
    arrays.  Such as an array of structs or classes.  */
 DEF_D_RUNTIME (ADEQ2, "_adEq2", RT(INT),
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 8ae6ea1bb78..d897ec4c5e4 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -993,13 +993,17 @@ public:
 	t->ctype = build_variant_type_copy (build_ctype (underlying));
 	build_type_decl (t->ctype, t->sym);
       }
-    else if (!INTEGRAL_TYPE_P (basetype) || TREE_CODE (basetype) == BOOLEAN_TYPE)
+    else if (t->sym->ident == NULL
+	     || !INTEGRAL_TYPE_P (basetype)
+	     || TREE_CODE (basetype) == BOOLEAN_TYPE)
       {
-	/* Enums in D2 can have a base type that is not necessarily integral.
-	   For these, we simplify this a little by using the base type directly
-	   instead of building an ENUMERAL_TYPE.  */
+	/* Enums in D2 can either be anonymous, or have a base type that is not
+	   necessarily integral. For these, we simplify this a little by using
+	   the base type directly instead of building an ENUMERAL_TYPE.  */
 	t->ctype = build_variant_type_copy (basetype);
-	build_type_decl (t->ctype, t->sym);
+
+	if (t->sym->ident != NULL)
+	  build_type_decl (t->ctype, t->sym);
       }
     else
       {
diff --git a/gcc/testsuite/gdc.dg/special1.d b/gcc/testsuite/gdc.dg/special1.d
new file mode 100644
index 00000000000..8881dd0c299
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/special1.d
@@ -0,0 +1,12 @@
+// { dg-do compile }
+
+struct _Complex(T) { T re; T im; }
+enum __c_complex_float : _Complex!float;
+
+bool equals(__c_complex_float[] lhs, __c_complex_float[] rhs)
+{
+    foreach (i; 0 .. lhs.length)
+        if (lhs.ptr[i] != rhs.ptr[i])
+            return false;
+    return true;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/99bottles.d b/gcc/testsuite/gdc.test/compilable/99bottles.d
index 5341a49f766..ac416eb0fcb 100644
--- a/gcc/testsuite/gdc.test/compilable/99bottles.d
+++ b/gcc/testsuite/gdc.test/compilable/99bottles.d
@@ -3,7 +3,7 @@
 //    http://www.99-bottles-of-beer.net/language-d-1212.html
 
 // Generates the "99 bottles of beer" song at compile time,
-// using the template metaprograming facilities of D. 
+// using the template metaprograming facilities of D.
 // No executable is generated. No libraries are used.
 // Illustrates template default values, template string value parameters,
 // compile-time concatenation of constant strings, static if.
@@ -24,13 +24,13 @@ template itoa(ulong n)
 
 template showHowMany(int n, string where, bool needcapital = false)
 {
-  static if ( n > 1 ) 
+  static if ( n > 1 )
       const string showHowMany = itoa!(n) ~ " bottles of beer" ~ where ~ "\n";
   else static if ( n == 1 )
       const string showHowMany = "1 bottle of beer" ~ where ~ "\n";
   else static if ( needcapital )
       const string showHowMany = "No more bottles of beer" ~ where ~ "\n";
-  else 
+  else
       const string showHowMany = "no more bottles of beer" ~ where ~ "\n";
 }
 
@@ -39,514 +39,514 @@ template beer(int maxbeers, int n = maxbeers)
   static if ( n > 0 )
     const string beer = showHowMany!(n, " on the wall,", true)
         ~ showHowMany!(n, ".")
-        ~ "Take one down and pass it around, " ~ "\n" 
-        ~ showHowMany!( n - 1 , " on the wall.") 
+        ~ "Take one down and pass it around," ~ "\n"
+        ~ showHowMany!( n - 1 , " on the wall.")
         ~ "\n" ~ beer!(maxbeers, n - 1); // recurse for subsequent verses.
   else
     const string beer = showHowMany!(n, " on the wall,", true)
         ~ showHowMany!(n, ".")
-        ~ "Go to the store and buy some more, " ~ "\n"
+        ~ "Go to the store and buy some more," ~ "\n"
         ~ showHowMany!( maxbeers, " on the wall.");
 }
 
 enum expected = `99 bottles of beer on the wall,
 99 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 98 bottles of beer on the wall.
 
 98 bottles of beer on the wall,
 98 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 97 bottles of beer on the wall.
 
 97 bottles of beer on the wall,
 97 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 96 bottles of beer on the wall.
 
 96 bottles of beer on the wall,
 96 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 95 bottles of beer on the wall.
 
 95 bottles of beer on the wall,
 95 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 94 bottles of beer on the wall.
 
 94 bottles of beer on the wall,
 94 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 93 bottles of beer on the wall.
 
 93 bottles of beer on the wall,
 93 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 92 bottles of beer on the wall.
 
 92 bottles of beer on the wall,
 92 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 91 bottles of beer on the wall.
 
 91 bottles of beer on the wall,
 91 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 90 bottles of beer on the wall.
 
 90 bottles of beer on the wall,
 90 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 89 bottles of beer on the wall.
 
 89 bottles of beer on the wall,
 89 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 88 bottles of beer on the wall.
 
 88 bottles of beer on the wall,
 88 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 87 bottles of beer on the wall.
 
 87 bottles of beer on the wall,
 87 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 86 bottles of beer on the wall.
 
 86 bottles of beer on the wall,
 86 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 85 bottles of beer on the wall.
 
 85 bottles of beer on the wall,
 85 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 84 bottles of beer on the wall.
 
 84 bottles of beer on the wall,
 84 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 83 bottles of beer on the wall.
 
 83 bottles of beer on the wall,
 83 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 82 bottles of beer on the wall.
 
 82 bottles of beer on the wall,
 82 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 81 bottles of beer on the wall.
 
 81 bottles of beer on the wall,
 81 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 80 bottles of beer on the wall.
 
 80 bottles of beer on the wall,
 80 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 79 bottles of beer on the wall.
 
 79 bottles of beer on the wall,
 79 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 78 bottles of beer on the wall.
 
 78 bottles of beer on the wall,
 78 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 77 bottles of beer on the wall.
 
 77 bottles of beer on the wall,
 77 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 76 bottles of beer on the wall.
 
 76 bottles of beer on the wall,
 76 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 75 bottles of beer on the wall.
 
 75 bottles of beer on the wall,
 75 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 74 bottles of beer on the wall.
 
 74 bottles of beer on the wall,
 74 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 73 bottles of beer on the wall.
 
 73 bottles of beer on the wall,
 73 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 72 bottles of beer on the wall.
 
 72 bottles of beer on the wall,
 72 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 71 bottles of beer on the wall.
 
 71 bottles of beer on the wall,
 71 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 70 bottles of beer on the wall.
 
 70 bottles of beer on the wall,
 70 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 69 bottles of beer on the wall.
 
 69 bottles of beer on the wall,
 69 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 68 bottles of beer on the wall.
 
 68 bottles of beer on the wall,
 68 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 67 bottles of beer on the wall.
 
 67 bottles of beer on the wall,
 67 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 66 bottles of beer on the wall.
 
 66 bottles of beer on the wall,
 66 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 65 bottles of beer on the wall.
 
 65 bottles of beer on the wall,
 65 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 64 bottles of beer on the wall.
 
 64 bottles of beer on the wall,
 64 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 63 bottles of beer on the wall.
 
 63 bottles of beer on the wall,
 63 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 62 bottles of beer on the wall.
 
 62 bottles of beer on the wall,
 62 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 61 bottles of beer on the wall.
 
 61 bottles of beer on the wall,
 61 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 60 bottles of beer on the wall.
 
 60 bottles of beer on the wall,
 60 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 59 bottles of beer on the wall.
 
 59 bottles of beer on the wall,
 59 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 58 bottles of beer on the wall.
 
 58 bottles of beer on the wall,
 58 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 57 bottles of beer on the wall.
 
 57 bottles of beer on the wall,
 57 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 56 bottles of beer on the wall.
 
 56 bottles of beer on the wall,
 56 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 55 bottles of beer on the wall.
 
 55 bottles of beer on the wall,
 55 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 54 bottles of beer on the wall.
 
 54 bottles of beer on the wall,
 54 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 53 bottles of beer on the wall.
 
 53 bottles of beer on the wall,
 53 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 52 bottles of beer on the wall.
 
 52 bottles of beer on the wall,
 52 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 51 bottles of beer on the wall.
 
 51 bottles of beer on the wall,
 51 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 50 bottles of beer on the wall.
 
 50 bottles of beer on the wall,
 50 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 49 bottles of beer on the wall.
 
 49 bottles of beer on the wall,
 49 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 48 bottles of beer on the wall.
 
 48 bottles of beer on the wall,
 48 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 47 bottles of beer on the wall.
 
 47 bottles of beer on the wall,
 47 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 46 bottles of beer on the wall.
 
 46 bottles of beer on the wall,
 46 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 45 bottles of beer on the wall.
 
 45 bottles of beer on the wall,
 45 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 44 bottles of beer on the wall.
 
 44 bottles of beer on the wall,
 44 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 43 bottles of beer on the wall.
 
 43 bottles of beer on the wall,
 43 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 42 bottles of beer on the wall.
 
 42 bottles of beer on the wall,
 42 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 41 bottles of beer on the wall.
 
 41 bottles of beer on the wall,
 41 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 40 bottles of beer on the wall.
 
 40 bottles of beer on the wall,
 40 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 39 bottles of beer on the wall.
 
 39 bottles of beer on the wall,
 39 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 38 bottles of beer on the wall.
 
 38 bottles of beer on the wall,
 38 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 37 bottles of beer on the wall.
 
 37 bottles of beer on the wall,
 37 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 36 bottles of beer on the wall.
 
 36 bottles of beer on the wall,
 36 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 35 bottles of beer on the wall.
 
 35 bottles of beer on the wall,
 35 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 34 bottles of beer on the wall.
 
 34 bottles of beer on the wall,
 34 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 33 bottles of beer on the wall.
 
 33 bottles of beer on the wall,
 33 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 32 bottles of beer on the wall.
 
 32 bottles of beer on the wall,
 32 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 31 bottles of beer on the wall.
 
 31 bottles of beer on the wall,
 31 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 30 bottles of beer on the wall.
 
 30 bottles of beer on the wall,
 30 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 29 bottles of beer on the wall.
 
 29 bottles of beer on the wall,
 29 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 28 bottles of beer on the wall.
 
 28 bottles of beer on the wall,
 28 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 27 bottles of beer on the wall.
 
 27 bottles of beer on the wall,
 27 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 26 bottles of beer on the wall.
 
 26 bottles of beer on the wall,
 26 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 25 bottles of beer on the wall.
 
 25 bottles of beer on the wall,
 25 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 24 bottles of beer on the wall.
 
 24 bottles of beer on the wall,
 24 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 23 bottles of beer on the wall.
 
 23 bottles of beer on the wall,
 23 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 22 bottles of beer on the wall.
 
 22 bottles of beer on the wall,
 22 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 21 bottles of beer on the wall.
 
 21 bottles of beer on the wall,
 21 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 20 bottles of beer on the wall.
 
 20 bottles of beer on the wall,
 20 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 19 bottles of beer on the wall.
 
 19 bottles of beer on the wall,
 19 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 18 bottles of beer on the wall.
 
 18 bottles of beer on the wall,
 18 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 17 bottles of beer on the wall.
 
 17 bottles of beer on the wall,
 17 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 16 bottles of beer on the wall.
 
 16 bottles of beer on the wall,
 16 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 15 bottles of beer on the wall.
 
 15 bottles of beer on the wall,
 15 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 14 bottles of beer on the wall.
 
 14 bottles of beer on the wall,
 14 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 13 bottles of beer on the wall.
 
 13 bottles of beer on the wall,
 13 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 12 bottles of beer on the wall.
 
 12 bottles of beer on the wall,
 12 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 11 bottles of beer on the wall.
 
 11 bottles of beer on the wall,
 11 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 10 bottles of beer on the wall.
 
 10 bottles of beer on the wall,
 10 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 9 bottles of beer on the wall.
 
 9 bottles of beer on the wall,
 9 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 8 bottles of beer on the wall.
 
 8 bottles of beer on the wall,
 8 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 7 bottles of beer on the wall.
 
 7 bottles of beer on the wall,
 7 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 6 bottles of beer on the wall.
 
 6 bottles of beer on the wall,
 6 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 5 bottles of beer on the wall.
 
 5 bottles of beer on the wall,
 5 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 4 bottles of beer on the wall.
 
 4 bottles of beer on the wall,
 4 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 3 bottles of beer on the wall.
 
 3 bottles of beer on the wall,
 3 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 2 bottles of beer on the wall.
 
 2 bottles of beer on the wall,
 2 bottles of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 1 bottle of beer on the wall.
 
 1 bottle of beer on the wall,
 1 bottle of beer.
-Take one down and pass it around, 
+Take one down and pass it around,
 no more bottles of beer on the wall.
 
 No more bottles of beer on the wall,
 no more bottles of beer.
-Go to the store and buy some more, 
+Go to the store and buy some more,
 99 bottles of beer on the wall.
 `;
 
diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d
index 5dcaeca73b4..3bc699aa7da 100644
--- a/gcc/testsuite/gdc.test/compilable/b18242.d
+++ b/gcc/testsuite/gdc.test/compilable/b18242.d
@@ -5,14 +5,14 @@ module object;
 class Object { }
 
 class TypeInfo { }
-class TypeInfo_Class : TypeInfo 
-{ 
+class TypeInfo_Class : TypeInfo
+{
     version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; }
 }
 
 class Throwable { }
 
-int _d_run_main() 
+int _d_run_main()
 {
     try { } catch(Throwable e) { return 1; }
     return 0;
diff --git a/gcc/testsuite/gdc.test/compilable/b19294.d b/gcc/testsuite/gdc.test/compilable/b19294.d
index 063a9df152a..ed1a71747e4 100644
--- a/gcc/testsuite/gdc.test/compilable/b19294.d
+++ b/gcc/testsuite/gdc.test/compilable/b19294.d
@@ -51,19 +51,19 @@ void test()
     MT s = MyStruct!int(1);
     MT[] arr = [s, 2 * s, 3 * s, 4 * s, 5 * s, 6 * s];
     MT[] result = new MT[arr.length];
-    
+
     result[] = arr[] + s;
     result[] = s + arr[];
-    
+
     result[] = arr[] - s;
     result[] = s - arr[];
-    
+
     result[] = arr[] * s;
     result[] = s * arr[];
-    
+
     result[] = arr[] / s;
     result[] = s / arr[];
-    
+
     result[] = arr[] ^^ s;
     result[] = s ^^ arr[];
 }
diff --git a/gcc/testsuite/gdc.test/compilable/b20938.d b/gcc/testsuite/gdc.test/compilable/b20938.d
index efcf4aab06f..ba3565ae8f9 100644
--- a/gcc/testsuite/gdc.test/compilable/b20938.d
+++ b/gcc/testsuite/gdc.test/compilable/b20938.d
@@ -12,11 +12,11 @@ void fun() {
     immutable S _is;
     Object o;
     immutable Object io;
-    
+
     auto a = [pi, ipi];
-    auto b = [ai, iai];    
+    auto b = [ai, iai];
     auto c = [s, _is];
     auto d = [o, io];
-    
+
     auto e = [A.a, B.b];
 }
diff --git a/gcc/testsuite/gdc.test/compilable/b21285.d b/gcc/testsuite/gdc.test/compilable/b21285.d
index 11eea74b669..482faa77f0d 100644
--- a/gcc/testsuite/gdc.test/compilable/b21285.d
+++ b/gcc/testsuite/gdc.test/compilable/b21285.d
@@ -1,27 +1,27 @@
 // REQUIRED_ARGS: -unittest
-// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master). 
+// Issue 21285 - Delegate covariance broken between 2.092 and 2.094 (git master).
 unittest
 {
     string path;
     int bank;
     static string path2;
     static int bank2;
-    
+
     // delegates
     auto a = [
         (string arg) { path = arg; },
         (string arg) { bank = 1; throw new Exception(""); }
     ];
-    
+
     // functions
     auto ab = [
         (string arg) { path2 = arg; },
         (string arg) { bank2 = 1; throw new Exception(""); }
     ];
-    
+
     alias dg = void delegate(string) pure @safe;
     alias fn = void function(string) @safe;
-    
+
     static assert(is(typeof(a[0]) == dg));
     static assert(is(typeof(ab[0]) == fn));
 }
diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d
index 076e29baece..a740994d7b5 100644
--- a/gcc/testsuite/gdc.test/compilable/commontype.d
+++ b/gcc/testsuite/gdc.test/compilable/commontype.d
@@ -196,7 +196,8 @@ static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***`
 
 static assert(is( X!( C*, I* ) == I* ));
 static assert(is( X!( I*, C* ) == I* ));
-static assert(Error!( C**, I** ));
+//static assert(Error!( C**, I** ));
+static assert(is( X!( C**, I** ) == const(I*)* ));
 
 static assert(Error!( C*, D* )); // should work
 
@@ -303,13 +304,15 @@ static assert(is( X!(C[4], B[4]) ));
 static assert(Error!( C[4], I[4] ));
 static assert(Error!( C[4], D[4] ));
 static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] ));
-static assert(Error!( C[4], const(I)[4] ));
+//static assert(Error!( C[4], const(I)[4] ));
+static assert(is( X!( C[4], const(I)[4] ) == const(I)[] ));
 static assert(Error!( C[4], const(D)[4] ));
 static assert(Error!( C*[4], B*[4] ));
 static assert(Error!( C*[4], I*[4] ));
 static assert(Error!( C*[4], D*[4] ));
 static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !?
-static assert(Error!( C*[4], const(I*)[4] ));
+//static assert(Error!( C*[4], const(I*)[4] ));
+static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] ));
 static assert(Error!( C*[4], const(D*)[4] ));
 static assert(Error!( C*[4], B**[4] ));
 static assert(Error!( C*[4], const(B*)*[4] ));
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc10.d b/gcc/testsuite/gdc.test/compilable/ddoc10.d
index 6a7a4812c60..2f614095a8e 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc10.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc10.d
@@ -171,7 +171,7 @@ struct T
     /****
      */
     this(A...)(A args) { }
-    
+
     ///
     this(int){}
 }
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc11.d b/gcc/testsuite/gdc.test/compilable/ddoc11.d
index 3fcf2ca00da..0082455d0ae 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc11.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc11.d
@@ -49,7 +49,7 @@ struct lldiv_t { long quot,rem; }
 
 
 
-    void *calloc(size_t, size_t);	/// 
+    void *calloc(size_t, size_t);	///
     void *malloc(size_t);	/// dittx
 
 /**
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc14.d b/gcc/testsuite/gdc.test/compilable/ddoc14.d
index a8b6d4d9d4c..fae99d401f1 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc14.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc14.d
@@ -77,7 +77,7 @@ interface Interface {
     V mColon(lazy P p) ; /// 10
 }
 +/
-    
+
 public P variable;  /// 0
 V mNone(lazy P p) {}  /// 1
 pure nothrow V mPrefix(lazy P p) {}   /// 2
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc3.d b/gcc/testsuite/gdc.test/compilable/ddoc3.d
index 1bcae411232..3b47497a1a7 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc3.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc3.d
@@ -42,7 +42,7 @@
  *	$(TROW 4, 5, 6)
  *	)
  *
- * $(D_CODE 
+ * $(D_CODE
       $(B pragma)( $(I name) );
       $(B pragma)( $(I name) , $(I option) [ $(I option) ] );
       $(U $(LPAREN))
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5.d b/gcc/testsuite/gdc.test/compilable/ddoc5.d
index 4ddc123b064..5a964f3dc65 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc5.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc5.d
@@ -15,10 +15,10 @@ class TestMembers(TemplateArg)
   public:
     /**
 
-       a static method 
+       a static method
 
        Params: idx = index
-   
+
     */
     static void PublicStaticMethod(int  idx)
     {
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc5446.d b/gcc/testsuite/gdc.test/compilable/ddoc5446.d
index 0596088b2e6..29cb8c9cefd 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc5446.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc5446.d
@@ -30,41 +30,41 @@ struct Bar
 {
     /** */
     alias A_Foo Bar_A_Foo;
-    
+
     /** */
     alias A_Foo_Alias Bar_A_Foo_Alias;
-    
+
     /** */
     alias A_Int Bar_A_Int;
-    
+
     /** */
     alias This_Foo Bar_This_Foo;
-    
+
     /** */
     alias This_Foo_Alias Bar_This_Foo_Alias;
-    
+
     /** */
     alias This_Int Bar_This_Int;
-    
+
     /** */
     alias Nested Nested_Alias;
-    
+
     /** */
     alias .Nested Fake_Nested;
-    
+
     /** */
     struct Nested
     {
         /** */
         alias Bar Bar_Nested_Bar_Alias;
-        
+
         /** */
         alias .Bar Bar_Alias;
-        
+
         /** */
         struct Bar
         {
-            
+
         }
     }
 }
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc9155.d b/gcc/testsuite/gdc.test/compilable/ddoc9155.d
index 9f5a59a434c..e03d422041b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc9155.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc9155.d
@@ -12,12 +12,12 @@ module ddoc9155;
  +  ---
  +  import std.stdio;   //&
  +  writeln("Hello world!");
- +  if (test) {  
+ +  if (test) {
  +    writefln("D programming language");
  +  }
  +
  +      algorithm;
- +  
+ +
  +  xxx;    //comment
  +      yyy;
  +  /* test
@@ -28,7 +28,7 @@ module ddoc9155;
  +File f = File("./text.txt", "r");
  +uint line = 0;
  + // The ElementType of data is not aggregation type
- +foreach (encoded; Base64.encoder(data)) 
+ +foreach (encoded; Base64.encoder(data))
  +  ---
  +/
 
@@ -45,12 +45,12 @@ module ddoc9155;
  *  ---
  *  import std.stdio;   //&
  *  writeln("Hello world!");
- *  if (test) {  
+ *  if (test) {
  *    writefln("D programming language");
  *  }
  *
  *      algorithm;
- *  
+ *
  *  xxx;    //comment
  *      yyy;
  *  /+ test
diff --git a/gcc/testsuite/gdc.test/compilable/debugInference.d b/gcc/testsuite/gdc.test/compilable/debugInference.d
index 1d4f157d788..947d820fcac 100644
--- a/gcc/testsuite/gdc.test/compilable/debugInference.d
+++ b/gcc/testsuite/gdc.test/compilable/debugInference.d
@@ -1,9 +1,5 @@
 /*
 REQUIRED_ARGS: -debug
-TEST_OUTPUT:
----
-compilable/debugInference.d(35): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
----
 https://issues.dlang.org/show_bug.cgi?id=20507
 */
 
@@ -32,7 +28,7 @@ void bar()()
         auto f2Ptr = &f2;
 
         S s;
-        delete s;
+        destroy(s);
 
         int* ptr = cast(int*) 0;
         int[] slice = ptr[0 .. 4];
diff --git a/gcc/testsuite/gdc.test/compilable/defa.d b/gcc/testsuite/gdc.test/compilable/defa.d
index a9222074ce4..5b4e5897c1f 100644
--- a/gcc/testsuite/gdc.test/compilable/defa.d
+++ b/gcc/testsuite/gdc.test/compilable/defa.d
@@ -3,7 +3,7 @@
 module defa;
 
 private import imports.defaa;
-	
+
 public abstract class A
 {
 	Display d;
diff --git a/gcc/testsuite/gdc.test/compilable/dlangui_crash.d b/gcc/testsuite/gdc.test/compilable/dlangui_crash.d
new file mode 100644
index 00000000000..36617f544c4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/dlangui_crash.d
@@ -0,0 +1,34 @@
+// https://issues.dlang.org/show_bug.cgi?id=22365
+
+class DrawableCache
+{
+    Ref _nullDrawable;
+
+    this()
+    {
+        debug Log;
+    }
+}
+
+class DrawableCacheEmpty
+{
+    Ref _nullDrawable;
+
+    this() {}
+}
+
+struct Ref
+{
+
+    ~this()
+    {
+    }
+}
+
+void foo()
+{
+    try
+        debug Log;
+    catch (Exception)
+        assert(false);
+}
diff --git a/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d b/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d
new file mode 100644
index 00000000000..4dbc56da476
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/enumbasearithmetic.d
@@ -0,0 +1,20 @@
+//https://issues.dlang.org/show_bug.cgi?id=20777
+struct FooInt
+{
+    int i;
+    auto opBinary(string op : "+")(int j)
+    {
+        return typeof(this)(i + j);
+    }
+
+    static @property FooInt max()
+    {
+        return typeof(this)(int.max);
+    }
+}
+
+enum foolist
+{
+    hi  = FooInt(0),
+    bye
+}
diff --git a/gcc/testsuite/gdc.test/compilable/header18364.d b/gcc/testsuite/gdc.test/compilable/header18364.d
index c7e1e67c7ae..080a0960a14 100644
--- a/gcc/testsuite/gdc.test/compilable/header18364.d
+++ b/gcc/testsuite/gdc.test/compilable/header18364.d
@@ -8,7 +8,7 @@ TEST_OUTPUT:
 === ${RESULTS_DIR}/compilable/header18364.di
 // D import file generated from 'compilable/header18364.d'
 module foo.bar.ba;
-nothrow pure @nogc @safe package(foo) 
+nothrow pure @nogc @safe package(foo)
 {
 	void foo();
 	nothrow pure @nogc @safe package(foo.bar) void foo2();
diff --git a/gcc/testsuite/gdc.test/compilable/imports/b33a.d b/gcc/testsuite/gdc.test/compilable/imports/b33a.d
index 5d52c66ceec..bd8fd0c2664 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/b33a.d
+++ b/gcc/testsuite/gdc.test/compilable/imports/b33a.d
@@ -6,10 +6,10 @@ struct IsEqual( T )
     {
 	return p1 == p2;
     }
-}    
+}
 
 template find_( Elem, Pred = IsEqual!(Elem) )
-{    
+{
     size_t fn( char[] buf, Pred pred = Pred.init )
     {
         return 3;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp22734.c b/gcc/testsuite/gdc.test/compilable/imports/imp22734.c
new file mode 100644
index 00000000000..9df542b5e0f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/imp22734.c
@@ -0,0 +1,3 @@
+typedef enum { C } E;
+
+int a = C;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test22714a.d b/gcc/testsuite/gdc.test/compilable/imports/test22714a.d
new file mode 100644
index 00000000000..7b77272a51b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test22714a.d
@@ -0,0 +1,3 @@
+module imports.test22714a;
+import imports.test22714b;
+class Statement {}
diff --git a/gcc/testsuite/gdc.test/compilable/imports/test22714b.d b/gcc/testsuite/gdc.test/compilable/imports/test22714b.d
new file mode 100644
index 00000000000..68bd95b1674
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/test22714b.d
@@ -0,0 +1,12 @@
+module imports.test22714b;
+import imports.test22714a;
+struct Array(T)
+{
+    T[] data;
+    T[1] smallarray;
+}
+struct Ensure
+{
+    Statement ensure;
+    Array!Ensure* arraySyntaxCopy;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/issue16472.d b/gcc/testsuite/gdc.test/compilable/issue16472.d
new file mode 100644
index 00000000000..a4353cee936
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue16472.d
@@ -0,0 +1,42 @@
+// https://issues.dlang.org/show_bug.cgi?id=16472
+enum e() = 0;
+
+template t(alias v = e!()) {} //Error
+alias dummy = t!(e!());
+
+template E(F){
+    enum E {
+        K = F(1)
+    }
+}
+
+struct S(F = float, alias e_ = E!double.K) {}
+S!float x; // Error: E!double.K is used as a type
+
+alias T = E!double.K;
+struct S2(F = float, alias e_ = T) {}
+S2!float y; // alias makes it okay...
+
+struct S3(F = float, alias e_ = (E!double.K)) {}
+S3!float z; // just putting parens make it okay as well... wat!?
+
+// for coverage
+
+template G(T)
+{
+    struct G
+    {
+        alias I = int;
+        static int i;
+    }
+}
+
+struct H(F = float, alias e_ = G!double) {}
+H!float a;
+
+struct H1(F = float, alias e_ = G!double.I) {}
+H1!float b;
+
+// https://issues.dlang.org/show_bug.cgi?id=21795
+// struct H2(F = float, alias e_ = G!double.i) {}
+// H2!float c;
diff --git a/gcc/testsuite/gdc.test/compilable/issue21340.d b/gcc/testsuite/gdc.test/compilable/issue21340.d
index 22eda6e3e02..03d37bdc61a 100644
--- a/gcc/testsuite/gdc.test/compilable/issue21340.d
+++ b/gcc/testsuite/gdc.test/compilable/issue21340.d
@@ -5,7 +5,7 @@ version (CppRuntime_Sun)   version = CppMangle_Itanium;
 template ScopeClass(C)
 if (is(C == class) && __traits(getLinkage, C) == "C++")
 {
-    
+
     extern(C++, class)
     extern(C++, __traits(getCppNamespaces,C))
     extern(C++, (ns))
@@ -35,4 +35,4 @@ alias ns = AliasSeq!();
 immutable ns2 = AliasSeq!();
 extern(C++,(ns)) class Bar {}
 extern(C++,) class Baz {}
-extern(C++, (ns2)) class Quux {} 
+extern(C++, (ns2)) class Quux {}
diff --git a/gcc/testsuite/gdc.test/compilable/issue21813b.d b/gcc/testsuite/gdc.test/compilable/issue21813b.d
index ef226971d87..0af986b34a6 100644
--- a/gcc/testsuite/gdc.test/compilable/issue21813b.d
+++ b/gcc/testsuite/gdc.test/compilable/issue21813b.d
@@ -4,7 +4,7 @@ Target.OS defaultTargetOS()
     return Target.OS.linux;
 }
 
-struct Target 
+struct Target
 {
     enum OS { linux }
     OS os = defaultTargetOS();
diff --git a/gcc/testsuite/gdc.test/compilable/minimal.d b/gcc/testsuite/gdc.test/compilable/minimal.d
index 63983288f30..155f0edb618 100644
--- a/gcc/testsuite/gdc.test/compilable/minimal.d
+++ b/gcc/testsuite/gdc.test/compilable/minimal.d
@@ -10,7 +10,7 @@
 
 struct S { }
 
-enum E 
+enum E
 {
     e0 = 0,
     e1 = 1
diff --git a/gcc/testsuite/gdc.test/compilable/test10993.d b/gcc/testsuite/gdc.test/compilable/test10993.d
index a69d0c616cf..9a99187aa06 100644
--- a/gcc/testsuite/gdc.test/compilable/test10993.d
+++ b/gcc/testsuite/gdc.test/compilable/test10993.d
@@ -19,7 +19,7 @@ auto fun()
 {
 	auto x = foo!()(test!(a=>a)());
 //	pragma(msg, "fun: " ~ typeof(x).mangleof);
-	
+
 	return x;
 }
 
diff --git a/gcc/testsuite/gdc.test/compilable/test16107.d b/gcc/testsuite/gdc.test/compilable/test16107.d
index 2267be3339f..3de4dd13c4b 100644
--- a/gcc/testsuite/gdc.test/compilable/test16107.d
+++ b/gcc/testsuite/gdc.test/compilable/test16107.d
@@ -3,12 +3,12 @@
 bool check()
 {
     bool result = false;
-    
+
     result |= false;
     if (result) goto ret;
-    
+
     result |= false;
     if (result) {}
-    
+
     ret: return true;
 }
diff --git a/gcc/testsuite/gdc.test/compilable/test17545.d b/gcc/testsuite/gdc.test/compilable/test17545.d
index bb0c2ae9ace..6285418b806 100644
--- a/gcc/testsuite/gdc.test/compilable/test17545.d
+++ b/gcc/testsuite/gdc.test/compilable/test17545.d
@@ -12,5 +12,5 @@ struct Attrib {}
 
 @Attrib enum TEST = 123;
 
-pragma(msg, __traits(getAttributes, 
+pragma(msg, __traits(getAttributes,
                      __traits(getMember, example, "TEST")));
diff --git a/gcc/testsuite/gdc.test/compilable/test17906.d b/gcc/testsuite/gdc.test/compilable/test17906.d
deleted file mode 100644
index 9c4a547a3e7..00000000000
--- a/gcc/testsuite/gdc.test/compilable/test17906.d
+++ /dev/null
@@ -1,7 +0,0 @@
-// REQUIRED_ARGS: -de
-// https://issues.dlang.org/show_bug.cgi?id=18647
-deprecated void main ()
-{
-    Object o = new Object;
-    delete o;
-}
diff --git a/gcc/testsuite/gdc.test/compilable/test18030.d b/gcc/testsuite/gdc.test/compilable/test18030.d
index f742a401afb..37f8630d2b1 100644
--- a/gcc/testsuite/gdc.test/compilable/test18030.d
+++ b/gcc/testsuite/gdc.test/compilable/test18030.d
@@ -9,6 +9,6 @@ struct S(T)
 class C
 {
 	alias Al = S!C;
-	
+
 	static void func(U)(U var) { }
 }
diff --git a/gcc/testsuite/gdc.test/compilable/test19014.d b/gcc/testsuite/gdc.test/compilable/test19014.d
index 7bbbc941abe..1110b28faeb 100644
--- a/gcc/testsuite/gdc.test/compilable/test19014.d
+++ b/gcc/testsuite/gdc.test/compilable/test19014.d
@@ -8,5 +8,5 @@ void main()
     {
     	static import core.stdc.math;
     }
-    static assert(!__traits(compiles, core.stdc.math.cos(0))); 
+    static assert(!__traits(compiles, core.stdc.math.cos(0)));
 }
diff --git a/gcc/testsuite/gdc.test/compilable/test19315.d b/gcc/testsuite/gdc.test/compilable/test19315.d
index 0c31ab84341..e95ecace07a 100644
--- a/gcc/testsuite/gdc.test/compilable/test19315.d
+++ b/gcc/testsuite/gdc.test/compilable/test19315.d
@@ -1,5 +1,5 @@
 //https://issues.dlang.org/show_bug.cgi?id=19315
-void main() 
+void main()
 {
     #line 100 "file.d"
     enum code = q{
diff --git a/gcc/testsuite/gdc.test/compilable/test19557.d b/gcc/testsuite/gdc.test/compilable/test19557.d
index f107e228a48..b11ae1095cd 100644
--- a/gcc/testsuite/gdc.test/compilable/test19557.d
+++ b/gcc/testsuite/gdc.test/compilable/test19557.d
@@ -1,6 +1,6 @@
 // https://issues.dlang.org/show_bug.cgi?id=19557
 // Error: redundant linkage `extern (C++)`
-    
+
 extern(C++, "ns")
 extern(C++, class)
 struct test {}
diff --git a/gcc/testsuite/gdc.test/compilable/test19609.d b/gcc/testsuite/gdc.test/compilable/test19609.d
index 4367df153b7..df8f891ec8f 100644
--- a/gcc/testsuite/gdc.test/compilable/test19609.d
+++ b/gcc/testsuite/gdc.test/compilable/test19609.d
@@ -3,9 +3,9 @@
 /*
 TEST_OUTPUT:
 ---
-compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated - 
+compilable/test19609.d(11): Deprecation: module `imports.test19609a` is deprecated
 compilable/test19609.d(12): Deprecation: module `imports.test19609b` is deprecated - hello
-compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated -
+compilable/test19609.d(13): Deprecation: module `imports.test19609c` is deprecated
 ---
 */
 import imports.test19609a;
diff --git a/gcc/testsuite/gdc.test/compilable/test21177.d b/gcc/testsuite/gdc.test/compilable/test21177.d
new file mode 100644
index 00000000000..b3b613bc0e9
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21177.d
@@ -0,0 +1,76 @@
+// https://issues.dlang.org/show_bug.cgi?id=21177
+/*
+DISABLED: win
+TEST_OUTPUT:
+---
+compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments
+compilable/test21177.d(203): Deprecation: format specifier `"%m"` is invalid
+compilable/test21177.d(204): Deprecation: format specifier `"%m"` is invalid
+compilable/test21177.d(205): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*`
+compilable/test21177.d(206): Deprecation: argument `c` for format specification `"%a"` must be `float*`, not `char*`
+---
+*/
+
+import core.stdc.stdio;
+import core.stdc.string;
+import core.stdc.stdlib;
+
+void main()
+{
+    version (CRuntime_Glibc)
+    {
+        #line 100
+        printf("%m this is a string in errno");
+        printf("%s %m", "str".ptr, 2);
+        printf("%a", 2.);
+        printf("%m %m %s");
+        printf("%*m");
+
+        char* a, b;
+        sscanf("salut poilu", "%a %m", a, b);
+        assert(!strcmp(a, b));
+        free(a);
+        free(b);
+
+        char* t, p;
+        sscanf("Tomate Patate", "%ms %as", t, p);
+        free(t);
+        free(p);
+
+        #line 150
+        sscanf("150", "%m");
+        sscanf("151", "%ms");
+        sscanf("152", "%a");
+        sscanf("153", "%as");
+
+        pragma(msg, "compilable/test21177.d(200): Deprecation: more format specifiers than 0 arguments");
+        pragma(msg, "compilable/test21177.d(203): Deprecation: format specifier `\"%m\"` is invalid");
+        pragma(msg, "compilable/test21177.d(204): Deprecation: format specifier `\"%m\"` is invalid");
+        pragma(msg, "compilable/test21177.d(205): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`");
+        pragma(msg, "compilable/test21177.d(206): Deprecation: argument `c` for format specification `\"%a\"` must be `float*`, not `char*`");
+    }
+    else
+    {
+        // fake it
+        pragma(msg, "compilable/test21177.d(103): Deprecation: more format specifiers than 0 arguments");
+        pragma(msg, "compilable/test21177.d(150): Deprecation: more format specifiers than 0 arguments");
+        pragma(msg, "compilable/test21177.d(151): Deprecation: more format specifiers than 0 arguments");
+        pragma(msg, "compilable/test21177.d(152): Deprecation: more format specifiers than 0 arguments");
+        pragma(msg, "compilable/test21177.d(153): Deprecation: more format specifiers than 0 arguments");
+
+        #line 200
+        printf("%m");
+
+        char* c;
+        sscanf("204", "%m", c);
+        sscanf("205", "%ms", c);
+        sscanf("206", "%a", c);
+        sscanf("207", "%as", c);
+
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test21196.d b/gcc/testsuite/gdc.test/compilable/test21196.d
new file mode 100644
index 00000000000..f8507b434f2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test21196.d
@@ -0,0 +1,71 @@
+// https://issues.dlang.org/show_bug.cgi?id=21674
+// REQUIRED_ARGS: -de
+
+struct Module
+{
+    CachedString data;
+}
+
+struct CachedString
+{
+    private size_t len;
+
+    this (string data) { this.len = data.length; }
+    public string str () const { return null; }
+    public void str (string value) { this.len = value.length; }
+
+    alias str this;
+}
+
+void test21674a()
+{
+    Module m;
+    m.data = "Hello World";
+}
+
+//////////////////////////////////////////
+
+struct StaticGetter(T)
+{
+    private static T _impl;
+    static ref T value() { return _impl; }
+    alias value this;
+}
+
+struct StaticWrapper
+{
+    StaticGetter!int get;
+    alias get this;
+}
+
+void test21674b()
+{
+    StaticGetter!float sg;
+    sg = 4.2;
+
+    StaticWrapper sw;
+    sw = 42;
+}
+
+//////////////////////////////////////////
+
+EntryType arr;
+auto getPtr() { return &arr; }
+
+struct EntryType
+{
+    bool _state;
+    alias _state this;
+}
+
+struct S19441
+{
+    @property auto ref entry() { return *getPtr(); }
+    alias entry this;
+}
+
+void test19441()
+{
+    S19441 s19441;
+    s19441 = true;
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22224.d b/gcc/testsuite/gdc.test/compilable/test22224.d
index d16b2f4023d..ef131e998c3 100644
--- a/gcc/testsuite/gdc.test/compilable/test22224.d
+++ b/gcc/testsuite/gdc.test/compilable/test22224.d
@@ -1,4 +1,4 @@
 // REQUIRED_ARGS: -profile -c
 
-import core.stdc.stdarg; 
+import core.stdc.stdarg;
 void error(...) { }
diff --git a/gcc/testsuite/gdc.test/compilable/test22632.d b/gcc/testsuite/gdc.test/compilable/test22632.d
new file mode 100644
index 00000000000..673b51b00f0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22632.d
@@ -0,0 +1,4 @@
+// https://issues.dlang.org/show_bug.cgi?id=22632
+
+static assert(["one": 1] != null);
+static assert(null != ["one": 1]);
diff --git a/gcc/testsuite/gdc.test/compilable/test22714.d b/gcc/testsuite/gdc.test/compilable/test22714.d
new file mode 100644
index 00000000000..2973e1d0c27
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22714.d
@@ -0,0 +1,3 @@
+// EXTRA_FILES: imports/test22714a.d imports/test22714b.d
+// https://issues.dlang.org/show_bug.cgi?id=22714
+import imports.test22714a;
diff --git a/gcc/testsuite/gdc.test/compilable/test22734.d b/gcc/testsuite/gdc.test/compilable/test22734.d
new file mode 100644
index 00000000000..fdd962eedb4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22734.d
@@ -0,0 +1,6 @@
+// https://issues.dlang.org/show_bug.cgi?id=22734
+// EXTRA_FILES: imports/imp22734.c
+
+import imports.imp22734;
+
+auto dc = C;
diff --git a/gcc/testsuite/gdc.test/compilable/test4375.d b/gcc/testsuite/gdc.test/compilable/test4375.d
index f5c4e4a9b40..1cc7a3a1c2e 100644
--- a/gcc/testsuite/gdc.test/compilable/test4375.d
+++ b/gcc/testsuite/gdc.test/compilable/test4375.d
@@ -256,7 +256,7 @@ label1:
                         else
                             assert(89);
     else
-        assert(12); 
+        assert(12);
 
 
     with (x)
@@ -299,7 +299,7 @@ label1:
             if (true)
                 assert(110);
             else
-                assert(112);                
+                assert(112);
         finally
             assert(111);
 
@@ -316,7 +316,7 @@ label1:
             int w;
 
         static if (true)
-            int t; 
+            int t;
         else static if (false)
             int u;
         else
diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d
index 859f29a13e5..a4cf663066e 100644
--- a/gcc/testsuite/gdc.test/compilable/test7172.d
+++ b/gcc/testsuite/gdc.test/compilable/test7172.d
@@ -7,7 +7,7 @@ void main()
     static assert(!__traits(compiles, { class D : FinalC{} }));
 
     scope class ScopeC{}
-//    static assert(!__traits(compiles, { auto  sc = new ScopeC(); }));
+    static assert(!__traits(compiles, { auto  sc = new ScopeC(); }));
     static assert( __traits(compiles, { scope sc = new ScopeC(); }));
 
     synchronized class SyncC{ void f(){} }
diff --git a/gcc/testsuite/gdc.test/compilable/test8296.d b/gcc/testsuite/gdc.test/compilable/test8296.d
index d27ba15f3e0..cd175b55322 100644
--- a/gcc/testsuite/gdc.test/compilable/test8296.d
+++ b/gcc/testsuite/gdc.test/compilable/test8296.d
@@ -10,7 +10,7 @@ struct bar2
 
 class InnerBar {
   bar2 b;
-  
+
   this()
   {
     b = bar2(0);
@@ -21,7 +21,7 @@ struct bar1
 {
   InnerBar b;
 }
-  
+
 class Foo
 {
   bar1 m_bar1;
diff --git a/gcc/testsuite/gdc.test/compilable/test8513.d b/gcc/testsuite/gdc.test/compilable/test8513.d
index bcdc657be93..4b5d5120502 100644
--- a/gcc/testsuite/gdc.test/compilable/test8513.d
+++ b/gcc/testsuite/gdc.test/compilable/test8513.d
@@ -5,25 +5,25 @@ class Bar
 {
     interface I_Foo { void i_inner(); }
     class C_Foo { void c_inner() { } }
-    
+
     class Impl1 : C_Foo, I_Foo
     {
         override void i_inner() { }
         override void c_inner() { }
     }
-    
+
     class Impl2 : C_Foo, .I_Foo
     {
         override void i_outer() { }
         override void c_inner() { }
     }
-    
+
     class Impl3 : .C_Foo, I_Foo
     {
         override void i_inner() { }
         override void c_outer() { }
     }
-    
+
     class Impl4 : .C_Foo, .I_Foo
     {
         override void i_outer() { }
diff --git a/gcc/testsuite/gdc.test/compilable/testpostblit.d b/gcc/testsuite/gdc.test/compilable/testpostblit.d
index 60a0f4a1ce9..dff4bc59eb9 100644
--- a/gcc/testsuite/gdc.test/compilable/testpostblit.d
+++ b/gcc/testsuite/gdc.test/compilable/testpostblit.d
@@ -14,4 +14,4 @@ struct Test1c
 {
     const Test1b b;
     @disable this(this);
-} 
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testsctreturn.d b/gcc/testsuite/gdc.test/compilable/testsctreturn.d
index 96b82da922f..7826cd4894d 100644
--- a/gcc/testsuite/gdc.test/compilable/testsctreturn.d
+++ b/gcc/testsuite/gdc.test/compilable/testsctreturn.d
@@ -17,3 +17,19 @@ void test()
     size_t* p;
     const ppi = const(PackedPtrImpl!(3))(p);
 }
+
+/************************************************/
+
+// issues.dlang.org/show_bug.cgi?id=22541
+
+struct S
+{
+    int i;
+    int* ptr;
+
+    int* wannabeReturnRef() scope return
+    {
+        return &i;
+    }
+}
+
diff --git a/gcc/testsuite/gdc.test/compilable/typeid_name.d b/gcc/testsuite/gdc.test/compilable/typeid_name.d
index e77d5c80a75..b2292bf60d7 100644
--- a/gcc/testsuite/gdc.test/compilable/typeid_name.d
+++ b/gcc/testsuite/gdc.test/compilable/typeid_name.d
@@ -9,6 +9,6 @@ class Panzer {}
 class Tiger : Panzer {}
 
 static assert (() {
-    Panzer p = new Tiger(); return classname(p); 
+    Panzer p = new Tiger(); return classname(p);
 } () == "Tiger");
 
diff --git a/gcc/testsuite/gdc.test/compilable/vgc1.d b/gcc/testsuite/gdc.test/compilable/vgc1.d
index 8a11657ac3d..8bfe1d079e2 100644
--- a/gcc/testsuite/gdc.test/compilable/vgc1.d
+++ b/gcc/testsuite/gdc.test/compilable/vgc1.d
@@ -65,20 +65,9 @@ void testNewScope()
 
 /***************** DeleteExp *******************/
 
-/*
-TEST_OUTPUT:
----
-compilable/vgc1.d(81): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-compilable/vgc1.d(81): vgc: `delete` requires the GC
-compilable/vgc1.d(82): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-compilable/vgc1.d(82): vgc: `delete` requires the GC
-compilable/vgc1.d(83): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-compilable/vgc1.d(83): vgc: `delete` requires the GC
----
-*/
 void testDelete(int* p, Object o, S1* s)
 {
-    delete p;
-    delete o;
-    delete s;
+    destroy(p);
+    destroy(o);
+    destroy(s);
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
index 669dd1073c9..7baad47f378 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
@@ -37,4 +37,4 @@ void main()
     assignableByRef(s1.member);
     assignableByOut(s1.member);
     assignableByConstRef(s1.member);
-} 
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b3841.d b/gcc/testsuite/gdc.test/fail_compilation/b3841.d
index ceddc87ddd8..0dda8bdd3a4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b3841.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b3841.d
@@ -47,7 +47,7 @@ void main()
         f!(op, long, short)();
         f!(op, float, long)();
         f!(op, double, float)();
-        
+
         // Should that really be OK ?
         f!(op, short, int)();
         f!(op, float, double)();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
index 1818e0d68f6..ca9879733ce 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug16165.d
@@ -7,7 +7,7 @@ void g()
 	f(5, 6, 404);
 }
 
-/* 
+/*
 TEST_OUTPUT:
 ---
 fail_compilation/bug16165.d(6): Error: function `bug16165.f(int x, Object y)` is not callable using argument types `(Object, Object, int)`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d
index a03f850ae80..fab12c20b84 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150a.d
@@ -3,7 +3,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/bug8150a.d(14): Error: `object.Exception` is thrown but not caught
-fail_compilation/bug8150a.d(12): Error: `nothrow` constructor `bug8150a.Foo.this` may throw
+fail_compilation/bug8150a.d(12): Error: constructor `bug8150a.Foo.this` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d
index 2091bc8cc2d..606b628270b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug8150b.d
@@ -3,7 +3,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/bug8150b.d(15): Error: `object.Exception` is thrown but not caught
-fail_compilation/bug8150b.d(13): Error: `nothrow` constructor `bug8150b.Foo.__ctor!().this` may throw
+fail_compilation/bug8150b.d(13): Error: constructor `bug8150b.Foo.__ctor!().this` may throw but is marked as `nothrow`
 fail_compilation/bug8150b.d(20): Error: template instance `bug8150b.Foo.__ctor!()` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ccast.d b/gcc/testsuite/gdc.test/fail_compilation/ccast.d
index b4897d469f3..dab29844158 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ccast.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ccast.d
@@ -1,4 +1,4 @@
-/* 
+/*
 TEST_OUTPUT:
 ---
 fail_compilation/ccast.d(9): Error: C style cast illegal, use `cast(byte)i`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d
index 78e0891f3d6..0f12d99f8cd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctfe14731.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `["a b"]` of type `string[]` to `string`
+fail_compilation/ctfe14731.d(16): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string`
 fail_compilation/ctfe14731.d(17): Error: cannot implicitly convert expression `split("a b")` of type `string[]` to `string`
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
index 4a01c5435b6..416d56310e1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10319.d
@@ -9,7 +9,7 @@ fail_compilation/diag10319.d(28): Error: `@safe` function `D main` cannot call `
 fail_compilation/diag10319.d(18):        `diag10319.bar!int.bar` is declared here
 fail_compilation/diag10319.d(27): Error: function `diag10319.foo` is not `nothrow`
 fail_compilation/diag10319.d(28): Error: function `diag10319.bar!int.bar` is not `nothrow`
-fail_compilation/diag10319.d(25): Error: `nothrow` function `D main` may throw
+fail_compilation/diag10319.d(25): Error: function `D main` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
index 3b5df6ebccf..ed38167b4c4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10805.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag10805.d(12): Error: delimited string must end in FOO"
+fail_compilation/diag10805.d(12): Error: delimited string must end in `FOO"`
 fail_compilation/diag10805.d(14): Error: unterminated string constant starting at fail_compilation/diag10805.d(14)
 fail_compilation/diag10805.d(14): Error: Implicit string concatenation is error-prone and disallowed in D
 fail_compilation/diag10805.d(14):        Use the explicit syntax instead (concatenating literals is `@nogc`): "" ~ ""
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag13281.d b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d
index c59b300900d..fc0d9f54dff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag13281.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag13281.d
@@ -11,9 +11,9 @@ fail_compilation/diag13281.d(26): Error: cannot implicitly convert expression `1
 fail_compilation/diag13281.d(27): Error: cannot implicitly convert expression `123.4i` of type `idouble` to `int`
 fail_compilation/diag13281.d(28): Error: cannot implicitly convert expression `123.4Fi` of type `ifloat` to `int`
 fail_compilation/diag13281.d(29): Error: cannot implicitly convert expression `123.4Li` of type `ireal` to `int`
-fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `(123.4+5.6i)` of type `cdouble` to `int`
-fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `(123.4F+5.6Fi)` of type `cfloat` to `int`
-fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `(123.4L+5.6Li)` of type `creal` to `int`
+fail_compilation/diag13281.d(30): Error: cannot implicitly convert expression `123.4 + 5.6i` of type `cdouble` to `int`
+fail_compilation/diag13281.d(31): Error: cannot implicitly convert expression `123.4F + 5.6Fi` of type `cfloat` to `int`
+fail_compilation/diag13281.d(32): Error: cannot implicitly convert expression `123.4L + 5.6Li` of type `creal` to `int`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
index 34fc645061b..1c614083bfc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15713.d
@@ -2,8 +2,8 @@
 TEST_OUTPUT:
 ---
 fail_compilation/diag15713.d(19): Error: no property `widthSign` for type `diag15713.WrData.Data`
-fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\x0a", Data(null))` error instantiating
-fail_compilation/diag15713.d(44):        instantiated from here: `conwritefImpl!("main", "\x0a", Data(null))`
+fail_compilation/diag15713.d(39): Error: template instance `diag15713.conwritefImpl!("parse-int", "width", "\n", Data(null))` error instantiating
+fail_compilation/diag15713.d(44):        instantiated from here: `conwritefImpl!("main", "\n", Data(null))`
 fail_compilation/diag15713.d(49):        instantiated from here: `fdwritef!()`
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
index 9d8dcfdca0c..73d628584d5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag16977.d
@@ -13,7 +13,7 @@ fail_compilation/diag16977.d(30): Error: template instance `diag16977.test.funcT
 ---
 */
 
-// when copying the expression of a default argument, location information is 
+// when copying the expression of a default argument, location information is
 //   replaced by the location of the caller to improve debug information
 // verify error messages are displayed for the original location only
 
@@ -26,7 +26,7 @@ void test()
     void badOp(int x, int y = 1 ~ "string") {}
     void lazyTemplate(int x, lazy int y = 4.templ) {}
     void funcTemplate(T)(T y = 5) {}
-    
+
     funcTemplate!string();
     undefinedId(1);
     badOp(2);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
index 05c5d30c5ed..21a12ed0253 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dtor_attributes.d
@@ -20,7 +20,7 @@ fail_compilation/dtor_attributes.d(118): Error: destructor `dtor_attributes.Stri
 fail_compilation/dtor_attributes.d(113):        generated `Strict.~this` is not nothrow because of the following field's destructors:
 fail_compilation/dtor_attributes.d(111):         - HasDtor member
 fail_compilation/dtor_attributes.d(103):           not nothrow `HasDtor.~this` is declared here
-fail_compilation/dtor_attributes.d(116): Error: `nothrow` function `dtor_attributes.test1` may throw
+fail_compilation/dtor_attributes.d(116): Error: function `dtor_attributes.test1` may throw but is marked as `nothrow`
 ---
 */
 #line 100
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
index de3673f7860..9f38cb04069 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10964.d
@@ -7,7 +7,7 @@ fail_compilation/fail10964.d(30): Error: function `fail10964.S.__postblit` is no
 fail_compilation/fail10964.d(33): Error: function `fail10964.S.__postblit` is not `nothrow`
 fail_compilation/fail10964.d(34): Error: function `fail10964.S.__postblit` is not `nothrow`
 fail_compilation/fail10964.d(35): Error: function `fail10964.S.__postblit` is not `nothrow`
-fail_compilation/fail10964.d(22): Error: `nothrow` function `fail10964.foo` may throw
+fail_compilation/fail10964.d(22): Error: function `fail10964.foo` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
index 4f221bfd5e5..7592a5a1dfd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11375.d
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail11375.d(17): Error: constructor `fail11375.D!().D.this` is not `nothrow`
-fail_compilation/fail11375.d(15): Error: `nothrow` function `D main` may throw
+fail_compilation/fail11375.d(15): Error: function `D main` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
index 0198f64a871..3c2f9c13a7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11542.d
@@ -4,9 +4,9 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail11542.d(15): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(12): Error: `nothrow` function `fail11542.test_success1` may throw
+fail_compilation/fail11542.d(12): Error: function `fail11542.test_success1` may throw but is marked as `nothrow`
 fail_compilation/fail11542.d(25): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(22): Error: `nothrow` function `fail11542.test_success3` may throw
+fail_compilation/fail11542.d(22): Error: function `fail11542.test_success3` may throw but is marked as `nothrow`
 ---
 */
 void test_success1() nothrow
@@ -29,7 +29,7 @@ void test_success3() nothrow
 TEST_OUTPUT:
 ---
 fail_compilation/fail11542.d(38): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(35): Error: `nothrow` function `fail11542.test_failure1` may throw
+fail_compilation/fail11542.d(35): Error: function `fail11542.test_failure1` may throw but is marked as `nothrow`
 ---
 */
 void test_failure1() nothrow
@@ -52,7 +52,7 @@ void est_failure3() nothrow
 TEST_OUTPUT:
 ---
 fail_compilation/fail11542.d(61): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail11542.d(58): Error: `nothrow` function `fail11542.test_exit1` may throw
+fail_compilation/fail11542.d(58): Error: function `fail11542.test_exit1` may throw but is marked as `nothrow`
 ---
 */
 void test_exit1() nothrow
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
index a5e9f721580..65e89b196c7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12809.d
@@ -6,10 +6,10 @@ bool cond;
 TEST_OUTPUT:
 ---
 fail_compilation/fail12809.d(18): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(15): Error: `nothrow` function `fail12809.test_finally1` may throw
+fail_compilation/fail12809.d(15): Error: function `fail12809.test_finally1` may throw but is marked as `nothrow`
 fail_compilation/fail12809.d(34): Error: `object.Exception` is thrown but not caught
 fail_compilation/fail12809.d(38): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(31): Error: `nothrow` function `fail12809.test_finally3` may throw
+fail_compilation/fail12809.d(31): Error: function `fail12809.test_finally3` may throw but is marked as `nothrow`
 ---
 */
 void test_finally1() nothrow
@@ -44,10 +44,10 @@ void test_finally3() nothrow
 TEST_OUTPUT:
 ---
 fail_compilation/fail12809.d(58): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(53): Error: `nothrow` function `fail12809.test_finally4` may throw
+fail_compilation/fail12809.d(53): Error: function `fail12809.test_finally4` may throw but is marked as `nothrow`
 fail_compilation/fail12809.d(74): Error: `object.Exception` is thrown but not caught
 fail_compilation/fail12809.d(78): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail12809.d(69): Error: `nothrow` function `fail12809.test_finally6` may throw
+fail_compilation/fail12809.d(69): Error: function `fail12809.test_finally6` may throw but is marked as `nothrow`
 ---
 */
 void test_finally4() nothrow
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14277.d b/gcc/testsuite/gdc.test/fail_compilation/fail14277.d
new file mode 100644
index 00000000000..fd6e618c0ce
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14277.d
@@ -0,0 +1,10 @@
+// https://issues.dlang.org/show_bug.cgi?id=14277
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail14277.d(10): Error: cannot implicitly convert expression `new char[](9999$?:32=u|64=LU$)` of type `char[]` to `ubyte[]`
+---
+*/
+
+ubyte[] u = new char[9999];
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
index 07152f4bb45..c7a2b89f448 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14486.d
@@ -3,39 +3,18 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail14486.d(56): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(56): Error: `delete c0` is not `@safe` but is used in `@safe` function `test1a`
-fail_compilation/fail14486.d(57): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(57): Error: `pure` function `fail14486.test1a` cannot call impure destructor `fail14486.C1a.~this`
-fail_compilation/fail14486.d(57): Error: `@safe` function `fail14486.test1a` cannot call `@system` destructor `fail14486.C1a.~this`
-fail_compilation/fail14486.d(43):        `fail14486.C1a.~this` is declared here
-fail_compilation/fail14486.d(57): Error: `@nogc` function `fail14486.test1a` cannot call non-@nogc destructor `fail14486.C1a.~this`
-fail_compilation/fail14486.d(62): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(63): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(63): Error: destructor `fail14486.C1b.~this` is not `nothrow`
-fail_compilation/fail14486.d(60): Error: `nothrow` function `fail14486.test1b` may throw
-fail_compilation/fail14486.d(68): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(68): Error: `delete s0` is not `@safe` but is used in `@safe` function `test2a`
-fail_compilation/fail14486.d(69): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(69): Error: `pure` function `fail14486.test2a` cannot call impure destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(69): Error: `@safe` function `fail14486.test2a` cannot call `@system` destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(49):        `fail14486.S1a.~this` is declared here
-fail_compilation/fail14486.d(69): Error: `@nogc` function `fail14486.test2a` cannot call non-@nogc destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(74): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(75): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(75): Error: destructor `fail14486.S1b.~this` is not `nothrow`
-fail_compilation/fail14486.d(72): Error: `nothrow` function `fail14486.test2b` may throw
-fail_compilation/fail14486.d(80): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(80): Error: `delete a0` is not `@safe` but is used in `@safe` function `test3a`
-fail_compilation/fail14486.d(81): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(81): Error: `pure` function `fail14486.test3a` cannot call impure destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(81): Error: `@safe` function `fail14486.test3a` cannot call `@system` destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(49):        `fail14486.S1a.~this` is declared here
-fail_compilation/fail14486.d(81): Error: `@nogc` function `fail14486.test3a` cannot call non-@nogc destructor `fail14486.S1a.~this`
-fail_compilation/fail14486.d(86): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(87): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail14486.d(87): Error: destructor `fail14486.S1b.~this` is not `nothrow`
-fail_compilation/fail14486.d(84): Error: `nothrow` function `fail14486.test3b` may throw
+fail_compilation/fail14486.d(35): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(36): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(41): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(42): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(47): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(48): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(53): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(54): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(59): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(60): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(65): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+fail_compilation/fail14486.d(66): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
index 73b0a780023..b71a68e2322 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail14554.d
@@ -25,6 +25,6 @@ struct issue14554_2 {
 
 void test14554()
 {
-     issue14554_1.foo!bool(1);    
-     issue14554_2.foo!bool(1);    
+     issue14554_1.foo!bool(1);
+     issue14554_2.foo!bool(1);
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail15089.d b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d
index 221a97871bf..9aa94f863df 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail15089.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail15089.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `130` of type `int` to `byte`
+fail_compilation/fail15089.d(10): Error: cannot implicitly convert expression `2 ^ 128` of type `int` to `byte`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail160.d b/gcc/testsuite/gdc.test/fail_compilation/fail160.d
index c07c8d36091..0c8a9378b64 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail160.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail160.d
@@ -14,7 +14,7 @@ template Wrapper(B, alias Func, int func)
     alias typeof(&Func) FuncPtr;
 
     private static FuncPtr get_funcptr() { return func; }
-} 
+}
 
 
 int main(char[][] args)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17906.d b/gcc/testsuite/gdc.test/fail_compilation/fail17906.d
new file mode 100644
index 00000000000..689dd489c95
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17906.d
@@ -0,0 +1,12 @@
+// REQUIRED_ARGS: -de
+/* TEST_OUTPUT:
+---
+fail_compilation/fail17906.d(11): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=18647
+deprecated void main ()
+{
+    Object o = new Object;
+    delete o;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
index 57fabbb7ec8..e6b95564b44 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
@@ -4,7 +4,7 @@ fail_compilation/fail17969.d(9): Error: no property `sum` for type `fail17969.__
 ---
  * https://issues.dlang.org/show_bug.cgi?id=17969
  */
- 
+
 
 alias fun = a => MapResult2!(b => b).sum;
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18228.d b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d
index 983719a728b..8da0b8d4437 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail18228.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18228.d
@@ -1,9 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail18228.d(12): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead
-fail_compilation/fail18228.d(13): Error: Using `this` as a type is obsolete. Use `typeof(this)` instead
-fail_compilation/fail18228.d(14): Error: Using `super` as a type is obsolete. Use `typeof(super)` instead
+fail_compilation/fail18228.d(12): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail18228.d(13): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail18228.d(14): Error: undefined identifier `super`, did you mean `typeof(super)`?
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19441.d b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d
index f1f17699c90..520eb763b9b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19441.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19441.d
@@ -2,7 +2,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail19441.d(44): Deprecation: Cannot use `alias this` to partially initialize variable `wrap[0]` of type `Wrap10595`. Use `wrap[0].i`
+fail_compilation/fail19441.d(44): Error: cannot use `alias this` to partially initialize variable `wrap[0]` of type `Wrap10595`. Use `wrap[0].i`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail196.d b/gcc/testsuite/gdc.test/fail_compilation/fail196.d
index c7b28cf8521..55c3bd89ff9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail196.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail196.d
@@ -1,14 +1,14 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail196.d(27): Error: delimited string must end in )"
+fail_compilation/fail196.d(27): Error: delimited string must end in `)"`
 fail_compilation/fail196.d(27): Error: Implicit string concatenation is error-prone and disallowed in D
-fail_compilation/fail196.d(27):        Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\x0a    assert(s == "
+fail_compilation/fail196.d(27):        Use the explicit syntax instead (concatenating literals is `@nogc`): "foo(xxx)" ~ ";\n    assert(s == "
 fail_compilation/fail196.d(28): Error: semicolon needed to end declaration of `s`, instead of `foo`
 fail_compilation/fail196.d(27):        `s` declared here
-fail_compilation/fail196.d(28): Error: found `");\x0a\x0a    s = q"` when expecting `;` following statement
-fail_compilation/fail196.d(30): Error: found `";\x0a    assert(s == "` when expecting `;` following statement
-fail_compilation/fail196.d(31): Error: found `");\x0a\x0a    s = q"` when expecting `;` following statement
+fail_compilation/fail196.d(28): Error: found `");\n\n    s = q"` when expecting `;` following statement
+fail_compilation/fail196.d(30): Error: found `";\n    assert(s == "` when expecting `;` following statement
+fail_compilation/fail196.d(31): Error: found `");\n\n    s = q"` when expecting `;` following statement
 fail_compilation/fail196.d(33): Error: found `{` when expecting `;` following statement
 fail_compilation/fail196.d(33): Error: found `}` when expecting `;` following statement
 fail_compilation/fail196.d(34): Error: found `foo` when expecting `;` following statement
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
index 4f5804bc713..49df4706777 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19897.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail19897.d(9): Error: cannot implicitly convert expression `[]` of type `const(char[0])` to `const(char)`
+fail_compilation/fail19897.d(12): Error: cannot implicitly convert expression `a.x` of type `const(char[0])` to `const(char)`
 ---
 */
 struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
index c5d6a8ac47d..9f2dbbb81ab 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911b.d
@@ -1,4 +1,4 @@
-/* 
+/*
 DFLAGS:
 EXTRA_SOURCES: extra-files/minimal/object.d
 TEST_OUTPUT:
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
index fbd74064547..c1c654942c6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19911c.d
@@ -1,4 +1,4 @@
-/* 
+/*
 DFLAGS:
 TEST_OUTPUT:
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
index 201b1247246..1476666414c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19922.d
@@ -1,4 +1,4 @@
-/* 
+/*
 DFLAGS:
 TEST_OUTPUT:
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
index 1438151329b..d98dd03fd85 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19923.d
@@ -1,4 +1,4 @@
-/* 
+/*
 DFLAGS:
 TEST_OUTPUT:
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20.d b/gcc/testsuite/gdc.test/fail_compilation/fail20.d
index 6cc4d22559b..4528d365da8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20.d
@@ -14,6 +14,6 @@ void main()
     FOO one;
     FOO two;
     if (one < two){} // This should tell me that there
-                     // is no opCmp() defined instead 
+                     // is no opCmp() defined instead
                      // of crashing.
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d
index 1184b8e6ee8..185baecd0a2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20800.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20800.d
@@ -15,7 +15,7 @@ struct RegexMatch
 }
 static m() { return RegexMatch(); }
 
-void fun(int a); 
+void fun(int a);
 
 void initCommands()
 {
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22127.d b/gcc/testsuite/gdc.test/fail_compilation/fail22127.d
new file mode 100644
index 00000000000..c6e3684289e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22127.d
@@ -0,0 +1,11 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22127.d(101): Error: user-defined attributes are not allowed on `alias` declarations
+---
+ */
+
+// https://issues.dlang.org/show_bug.cgi?id=22127
+
+#line 100
+
+alias getOne = @(0) function int () => 1;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22634.d b/gcc/testsuite/gdc.test/fail_compilation/fail22634.d
new file mode 100644
index 00000000000..320d1eb07f4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22634.d
@@ -0,0 +1,12 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22634.d(9): Error: more than 65535 symbols with name `i` generated
+---
+*/
+void main()
+{
+    static foreach(i; 0..65537)
+    {
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d
new file mode 100644
index 00000000000..dd83f75e9c2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d
@@ -0,0 +1,12 @@
+// https://issues.dlang.org/show_bug.cgi?id=22780
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22780.d(11): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope`
+---
+*/
+scope class C10717 { }
+
+void test10717()
+{
+    C10717 c;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
index a969495ccd2..57edd3a0edd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail2361.d
@@ -1,8 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail2361.d(14): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail2361.d(14): Error: cannot modify `immutable` expression `c`
+fail_compilation/fail2361.d(13): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail258.d b/gcc/testsuite/gdc.test/fail_compilation/fail258.d
index 459d2715c26..63cbfd43cf5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail258.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail258.d
@@ -1,13 +1,15 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail258.d(11): Error: delimiter cannot be whitespace
-fail_compilation/fail258.d(11): Error: delimited string must end in 
-"
-fail_compilation/fail258.d(11): Error: declaration expected, not `"X"`
-fail_compilation/fail258.d(14): Error: unterminated string constant starting at fail_compilation/fail258.d(14)
+fail_compilation/fail258.d(101): Error: delimiter cannot be whitespace
+fail_compilation/fail258.d(101): Error: delimited string must end in `"`
+fail_compilation/fail258.d(101): Error: declaration expected, not `"X"`
+fail_compilation/fail258.d(104): Error: unterminated string constant starting at fail_compilation/fail258.d(104)
 ---
 */
+
+#line 100
+
 q"
 X
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail332.d b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
index 12164b92e9a..91f80464705 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail332.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail332.d
@@ -21,7 +21,7 @@ void test()
 {
     foo();
     foo(null);
-    
+
     baz("");
     baz(3, null);
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail349.d b/gcc/testsuite/gdc.test/fail_compilation/fail349.d
index 11a392c158c..215453ebe75 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail349.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail349.d
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail349.d(15): Error: function `fail349.bug6109throwing` is not `nothrow`
-fail_compilation/fail349.d(13): Error: `nothrow` function `fail349.bug6109noThrow` may throw
+fail_compilation/fail349.d(13): Error: function `fail349.bug6109noThrow` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail354.d b/gcc/testsuite/gdc.test/fail_compilation/fail354.d
index 8689f619857..2795acc1059 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail354.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail354.d
@@ -10,4 +10,4 @@ struct S(int N)
 {
     this(T!N) { }
 }
-alias S!1 M; 
+alias S!1 M;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
index 6f9ee613223..a09f725754b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4082.d
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail4082.d(14): Error: destructor `fail4082.Foo.~this` is not `nothrow`
-fail_compilation/fail4082.d(12): Error: `nothrow` function `fail4082.test1` may throw
+fail_compilation/fail4082.d(12): Error: function `fail4082.test1` may throw but is marked as `nothrow`
 ---
 */
 struct Foo
@@ -22,7 +22,7 @@ NEXT:
 TEST_OUTPUT:
 ---
 fail_compilation/fail4082.d(32): Error: destructor `fail4082.Bar.~this` is not `nothrow`
-fail_compilation/fail4082.d(32): Error: `nothrow` function `fail4082.test2` may throw
+fail_compilation/fail4082.d(32): Error: function `fail4082.test2` may throw but is marked as `nothrow`
 ---
 */
 struct Bar
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d
index 6604f1f7fc7..69b142eb342 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269a.d
@@ -10,6 +10,6 @@ enum bool WWW = is(typeof(A.x));
 
 interface A {
     B blah;
-    void foo(B b){} 
+    void foo(B b){}
 }
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d
index 253013344fc..e0ebd2f1a0a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269b.d
@@ -9,6 +9,6 @@ enum bool WWW = is(typeof(A.x));
 
 struct A {
     B blah;
-    void foo(B b){} 
+    void foo(B b){}
 }
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d
index 8bbfaacb8f1..5bba42e04ea 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4269c.d
@@ -9,6 +9,6 @@ enum bool WWW = is(typeof(A.x));
 
 class A {
     B blah;
-    void foo(B b){} 
+    void foo(B b){}
 }
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
index 75927798d63..9c6aaed8cde 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4375d.d
@@ -14,7 +14,7 @@ void main() {
 label2:
         if (true)
             assert(15);
-    else 
+    else
         assert(16);
 }
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6968.d b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d
index b56a5db931e..aca90c6c3dd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6968.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6968.d
@@ -29,4 +29,4 @@ template PredAny(A, B...)
 void main()
 {
     pragma(msg, PredAny!(int, long, float));
-} 
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
index 4fc269eed4c..e8371c4f7fe 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7848.d
@@ -8,13 +8,13 @@ fail_compilation/fail7848.d(27): Error: `@safe` function `fail7848.C.__unittest_
 fail_compilation/fail7848.d(21):        `fail7848.func` is declared here
 fail_compilation/fail7848.d(27): Error: `@nogc` function `fail7848.C.__unittest_L25_C30` cannot call non-@nogc function `fail7848.func`
 fail_compilation/fail7848.d(27): Error: function `fail7848.func` is not `nothrow`
-fail_compilation/fail7848.d(25): Error: `nothrow` function `fail7848.C.__unittest_L25_C30` may throw
+fail_compilation/fail7848.d(25): Error: function `fail7848.C.__unittest_L25_C30` may throw but is marked as `nothrow`
 fail_compilation/fail7848.d(32): Error: `pure` function `fail7848.C.__invariant1` cannot call impure function `fail7848.func`
 fail_compilation/fail7848.d(32): Error: `@safe` function `fail7848.C.__invariant1` cannot call `@system` function `fail7848.func`
 fail_compilation/fail7848.d(21):        `fail7848.func` is declared here
 fail_compilation/fail7848.d(32): Error: `@nogc` function `fail7848.C.__invariant1` cannot call non-@nogc function `fail7848.func`
 fail_compilation/fail7848.d(32): Error: function `fail7848.func` is not `nothrow`
-fail_compilation/fail7848.d(30): Error: `nothrow` function `fail7848.C.__invariant1` may throw
+fail_compilation/fail7848.d(30): Error: function `fail7848.C.__invariant1` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
index 11facfd9fef..a378fbbfdeb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m32.d
@@ -23,7 +23,7 @@ class Test
 
     static Image[] images;
 
-    static void initIcons() 
+    static void initIcons()
     {
         images["progress_rem"]  = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis
         images["redo"]          = ResourceManager.getImage("redo.gif");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
index 59c890ed60d..e0cc871323b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail80_m64.d
@@ -23,7 +23,7 @@ class Test
 
     static Image[] images;
 
-    static void initIcons() 
+    static void initIcons()
     {
         images["progress_rem"]  = ResourceManager.getImage("progress_rem.gif"); // delete_obj_dis
         images["redo"]          = ResourceManager.getImage("redo.gif");
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
index c5ca98b4738..92d313a5624 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail8724.d
@@ -3,7 +3,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail8724.d(14): Error: `object.Exception` is thrown but not caught
-fail_compilation/fail8724.d(12): Error: `nothrow` constructor `fail8724.Foo.this` may throw
+fail_compilation/fail8724.d(12): Error: constructor `fail8724.Foo.this` may throw but is marked as `nothrow`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
index ed228a94c35..7087b0c8c72 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
@@ -209,8 +209,7 @@ fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'`
 fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified
 fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]`
-fail_compilation/fail_arrayop2.d(281): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/fail_arrayop2.d(281): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(281): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
 fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified
@@ -235,6 +234,7 @@ fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without
 fail_compilation/fail_arrayop2.d(321): Error: array operation `[1] * 6` without destination memory not allowed
 ---
 */
+
 // Test all expressions, which can take arrays as their operands but cannot be a part of array operation.
 void test15407exp()
 {
@@ -252,7 +252,7 @@ void test15407exp()
     // StructLiteralExp.elements <- preFunctionParameters in CallExp
     { auto r = S([1] * 6); }
 
-    // NewExp.newargs/arguments <- preFunctionParameters
+    // NewExp.arguments <- preFunctionParameters
     { auto r = new S([1] * 6); }
 
     // TODO: TypeidExp
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d
new file mode 100644
index 00000000000..392cebd2f73
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_typeof.d
@@ -0,0 +1,82 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/fail_typeof.d(18): Error: undefined identifier `this`
+fail_compilation/fail_typeof.d(23): Error: `this` is not in a class or struct scope
+fail_compilation/fail_typeof.d(23): Error: `this` is only defined in non-static member functions, not `fail_typeof`
+fail_compilation/fail_typeof.d(28): Error: undefined identifier `super`
+fail_compilation/fail_typeof.d(33): Error: `super` is not in a class scope
+fail_compilation/fail_typeof.d(33): Error: `super` is only allowed in non-static class member functions
+fail_compilation/fail_typeof.d(40): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail_typeof.d(50): Error: undefined identifier `super`
+fail_compilation/fail_typeof.d(55): Error: `super` is not in a class scope
+fail_compilation/fail_typeof.d(55): Error: `super` is only allowed in non-static class member functions
+fail_compilation/fail_typeof.d(63): Error: undefined identifier `this`, did you mean `typeof(this)`?
+fail_compilation/fail_typeof.d(73): Error: undefined identifier `super`, did you mean `typeof(super)`?
+---
+*/
+
+enum E1 : this
+{
+    fail,
+}
+
+enum E2 : typeof(this)
+{
+    fail,
+}
+
+enum E3 : super
+{
+    fail,
+}
+
+enum E4 : typeof(super)
+{
+    fail,
+}
+
+struct S1
+{
+    enum E1 : this
+    {
+        fail,
+    }
+
+    enum E2 : typeof(this)
+    {
+        ok = S1(),
+    }
+
+    enum E3 : super
+    {
+        fail,
+    }
+
+    enum E4 : typeof(super)
+    {
+        fail,
+    }
+}
+
+class C1
+{
+    enum E1 : this
+    {
+        fail,
+    }
+
+    enum E2 : typeof(this)
+    {
+        ok = new C1,
+    }
+
+    enum E3 : super
+    {
+        fail,
+    }
+
+    enum E4 : typeof(super)
+    {
+        ok = new C1,
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
index 95663ea7790..0a2999763d1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/faildeleteaa.d
@@ -1,8 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/faildeleteaa.d(12): Deprecation: The `delete` keyword has been deprecated.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
-fail_compilation/faildeleteaa.d(12): Error: cannot delete type `int`
+fail_compilation/faildeleteaa.d(11): Error: The `delete` keyword is obsolete.  Use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead.
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
index ebefe33f2db..6d3b223db0e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727a.d
@@ -4,6 +4,8 @@
 TEST_OUTPUT:
 ---
 fail_compilation/imports/foo10727a.d(34): Error: undefined identifier `Frop`
+fail_compilation/imports/foo10727a.d(26): Error: template instance `foo10727a.CirBuff!(Foo)` error instantiating
+fail_compilation/imports/foo10727a.d(31):        instantiated from here: `Bar!(Foo)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
index 125ac12b193..4a59d5ce6b5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10727b.d
@@ -4,6 +4,8 @@
 TEST_OUTPUT:
 ---
 fail_compilation/imports/foo10727b.d(25): Error: undefined identifier `Frop`
+fail_compilation/imports/foo10727b.d(17): Error: template instance `foo10727b.CirBuff!(Foo)` error instantiating
+fail_compilation/imports/foo10727b.d(22):        instantia[...]

[diff truncated at 524288 bytes]


More information about the Gcc-cvs mailing list