public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/ibuclaw/heads/gdc)] Import dmd v2.097.1: dmd 50bdf003a, druntime f8df5552, phobos 4ea930b6c
@ 2021-07-30  8:44 Iain Buclaw
  0 siblings, 0 replies; only message in thread
From: Iain Buclaw @ 2021-07-30  8:44 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:9ad4b07f274d805fed51561046352725c418e5cb

commit 9ad4b07f274d805fed51561046352725c418e5cb
Author: Iain Buclaw <ibuclaw@gdcproject.org>
Date:   Sat Jul 24 03:53:04 2021 +0200

    Import dmd v2.097.1: dmd 50bdf003a, druntime f8df5552, phobos 4ea930b6c

Diff:
---
 gcc/d/d-codegen.cc                                 |   4 +-
 gcc/d/d-convert.cc                                 |   2 +-
 gcc/d/d-lang.cc                                    |   1 +
 gcc/d/dmd/VERSION                                  |   2 +-
 gcc/d/dmd/access.d                                 |   8 +-
 gcc/d/dmd/aggregate.d                              |  94 +---
 gcc/d/dmd/aggregate.h                              |  11 +-
 gcc/d/dmd/attrib.d                                 |   2 +-
 gcc/d/dmd/blockexit.d                              |   3 +-
 gcc/d/dmd/canthrow.d                               |   4 -
 gcc/d/dmd/clone.d                                  |  24 +-
 gcc/d/dmd/cond.d                                   |   2 +-
 gcc/d/dmd/cparse.d                                 | 129 ++++-
 gcc/d/dmd/dcast.d                                  | 105 ++--
 gcc/d/dmd/dclass.d                                 | 587 +++++++++++----------
 gcc/d/dmd/declaration.d                            |  17 +-
 gcc/d/dmd/declaration.h                            |   1 +
 gcc/d/dmd/denum.d                                  | 133 -----
 gcc/d/dmd/dinterpret.d                             |  13 +-
 gcc/d/dmd/dmodule.d                                |  19 +-
 gcc/d/dmd/dstruct.d                                | 169 +-----
 gcc/d/dmd/dsymbolsem.d                             | 212 ++++++--
 gcc/d/dmd/dtemplate.d                              |   2 +-
 gcc/d/dmd/dtoh.d                                   | 369 +++++--------
 gcc/d/dmd/enum.h                                   |   2 -
 gcc/d/dmd/escape.d                                 | 108 ++--
 gcc/d/dmd/expression.d                             | 117 +---
 gcc/d/dmd/expression.h                             |   9 +-
 gcc/d/dmd/expressionsem.d                          | 479 +++++++++++++----
 gcc/d/dmd/func.d                                   |  22 +-
 gcc/d/dmd/globals.d                                |   1 +
 gcc/d/dmd/gluelayer.d                              |  25 -
 gcc/d/dmd/hdrgen.d                                 |   4 +-
 gcc/d/dmd/iasmgcc.d                                |  12 +-
 gcc/d/dmd/identifier.h                             |   2 +-
 gcc/d/dmd/init.d                                   |  12 +-
 gcc/d/dmd/mtype.d                                  | 115 ++--
 gcc/d/dmd/nogc.d                                   |   2 -
 gcc/d/dmd/optimize.d                               |   2 +-
 gcc/d/dmd/parse.d                                  |  45 +-
 gcc/d/dmd/semantic3.d                              |  54 +-
 gcc/d/dmd/statement.d                              | 527 +-----------------
 gcc/d/dmd/statement.h                              |  20 +-
 gcc/d/dmd/statementsem.d                           | 530 ++++++++++++++++++-
 gcc/d/dmd/transitivevisitor.d                      |   2 -
 gcc/d/dmd/typesem.d                                | 134 ++++-
 gcc/d/expr.cc                                      |  36 +-
 gcc/d/lang-specs.h                                 |   3 +-
 gcc/testsuite/gdc.test/compilable/b17111.d         |  11 +-
 .../gdc.test/compilable/ddoc_markdown_breaks.d     |   3 +-
 .../compilable/ddoc_markdown_breaks_verbose.d      |  12 +-
 .../gdc.test/compilable/ddoc_markdown_code.d       |   9 +-
 .../compilable/ddoc_markdown_code_verbose.d        |  10 +-
 .../gdc.test/compilable/ddoc_markdown_emphasis.d   |   3 +-
 .../compilable/ddoc_markdown_emphasis_verbose.d    |  11 +-
 .../gdc.test/compilable/ddoc_markdown_escapes.d    |   3 +-
 .../gdc.test/compilable/ddoc_markdown_headings.d   |   3 +-
 .../compilable/ddoc_markdown_headings_verbose.d    |  10 +-
 .../gdc.test/compilable/ddoc_markdown_links.d      |   3 +-
 .../compilable/ddoc_markdown_links_verbose.d       |  15 +-
 .../gdc.test/compilable/ddoc_markdown_lists.d      |   3 +-
 .../compilable/ddoc_markdown_lists_verbose.d       |  10 +-
 .../gdc.test/compilable/ddoc_markdown_quote.d      |   9 +-
 .../compilable/ddoc_markdown_quote_verbose.d       |  10 +-
 .../gdc.test/compilable/ddoc_markdown_tables.d     |   9 +-
 .../compilable/ddoc_markdown_tables_verbose.d      |  10 +-
 .../gdc.test/compilable/dtoh_AnonDeclaration.d     |  21 +
 .../gdc.test/compilable/dtoh_forwarding.d          |  38 +-
 gcc/testsuite/gdc.test/compilable/header18364.d    |  20 +-
 gcc/testsuite/gdc.test/compilable/header18365.d    |  25 +-
 .../gdc.test/compilable/imports/imp22122.d         |   5 +
 gcc/testsuite/gdc.test/compilable/interpret3.d     |  11 +-
 gcc/testsuite/gdc.test/compilable/test17143.d      |  14 +-
 gcc/testsuite/gdc.test/compilable/test20367.d      |   2 -
 gcc/testsuite/gdc.test/compilable/test22122.d      |  53 ++
 gcc/testsuite/gdc.test/compilable/testcstuff1.c    | 499 ------------------
 gcc/testsuite/gdc.test/compilable/testcstuff2.c    | 313 -----------
 gcc/testsuite/gdc.test/compilable/testheader1.d    |  13 +-
 .../gdc.test/compilable/testheader12567a.d         |  16 +-
 .../gdc.test/compilable/testheader12567b.d         |  16 +-
 gcc/testsuite/gdc.test/compilable/testheader1i.d   |  13 +-
 gcc/testsuite/gdc.test/compilable/testheader2.d    |  11 +-
 gcc/testsuite/gdc.test/compilable/testheader2i.d   |  11 +-
 gcc/testsuite/gdc.test/compilable/testheader3.d    |  31 +-
 .../gdc.test/compilable/testheaderudamodule.d      |  22 +-
 gcc/testsuite/gdc.test/compilable/vcg-ast.d        |  10 +-
 gcc/testsuite/gdc.test/fail_compilation/cconst1.c  |  21 -
 .../gdc.test/fail_compilation/diag_class_alloc.d   |   4 +-
 .../gdc.test/fail_compilation/disable_new.d        |   4 +-
 .../gdc.test/fail_compilation/fail11038.d          |   6 +-
 .../gdc.test/fail_compilation/fail20033.d          |  22 +-
 .../gdc.test/fail_compilation/fail21868b.d         |  22 +
 .../gdc.test/fail_compilation/fail22054.d          |  23 +
 .../gdc.test/fail_compilation/fail22075.d          |  30 ++
 .../gdc.test/fail_compilation/fail22121.d          |  11 +
 .../fail22121/imports/test22121/package.d          |   1 +
 gcc/testsuite/gdc.test/fail_compilation/fail4517.d |  21 -
 gcc/testsuite/gdc.test/fail_compilation/fail4923.d |   3 +-
 gcc/testsuite/gdc.test/fail_compilation/fail9368.d |  48 --
 .../gdc.test/fail_compilation/failcstuff1.c        | 103 ----
 .../gdc.test/fail_compilation/failcstuff2.c        |  86 ---
 gcc/testsuite/gdc.test/fail_compilation/ice17831.d |  16 +-
 .../gdc.test/fail_compilation/test16523.d          |   3 +-
 .../gdc.test/fail_compilation/trait_loc_err.d      |   6 +-
 gcc/testsuite/gdc.test/runnable/builtin.d          |  10 -
 gcc/testsuite/gdc.test/runnable/cstuff2.c          | 254 ---------
 gcc/testsuite/gdc.test/runnable/fix22115.d         |  70 +++
 gcc/testsuite/gdc.test/runnable/ice21727.d         |  46 ++
 gcc/testsuite/gdc.test/runnable/test15.d           |  58 +-
 gcc/testsuite/gdc.test/runnable/ufcs.d             |  69 ++-
 libphobos/libdruntime/core/exception.d             | 201 ++++++-
 libphobos/libdruntime/core/internal/atomic.d       |   7 +-
 .../libdruntime/core/internal/backtrace/dwarf.d    | 417 ++++++---------
 libphobos/libdruntime/core/internal/dassert.d      |  55 +-
 libphobos/libdruntime/core/internal/hash.d         |  77 ++-
 libphobos/libdruntime/core/lifetime.d              |   6 +-
 libphobos/libdruntime/core/runtime.d               |   2 +-
 libphobos/libdruntime/core/sys/posix/fcntl.d       |   8 +-
 libphobos/libdruntime/core/sys/windows/sqlext.d    |   2 +-
 libphobos/libdruntime/object.d                     |  27 +-
 libphobos/src/std/algorithm/comparison.d           |  23 +-
 libphobos/src/std/algorithm/mutation.d             |  18 +-
 libphobos/src/std/array.d                          | 335 ++++++------
 libphobos/src/std/container/array.d                |  22 +-
 libphobos/src/std/datetime/date.d                  |   6 +-
 libphobos/src/std/datetime/systime.d               | 216 ++++----
 libphobos/src/std/datetime/timezone.d              |   2 +-
 libphobos/src/std/file.d                           |   2 +-
 libphobos/src/std/internal/math/biguintcore.d      |   4 +-
 libphobos/src/std/math/operations.d                |  46 +-
 libphobos/src/std/path.d                           |  12 +-
 libphobos/src/std/process.d                        |  27 +-
 libphobos/src/std/random.d                         |   4 +-
 libphobos/src/std/range/package.d                  |   4 +-
 libphobos/src/std/regex/internal/ir.d              |   4 +-
 libphobos/src/std/signals.d                        |   9 +-
 libphobos/src/std/stdio.d                          |   8 +-
 libphobos/src/std/string.d                         |  59 ++-
 libphobos/src/std/sumtype.d                        |   1 +
 libphobos/src/std/traits.d                         |  79 ++-
 libphobos/src/std/typecons.d                       |  58 +-
 libphobos/src/std/utf.d                            |  49 ++
 libphobos/src/std/uuid.d                           |   2 +-
 .../testsuite/libphobos.exceptions/assert_fail.d   |  79 +++
 libphobos/testsuite/libphobos.hash/test_hash.d     |  67 +++
 145 files changed, 4017 insertions(+), 4322 deletions(-)

diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 18f8b75a616..b7dbda937e7 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -2322,7 +2322,7 @@ get_frame_for_symbol (Dsymbol *sym)
 	  gcc_assert (cdo && cd);
 
 	  int offset;
-	  if (cdo->isBaseOf (cd, &offset) && offset != 0)
+	  if (isBaseOf (cdo, cd, &offset) && offset != 0)
 	    {
 	      /* Generate a new frame to pass to the overriden function that
 		 has the `this' pointer adjusted.  */
@@ -2393,7 +2393,7 @@ find_this_tree (ClassDeclaration *ocd)
 	{
 	  if (ocd == cd)
 	    return get_decl_tree (fd->vthis);
-	  else if (ocd->isBaseOf (cd, NULL))
+	  else if (isBaseOf (ocd, cd, NULL))
 	    return convert_expr (get_decl_tree (fd->vthis),
 				 cd->type, ocd->type);
 
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 0e030eca541..f822ee2ccd9 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -407,7 +407,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	  ClassDeclaration *cdto = tbtype->isClassHandle ();
 	  int offset;
 
-	  if (cdto->isBaseOf (cdfrom, &offset) && offset != OFFSET_RUNTIME)
+	  if (isBaseOf (cdto, cdfrom, &offset) && offset != OFFSET_RUNTIME)
 	    {
 	      /* Casting up the inheritance tree: Don't do anything special.
 		 Cast to an implemented interface: Handle at compile-time.  */
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index c8f9935da30..4f9d4205cd1 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -32,6 +32,7 @@ along with GCC; see the file COPYING3.  If not see
 #include "dmd/mangle.h"
 #include "dmd/module.h"
 #include "dmd/mtype.h"
+#include "dmd/root/file.h"
 #include "dmd/target.h"
 
 #include "opts.h"
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 6945fd11783..53632cade2f 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.097.0
+v2.097.1
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index 20c162c7fa1..a97e43310e2 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -197,10 +197,10 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
     if (!e)
         return false;
 
-    if (e.type.ty == Tclass)
+    if (auto tc = e.type.isTypeClass())
     {
         // Do access check
-        ClassDeclaration cd = (cast(TypeClass)e.type).sym;
+        ClassDeclaration cd = tc.sym;
         if (e.op == TOK.super_)
         {
             if (ClassDeclaration cd2 = sc.func.toParent().isClassDeclaration())
@@ -208,10 +208,10 @@ bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
         }
         return checkAccess(cd, loc, sc, d);
     }
-    else if (e.type.ty == Tstruct)
+    else if (auto ts = e.type.isTypeStruct())
     {
         // Do access check
-        StructDeclaration cd = (cast(TypeStruct)e.type).sym;
+        StructDeclaration cd = ts.sym;
         return checkAccess(cd, loc, sc, d);
     }
     return false;
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index da54ba2bf9f..88b7fbf7ef6 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -103,7 +103,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
     // Special member functions
     FuncDeclarations invs;  /// Array of invariants
     FuncDeclaration inv;    /// Merged invariant calling all members of invs
-    NewDeclaration aggNew;  /// allocator
 
     /// CtorDeclaration or TemplateDeclaration
     Dsymbol ctor;
@@ -125,6 +124,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
     ///
     Visibility visibility;
     bool noDefaultCtor;             /// no default construction
+    bool disableNew;                /// disallow allocations using `new`
     Sizeok sizeok = Sizeok.none;    /// set when structsize contains valid data
 
     final extern (D) this(const ref Loc loc, Identifier id)
@@ -161,91 +161,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
             ScopeDsymbol.setScope(sc);
     }
 
-    /***************************************
-     * Find all instance fields, then push them into `fields`.
-     *
-     * Runs semantic() for all instance field variables, but also
-     * the field types can remain yet not resolved forward references,
-     * except direct recursive definitions.
-     * After the process sizeok is set to Sizeok.fwd.
-     *
-     * Returns:
-     *      false if any errors occur.
-     */
-    final bool determineFields()
-    {
-        if (_scope)
-            dsymbolSemantic(this, null);
-        if (sizeok != Sizeok.none)
-            return true;
-
-        //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
-        // determineFields can be called recursively from one of the fields's v.semantic
-        fields.setDim(0);
-
-        static int func(Dsymbol s, AggregateDeclaration ad)
-        {
-            auto v = s.isVarDeclaration();
-            if (!v)
-                return 0;
-            if (v.storage_class & STC.manifest)
-                return 0;
-
-            if (v.semanticRun < PASS.semanticdone)
-                v.dsymbolSemantic(null);
-            // Return in case a recursive determineFields triggered by v.semantic already finished
-            if (ad.sizeok != Sizeok.none)
-                return 1;
-
-            if (v.aliassym)
-                return 0;   // If this variable was really a tuple, skip it.
-
-            if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
-                return 0;
-            if (!v.isField() || v.semanticRun < PASS.semanticdone)
-                return 1;   // unresolvable forward reference
-
-            ad.fields.push(v);
-
-            if (v.storage_class & STC.ref_)
-                return 0;
-            auto tv = v.type.baseElemOf();
-            if (tv.ty != Tstruct)
-                return 0;
-            if (ad == (cast(TypeStruct)tv).sym)
-            {
-                const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
-                ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz);
-                ad.type = Type.terror;
-                ad.errors = true;
-                return 1;
-            }
-            return 0;
-        }
-
-        if (members)
-        {
-            for (size_t i = 0; i < members.dim; i++)
-            {
-                auto s = (*members)[i];
-                if (s.apply(&func, this))
-                {
-                    if (sizeok != Sizeok.none)
-                    {
-                        // recursive determineFields already finished
-                        return true;
-                    }
-                    return false;
-                }
-            }
-        }
-
-        if (sizeok != Sizeok.done)
-            sizeok = Sizeok.fwd;
-
-        return true;
-    }
-
     /***************************************
      * Returns:
      *      The total number of fields minus the number of hidden fields.
@@ -288,7 +203,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         }
 
         // Determine instance fields when sizeok == Sizeok.none
-        if (!determineFields())
+        if (!this.determineFields())
             goto Lfail;
         if (sizeok != Sizeok.done)
             finalizeSize();
@@ -538,8 +453,9 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
                          * will return the base of the enum, and its default initializer
                          * would be different from the enum's.
                          */
-                        while (telem.toBasetype().ty == Tsarray)
-                            telem = (cast(TypeSArray)telem.toBasetype()).next;
+                        TypeSArray tsa;
+                        while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
+                            telem = tsa.next;
                         if (telem.ty == Tvoid)
                             telem = Type.tuns8.addMod(telem.mod);
                     }
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index 41572a82bdb..571f3aebd09 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -21,7 +21,6 @@ class Expression;
 class FuncDeclaration;
 class CtorDeclaration;
 class DtorDeclaration;
-class NewDeclaration;
 class InterfaceDeclaration;
 class TypeInfoClassDeclaration;
 class VarDeclaration;
@@ -102,7 +101,6 @@ public:
     // Special member functions
     FuncDeclarations invs;              // Array of invariants
     FuncDeclaration *inv;               // invariant
-    NewDeclaration *aggNew;             // allocator
 
     Dsymbol *ctor;                      // CtorDeclaration or TemplateDeclaration
 
@@ -122,11 +120,11 @@ public:
 
     Visibility visibility;
     bool noDefaultCtor;         // no default construction
+    bool disableNew;            // disallow allocations using `new`
     Sizeok sizeok;              // set when structsize contains valid data
 
     virtual Scope *newScope(Scope *sc);
     void setScope(Scope *sc);
-    bool determineFields();
     size_t nonHiddenFields();
     bool determineSize(Loc loc);
     virtual void finalizeSize() = 0;
@@ -193,11 +191,9 @@ public:
 
     static StructDeclaration *create(Loc loc, Identifier *id, bool inObject);
     StructDeclaration *syntaxCopy(Dsymbol *s);
-    void semanticTypeInfoMembers();
     Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
     const char *kind() const;
     void finalizeSize();
-    bool fit(const Loc &loc, Scope *sc, Expressions *elements, Type *stype);
     bool isPOD();
 
     StructDeclaration *isStructDeclaration() { return this; }
@@ -294,7 +290,6 @@ public:
 
     #define OFFSET_RUNTIME 0x76543210
     #define OFFSET_FWDREF 0x76543211
-    virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
 
     bool isBaseInfoComplete();
     Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
@@ -327,8 +322,6 @@ class InterfaceDeclaration : public ClassDeclaration
 public:
     InterfaceDeclaration *syntaxCopy(Dsymbol *s);
     Scope *newScope(Scope *sc);
-    bool isBaseOf(ClassDeclaration *cd, int *poffset);
-    bool isBaseOf(BaseClass *bc, int *poffset);
     const char *kind() const;
     int vtblOffset() const;
     bool isCPPinterface() const;
@@ -337,3 +330,5 @@ public:
     InterfaceDeclaration *isInterfaceDeclaration() { return this; }
     void accept(Visitor *v) { v->visit(this); }
 };
+
+bool isBaseOf(ClassDeclaration* derived, ClassDeclaration* cd, int* poffset);
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 646dd3c7a40..bb104250ebb 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -206,7 +206,7 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
         objc.addSymbols(this, classes, categories);
     }
 
-    override final inout(AttribDeclaration) isAttribDeclaration() inout
+    override final inout(AttribDeclaration) isAttribDeclaration() inout pure @safe
     {
         return this;
     }
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index efeb3fac748..1fd90051830 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -156,7 +156,8 @@ int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
 
                     if (!(result & BE.fallthru) && !s.comeFrom())
                     {
-                        if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode())
+                        if (blockExit(s, func, mustNotThrow) != BE.halt && s.hasCode() &&
+                            s.loc != Loc.initial) // don't emit warning for generated code
                             s.warning("statement is not reachable");
                     }
                     else
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index fcb884df72d..ed05af6ac7c 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -115,10 +115,6 @@ extern (C++) bool canThrow(Expression e, FuncDeclaration func, bool mustNotThrow
         {
             if (ne.member)
             {
-                if (ne.allocator)
-                    // https://issues.dlang.org/show_bug.cgi?id=14407
-                    checkFuncThrows(ne, ne.allocator);
-
                 // See if constructor call can throw
                 checkFuncThrows(ne, ne.member);
             }
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 094ce0051a0..d3006170be7 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -410,9 +410,8 @@ bool needOpEquals(StructDeclaration sd)
     /* If any of the fields has an opEquals, then we
      * need it too.
      */
-    for (size_t i = 0; i < sd.fields.dim; i++)
+    foreach (VarDeclaration v; sd.fields)
     {
-        VarDeclaration v = sd.fields[i];
         if (v.storage_class & STC.ref_)
             continue;
         if (v.overlapped)
@@ -426,8 +425,6 @@ bool needOpEquals(StructDeclaration sd)
                 continue;
             if (needOpEquals(ts.sym))
                 goto Lneed;
-            if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14806
-                goto Lneed;
         }
         if (tvbase.isfloating())
         {
@@ -731,12 +728,11 @@ private bool needToHash(StructDeclaration sd)
     if (sd.xhash)
         goto Lneed;
 
-    /* If any of the fields has an opEquals, then we
+    /* If any of the fields has an toHash, then we
      * need it too.
      */
-    for (size_t i = 0; i < sd.fields.dim; i++)
+    foreach (VarDeclaration v; sd.fields)
     {
-        VarDeclaration v = sd.fields[i];
         if (v.storage_class & STC.ref_)
             continue;
         if (v.overlapped)
@@ -750,8 +746,6 @@ private bool needToHash(StructDeclaration sd)
                 continue;
             if (needToHash(ts.sym))
                 goto Lneed;
-            if (ts.sym.aliasthis) // https://issues.dlang.org/show_bug.cgi?id=14948
-                goto Lneed;
         }
         if (tvbase.isfloating())
         {
@@ -1001,9 +995,8 @@ DtorDeclaration buildDtor(AggregateDeclaration ad, Scope* sc)
         Expression e = null;
         e = null;
         stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
-        for (size_t i = 0; i < ad.dtors.dim; i++)
+        foreach (FuncDeclaration fd; ad.dtors)
         {
-            FuncDeclaration fd = ad.dtors[i];
             stc = mergeFuncAttrs(stc, fd);
             if (stc & STC.disable)
             {
@@ -1228,10 +1221,8 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
 
     // if any of the postblits are disabled, then the generated postblit
     // will be disabled
-    for (size_t i = 0; i < sd.postblits.dim; i++)
-    {
-        stc |= sd.postblits[i].storage_class & STC.disable;
-    }
+    foreach (postblit; sd.postblits)
+        stc |= postblit.storage_class & STC.disable;
 
     VarDeclaration[] fieldsToDestroy;
     auto postblitCalls = new Statements();
@@ -1434,9 +1425,8 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc)
     default:
         Expression e = null;
         stc = STC.safe | STC.nothrow_ | STC.pure_ | STC.nogc;
-        for (size_t i = 0; i < sd.postblits.dim; i++)
+        foreach (fd; sd.postblits)
         {
-            auto fd = sd.postblits[i];
             stc = mergeFuncAttrs(stc, fd);
             if (stc & STC.disable)
             {
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index cf12ee4e530..d4a8b136d43 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -118,7 +118,7 @@ extern (C++) final class StaticForeach : RootObject
      */
     bool needExpansion = false;
 
-    extern (D) this(const ref Loc loc,ForeachStatement aggrfe,ForeachRangeStatement rangefe)
+    extern (D) this(const ref Loc loc, ForeachStatement aggrfe, ForeachRangeStatement rangefe)
     {
         assert(!!aggrfe ^ !!rangefe);
 
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index f64813d613f..063746116a3 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -163,6 +163,18 @@ final class CParser(AST) : Parser!AST
                 case TOK.rightShiftAssign:
                     goto Lexp;
 
+                case TOK.leftParenthesis:
+                {
+                    /* If tokens look like a function call, assume it is one,
+                     * As any type-name won't be resolved until semantic, this
+                     * could be rewritten later.
+                     */
+                    auto tk = &token;
+                    if (isFunctionCall(tk))
+                        goto Lexp;
+                    goto default;
+                }
+
                 default:
                 {
                     /* If tokens look like a declaration, assume it is one
@@ -1738,7 +1750,7 @@ final class CParser(AST) : Parser!AST
         auto body = cparseStatement(ParseStatementFlags.curly);  // don't start a new scope; continue with parameter scope
         Specifier specifier;
         specifier.scw = scw;
-        auto fd = new AST.FuncDeclaration(token.loc, Loc.initial, id, specifiersToSTC(LVL.global, specifier), ft);
+        auto fd = new AST.FuncDeclaration(locFunc, prevloc, id, specifiersToSTC(LVL.global, specifier), ft);
 
         if (addFuncName)
         {
@@ -2281,35 +2293,44 @@ final class CParser(AST) : Parser!AST
                 {
                     case TOK.leftBracket:
                     {
-                        // post [] syntax.
+                        // post [] syntax, pick up any leading type qualifiers, `static` and `*`
                         AST.Type ta;
                         nextToken();
 
-                        // pick up any leading type qualifiers, `static` and `*`
+                        auto mod = cparseTypeQualifierList();   // const/volatile/restrict/_Atomic
+
                         bool isStatic;
+                        bool isVLA;
                         if (token.value == TOK.static_)
                         {
-                            isStatic = true;
+                            isStatic = true;    // `static`
                             nextToken();
+                            if (!mod)           // type qualifiers after `static`
+                                mod = cparseTypeQualifierList();
                         }
-
-                        bool isVLA;
-                        if (!isStatic)
+                        else if (token.value == TOK.mul)
                         {
-                            if (token.value == TOK.static_)
+                            if (peekNext() == TOK.rightBracket)
                             {
-                                isStatic = true;
+                                isVLA = true;   // `*`
                                 nextToken();
                             }
-                            else if (token.value == TOK.mul)
-                            {
-                                if (peekNext() == TOK.rightBracket)
-                                {
-                                    isVLA = true;
-                                    nextToken();
-                                }
-                            }
                         }
+
+                        if (isStatic || token.value != TOK.rightBracket)
+                        {
+                            //printf("It's a static array\n");
+                            AST.Expression e = cparseAssignExp(); // [ expression ]
+                            ta = new AST.TypeSArray(t, e);
+                        }
+                        else
+                        {
+                            // An array of unknown size, fake it with a DArray
+                            ta = new AST.TypeDArray(t); // []
+                        }
+                        check(TOK.rightBracket);
+
+                        // Issue errors for unsupported types.
                         if (isVLA) // C11 6.7.6.2
                         {
                             error("variable length arrays are not supported");
@@ -2318,25 +2339,35 @@ final class CParser(AST) : Parser!AST
                         {
                             error("static array parameters are not supported");
                         }
-
-                        if (token.value == TOK.rightBracket)
+                        if (declarator != DTR.xparameter)
                         {
-                            // An array of unknown size, fake it with a DArray
-                            ta = new AST.TypeDArray(t); // []
-                            nextToken();
+                            /* C11 6.7.6.2-4: '*' can only be used with function prototype scope.
+                             */
+                            if (isVLA)
+                                error("variable length array used outside of function prototype");
+                            /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
+                             * in a declaration of a function parameter with an array type.
+                             */
+                            if (isStatic || mod)
+                                error("static or type qualifier used outside of function prototype");
                         }
-                        else
+                        if (ts.isTypeSArray() || ts.isTypeDArray())
                         {
-                            //printf("It's a static array\n");
-                            AST.Expression e = cparseAssignExp(); // [ expression ]
-                            ta = new AST.TypeSArray(t, e);
-                            check(TOK.rightBracket);
+                            /* C11 6.7.6.2-1: type qualifiers and 'static' shall only appear
+                             * in the outermost array type derivation.
+                             */
+                            if (isStatic || mod)
+                                error("static or type qualifier used in non-outermost array type derivation");
+                            /* C11 6.7.6.2-1: the element type shall not be an incomplete or
+                             * function type.
+                             */
+                            if (ta.isTypeDArray() && !isVLA)
+                                error("array type has incomplete element type `%s`", ta.toChars());
                         }
 
-                        const mod = cparseTypeQualifierList(); // const/volatile/restrict/_Atomic
+                        // Apply type qualifiers to the constructed type.
                         if (mod & MOD.xconst) // ignore the other bits
                             ta = toConst(ta);
-
                         insertTx(ts, ta, t);  // ts -> ... -> ta -> t
                         continue;
                     }
@@ -3189,6 +3220,46 @@ final class CParser(AST) : Parser!AST
         return true;
     }
 
+    /********************************
+     * See if match for:
+     *    postfix-expression ( argument-expression-list(opt) )
+     * Params:
+     *  pt = starting token, updated to one past end of initializer if true
+     * Returns:
+     *  true if function call
+     */
+    private bool isFunctionCall(ref Token* pt)
+    {
+        //printf("isFunctionCall()\n");
+        auto t = pt;
+
+        if (!isPrimaryExpression(t))
+            return false;
+        if (t.value != TOK.leftParenthesis)
+            return false;
+        t = peek(t);
+        while (1)
+        {
+            if (!isAssignmentExpression(t))
+                return false;
+            if (t.value == TOK.comma)
+            {
+                t = peek(t);
+                continue;
+            }
+            if (t.value == TOK.rightParenthesis)
+            {
+                t = peek(t);
+                break;
+            }
+            return false;
+        }
+        if (t.value != TOK.semicolon)
+            return false;
+        pt = t;
+        return true;
+    }
+
     /********************************
      * See if match for assignment-expression.
      * Params:
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index cd360e93cad..69b49fc59d5 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -574,7 +574,7 @@ MATCH implicitConvTo(Expression e, Type t)
             visit(cast(Expression)e);
             if (result != MATCH.nomatch)
                 return;
-            if (e.type.ty == t.ty && e.type.ty == Tstruct && (cast(TypeStruct)e.type).sym == (cast(TypeStruct)t).sym)
+            if (e.type.ty == t.ty && e.type.isTypeStruct() && e.type.isTypeStruct().sym == t.isTypeStruct().sym)
             {
                 result = MATCH.constant;
                 foreach (i, el; (*e.elements)[])
@@ -615,7 +615,7 @@ MATCH implicitConvTo(Expression e, Type t)
                     TY tynto = t.nextOf().ty;
                     if (tynto == tyn)
                     {
-                        if ((cast(TypeSArray)e.type).dim.toInteger() == (cast(TypeSArray)t).dim.toInteger())
+                        if (e.type.isTypeSArray().dim.toInteger() == t.isTypeSArray().dim.toInteger())
                         {
                             result = MATCH.exact;
                         }
@@ -626,7 +626,7 @@ MATCH implicitConvTo(Expression e, Type t)
                         if (e.committed && tynto != tyn)
                             return;
                         size_t fromlen = e.numberOfCodeUnits(tynto);
-                        size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
+                        size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
                         if (tolen < fromlen)
                             return;
                         if (tolen != fromlen)
@@ -650,7 +650,7 @@ MATCH implicitConvTo(Expression e, Type t)
                         if (e.committed && tynto != tyn)
                             return;
                         size_t fromlen = e.numberOfCodeUnits(tynto);
-                        size_t tolen = cast(size_t)(cast(TypeSArray)t).dim.toInteger();
+                        size_t tolen = cast(size_t)t.isTypeSArray().dim.toInteger();
                         if (tolen < fromlen)
                             return;
                         if (tolen != fromlen)
@@ -703,7 +703,7 @@ MATCH implicitConvTo(Expression e, Type t)
                         result = m;
                         return;
                     case Tenum:
-                        if ((cast(TypeEnum)tn).sym.isSpecial())
+                        if (tn.isTypeEnum().sym.isSpecial())
                         {
                             /* Allow string literal -> const(wchar_t)[]
                              */
@@ -1185,7 +1185,7 @@ MATCH implicitConvTo(Expression e, Type t)
              *    newargs
              *    arguments
              *    .init
-             * 'member' and 'allocator' need to be pure.
+             * 'member' need to be pure.
              */
 
             /* See if fail only because of mod bits
@@ -1219,30 +1219,25 @@ MATCH implicitConvTo(Expression e, Type t)
                     return;
             }
 
-            /* Check call to 'allocator', then 'member'
+            /* Check call to 'member'
              */
-            FuncDeclaration fd = e.allocator;
-            for (int count = 0; count < 2; ++count, (fd = e.member))
+            if (e.member)
             {
-                if (!fd)
-                    continue;
+                FuncDeclaration fd = e.member;
                 if (fd.errors || fd.type.ty != Tfunction)
                     return; // error
-                TypeFunction tf = cast(TypeFunction)fd.type;
+                TypeFunction tf = fd.type.isTypeFunction();
                 if (tf.purity == PURE.impure)
                     return; // impure
 
-                if (fd == e.member)
+                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)
                 {
-                    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.
+                    return;
                 }
+                // Allow a conversion to immutable type, or
+                // conversions of mutable types between thread-local and shared.
 
-                Expressions* args = (fd == e.allocator) ? e.newargs : e.arguments;
+                Expressions* args = e.arguments;
 
                 size_t nparams = tf.parameterList.length;
                 // if TypeInfoArray was prepended
@@ -1306,10 +1301,10 @@ MATCH implicitConvTo(Expression e, Type t)
             Type ntb = e.newtype.toBasetype();
             if (ntb.ty == Tarray)
                 ntb = ntb.nextOf().toBasetype();
-            if (ntb.ty == Tstruct)
+            if (auto ts = ntb.isTypeStruct())
             {
                 // Don't allow nested structs - uplevel reference may not be convertible
-                StructDeclaration sd = (cast(TypeStruct)ntb).sym;
+                StructDeclaration sd = ts.sym;
                 sd.size(e.loc); // resolve any forward references
                 if (sd.isNested())
                     return;
@@ -1318,11 +1313,11 @@ MATCH implicitConvTo(Expression e, Type t)
             {
                 /* Zeros are implicitly convertible, except for special cases.
                  */
-                if (ntb.ty == Tclass)
+                if (auto tc = ntb.isTypeClass())
                 {
                     /* With new() must look at the class instance initializer.
                      */
-                    ClassDeclaration cd = (cast(TypeClass)ntb).sym;
+                    ClassDeclaration cd = tc.sym;
 
                     cd.size(e.loc); // resolve any forward references
 
@@ -1632,7 +1627,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             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 = cast(TypeVector)tob;
+                TypeVector tv = tob.isTypeVector();
                 result = new CastExp(e.loc, e, tv.elementType());
                 result = new VectorExp(e.loc, result, tob);
                 result = result.expressionSemantic(sc);
@@ -1704,7 +1699,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     // cast(U[])sa; // ==> cast(U[])sa[];
                     d_uns64 fsize = t1b.nextOf().size();
                     d_uns64 tsize = tob.nextOf().size();
-                    if (((cast(TypeSArray)t1b).dim.toInteger() * fsize) % tsize != 0)
+                    if ((t1b.isTypeSArray().dim.toInteger() * fsize) % tsize != 0)
                     {
                         // copied from sarray_toDarray() in e2ir.c
                         e.error("cannot cast expression `%s` of type `%s` to `%s` since sizes don't line up", e.toChars(), e.type.toChars(), t.toChars());
@@ -1887,7 +1882,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 d_uns64 szx = tb.nextOf().size();
                 assert(szx <= 255);
                 se.sz = cast(ubyte)szx;
-                se.len = cast(size_t)(cast(TypeSArray)tb).dim.toInteger();
+                se.len = cast(size_t)tb.isTypeSArray().dim.toInteger();
                 se.committed = 1;
                 se.type = t;
 
@@ -2061,9 +2056,9 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             assert(copied);
 
             // See if need to truncate or extend the literal
-            if (tb.ty == Tsarray)
+            if (auto tsa = tb.isTypeSArray())
             {
-                size_t dim2 = cast(size_t)(cast(TypeSArray)tb).dim.toInteger();
+                size_t dim2 = cast(size_t)tsa.dim.toInteger();
                 //printf("dim from = %d, to = %d\n", (int)se.len, (int)dim2);
 
                 // Changing dimensions
@@ -2181,7 +2176,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 return;
             }
 
-            TupleExp te = cast(TupleExp)e.copy();
+            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++)
@@ -2243,9 +2238,8 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 }
                 else
                 {
-                    if (tb.ty == Tsarray)
+                    if (auto tsa = tb.isTypeSArray())
                     {
-                        TypeSArray tsa = cast(TypeSArray)tb;
                         if (e.elements.dim != tsa.dim.toInteger())
                             goto L1;
                     }
@@ -2279,15 +2273,15 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             else if (tb.ty == Tvector && (typeb.ty == Tarray || typeb.ty == Tsarray))
             {
                 // Convert array literal to vector type
-                TypeVector tv = cast(TypeVector)tb;
-                TypeSArray tbase = cast(TypeSArray)tv.basetype;
+                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 = cast(ArrayLiteralExp)e.copy();
+                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();
@@ -2340,7 +2334,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     (*ae.values)[i] = ex;
 
                     ex = (*e.keys)[i];
-                    ex = ex.castTo(sc, (cast(TypeAArray)tb).index);
+                    ex = ex.castTo(sc, tb.isTypeAArray().index);
                     (*ae.keys)[i] = ex;
                 }
                 ae.type = t;
@@ -2555,7 +2549,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
 
             // Handle the cast from Tarray to Tsarray with CT-known slicing
 
-            TypeSArray tsa = cast(TypeSArray)toStaticArrayType(e);
+            TypeSArray tsa = toStaticArrayType(e).isTypeSArray();
             if (tsa && tsa.size(e.loc) == tb.size(e.loc))
             {
                 /* Match if the sarray sizes are equal:
@@ -2569,7 +2563,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 result.type = t;
                 return;
             }
-            if (tsa && tsa.dim.equals((cast(TypeSArray)tb).dim))
+            if (tsa && tsa.dim.equals(tb.isTypeSArray().dim))
             {
                 /* Match if the dimensions are equal
                  * with the implicit conversion of e.e1:
@@ -2577,7 +2571,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                  */
                 Type t1b = e.e1.type.toBasetype();
                 if (t1b.ty == Tsarray)
-                    t1b = tb.nextOf().sarrayOf((cast(TypeSArray)t1b).dim.toInteger());
+                    t1b = tb.nextOf().sarrayOf(t1b.isTypeSArray().dim.toInteger());
                 else if (t1b.ty == Tarray)
                     t1b = tb.nextOf().arrayOf();
                 else if (t1b.ty == Tpointer)
@@ -2654,9 +2648,8 @@ Expression inferType(Expression e, Type t, int flag = 0)
     Expression visitAar(AssocArrayLiteralExp aale)
     {
         Type tb = t.toBasetype();
-        if (tb.ty == Taarray)
+        if (auto taa = tb.isTypeAArray())
         {
-            TypeAArray taa = cast(TypeAArray)tb;
             Type ti = taa.index;
             Type tv = taa.nextOf();
             for (size_t i = 0; i < aale.keys.dim; i++)
@@ -2880,7 +2873,7 @@ Type typeMerge(Scope* sc, TOK op, ref Expression pe1, ref Expression pe2)
 
     if (t1.mod != t2.mod &&
         t1.ty == Tenum && t2.ty == Tenum &&
-        (cast(TypeEnum)t1).sym == (cast(TypeEnum)t2).sym)
+        t1.isTypeEnum().sym == t2.isTypeEnum().sym)
     {
         ubyte mod = MODmerge(t1.mod, t2.mod);
         t1 = t1.castMod(mod);
@@ -2950,8 +2943,8 @@ Lagain:
 
         if (t1n.ty == Tfunction && t2n.ty == Tfunction)
         {
-            TypeFunction tf1 = cast(TypeFunction)t1n;
-            TypeFunction tf2 = cast(TypeFunction)t2n;
+            TypeFunction tf1 = t1n.isTypeFunction();
+            TypeFunction tf2 = t2n.isTypeFunction();
             tf1.purityLevel();
             tf2.purityLevel();
 
@@ -3021,7 +3014,7 @@ Lagain:
         return null;
     }
 
-    if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && (cast(TypeSArray)t2).dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
+    if ((t1.ty == Tsarray || t1.ty == Tarray) && (e2.op == TOK.null_ && t2.ty == Tpointer && t2.nextOf().ty == Tvoid || e2.op == TOK.arrayLiteral && t2.ty == Tsarray && t2.nextOf().ty == Tvoid && t2.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e2, t1)))
     {
         /*  (T[n] op void*)   => T[]
          *  (T[]  op void*)   => T[]
@@ -3033,7 +3026,7 @@ Lagain:
         return coerce(t1.nextOf().arrayOf());
     }
 
-    if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && (cast(TypeSArray)t1).dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
+    if ((t2.ty == Tsarray || t2.ty == Tarray) && (e1.op == TOK.null_ && t1.ty == Tpointer && t1.nextOf().ty == Tvoid || e1.op == TOK.arrayLiteral && t1.ty == Tsarray && t1.nextOf().ty == Tvoid && t1.isTypeSArray().dim.toInteger() == 0 || isVoidArrayLiteral(e1, t2)))
     {
         /*  (void*   op T[n]) => T[]
          *  (void*   op T[])  => T[]
@@ -3145,8 +3138,8 @@ Lagain:
 
             if (t1.ty == Tclass && t2.ty == Tclass)
             {
-                TypeClass tc1 = cast(TypeClass)t1;
-                TypeClass tc2 = cast(TypeClass)t2;
+                TypeClass tc1 = t1.isTypeClass();
+                TypeClass tc2 = t2.isTypeClass();
 
                 /* Pick 'tightest' type
                  */
@@ -3164,7 +3157,7 @@ Lagain:
                 else
                     return null;
             }
-            else if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis)
+            else if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
             {
                 if (isRecursiveAliasThis(att1, e1.type))
                     return null;
@@ -3173,7 +3166,7 @@ Lagain:
                 t1 = e1.type;
                 continue;
             }
-            else if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis)
+            else if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
             {
                 if (isRecursiveAliasThis(att2, e2.type))
                     return null;
@@ -3200,8 +3193,8 @@ Lagain:
             goto Lagain;
         }
 
-        TypeStruct ts1 = cast(TypeStruct)t1;
-        TypeStruct ts2 = cast(TypeStruct)t2;
+        TypeStruct ts1 = t1.isTypeStruct();
+        TypeStruct ts2 = t2.isTypeStruct();
         if (ts1.sym != ts2.sym)
         {
             if (!ts1.sym.aliasthis && !ts2.sym.aliasthis)
@@ -3253,7 +3246,7 @@ Lagain:
 
     if (t1.ty == Tstruct || t2.ty == Tstruct)
     {
-        if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.aliasthis)
+        if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
         {
             if (isRecursiveAliasThis(att1, e1.type))
                 return null;
@@ -3263,7 +3256,7 @@ Lagain:
             t = t1;
             goto Lagain;
         }
-        if (t2.ty == Tstruct && (cast(TypeStruct)t2).sym.aliasthis)
+        if (t2.ty == Tstruct && t2.isTypeStruct().sym.aliasthis)
         {
             if (isRecursiveAliasThis(att2, e2.type))
                 return null;
@@ -3290,8 +3283,8 @@ Lagain:
         // https://issues.dlang.org/show_bug.cgi?id=13841
         // all vector types should have no common types between
         // different vectors, even though their sizes are same.
-        auto tv1 = cast(TypeVector)t1;
-        auto tv2 = cast(TypeVector)t2;
+        auto tv1 = t1.isTypeVector();
+        auto tv2 = t2.isTypeVector();
         if (!tv1.basetype.equals(tv2.basetype))
             return null;
 
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 9c5f0da2f97..fb0e4fb53eb 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -228,151 +228,149 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         // For forward references
         type = new TypeClass(this);
 
-        if (id)
-        {
-            // Look for special class names
-            if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
-                error("illegal class name");
+        // Look for special class names
+        if (id == Id.__sizeof || id == Id.__xalignof || id == Id._mangleof)
+            error("illegal class name");
 
-            // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
-            if (id.toChars()[0] == 'T')
+        // BUG: What if this is the wrong TypeInfo, i.e. it is nested?
+        if (id.toChars()[0] == 'T')
+        {
+            if (id == Id.TypeInfo)
             {
-                if (id == Id.TypeInfo)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.dtypeinfo = this;
-                }
-                if (id == Id.TypeInfo_Class)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoclass = this;
-                }
-                if (id == Id.TypeInfo_Interface)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfointerface = this;
-                }
-                if (id == Id.TypeInfo_Struct)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfostruct = this;
-                }
-                if (id == Id.TypeInfo_Pointer)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfopointer = this;
-                }
-                if (id == Id.TypeInfo_Array)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoarray = this;
-                }
-                if (id == Id.TypeInfo_StaticArray)
-                {
-                    //if (!inObject)
-                    //    Type.typeinfostaticarray.error("%s", msg);
-                    Type.typeinfostaticarray = this;
-                }
-                if (id == Id.TypeInfo_AssociativeArray)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoassociativearray = this;
-                }
-                if (id == Id.TypeInfo_Enum)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoenum = this;
-                }
-                if (id == Id.TypeInfo_Function)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfofunction = this;
-                }
-                if (id == Id.TypeInfo_Delegate)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfodelegate = this;
-                }
-                if (id == Id.TypeInfo_Tuple)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfotypelist = this;
-                }
-                if (id == Id.TypeInfo_Const)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoconst = this;
-                }
-                if (id == Id.TypeInfo_Invariant)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoinvariant = this;
-                }
-                if (id == Id.TypeInfo_Shared)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfoshared = this;
-                }
-                if (id == Id.TypeInfo_Wild)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfowild = this;
-                }
-                if (id == Id.TypeInfo_Vector)
-                {
-                    if (!inObject)
-                        error("%s", msg);
-                    Type.typeinfovector = this;
-                }
+                if (!inObject)
+                    error("%s", msg);
+                Type.dtypeinfo = this;
             }
-
-            if (id == Id.Object)
+            if (id == Id.TypeInfo_Class)
             {
                 if (!inObject)
                     error("%s", msg);
-                object = this;
+                Type.typeinfoclass = this;
             }
-
-            if (id == Id.Throwable)
+            if (id == Id.TypeInfo_Interface)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfointerface = this;
+            }
+            if (id == Id.TypeInfo_Struct)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfostruct = this;
+            }
+            if (id == Id.TypeInfo_Pointer)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfopointer = this;
+            }
+            if (id == Id.TypeInfo_Array)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfoarray = this;
+            }
+            if (id == Id.TypeInfo_StaticArray)
+            {
+                //if (!inObject)
+                //    Type.typeinfostaticarray.error("%s", msg);
+                Type.typeinfostaticarray = this;
+            }
+            if (id == Id.TypeInfo_AssociativeArray)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfoassociativearray = this;
+            }
+            if (id == Id.TypeInfo_Enum)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfoenum = this;
+            }
+            if (id == Id.TypeInfo_Function)
             {
                 if (!inObject)
                     error("%s", msg);
-                throwable = this;
+                Type.typeinfofunction = this;
             }
-            if (id == Id.Exception)
+            if (id == Id.TypeInfo_Delegate)
             {
                 if (!inObject)
                     error("%s", msg);
-                exception = this;
+                Type.typeinfodelegate = this;
             }
-            if (id == Id.Error)
+            if (id == Id.TypeInfo_Tuple)
             {
                 if (!inObject)
                     error("%s", msg);
-                errorException = this;
+                Type.typeinfotypelist = this;
             }
-            if (id == Id.cpp_type_info_ptr)
+            if (id == Id.TypeInfo_Const)
             {
                 if (!inObject)
                     error("%s", msg);
-                cpp_type_info_ptr = this;
+                Type.typeinfoconst = this;
+            }
+            if (id == Id.TypeInfo_Invariant)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfoinvariant = this;
+            }
+            if (id == Id.TypeInfo_Shared)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfoshared = this;
+            }
+            if (id == Id.TypeInfo_Wild)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfowild = this;
+            }
+            if (id == Id.TypeInfo_Vector)
+            {
+                if (!inObject)
+                    error("%s", msg);
+                Type.typeinfovector = this;
             }
         }
+
+        if (id == Id.Object)
+        {
+            if (!inObject)
+                error("%s", msg);
+            object = this;
+        }
+
+        if (id == Id.Throwable)
+        {
+            if (!inObject)
+                error("%s", msg);
+            throwable = this;
+        }
+        if (id == Id.Exception)
+        {
+            if (!inObject)
+                error("%s", msg);
+            exception = this;
+        }
+        if (id == Id.Error)
+        {
+            if (!inObject)
+                error("%s", msg);
+            errorException = this;
+        }
+        if (id == Id.cpp_type_info_ptr)
+        {
+            if (!inObject)
+                error("%s", msg);
+            cpp_type_info_ptr = this;
+        }
+
         baseok = Baseok.none;
     }
 
@@ -444,32 +442,6 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
     enum OFFSET_RUNTIME = 0x76543210;
     enum OFFSET_FWDREF = 0x76543211;
 
-    /*******************************************
-     * Determine if 'this' is a base class of cd.
-     */
-    bool isBaseOf(ClassDeclaration cd, int* poffset)
-    {
-        //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
-        if (poffset)
-            *poffset = 0;
-        while (cd)
-        {
-            /* cd.baseClass might not be set if cd is forward referenced.
-             */
-            if (!cd.baseClass && cd.semanticRun < PASS.semanticdone && !cd.isInterfaceDeclaration())
-            {
-                cd.dsymbolSemantic(null);
-                if (!cd.baseClass && cd.semanticRun < PASS.semanticdone)
-                    cd.error("base class is forward referenced by `%s`", toChars());
-            }
-
-            if (this == cd.baseClass)
-                return true;
-
-            cd = cd.baseClass;
-        }
-        return false;
-    }
 
     /*********************************************
      * Determine if 'this' has complete base class information.
@@ -498,7 +470,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         if (!members || !symtab) // opaque or addMember is not yet done
         {
             // .stringof is always defined (but may be hidden by some other symbol)
-            if (ident != Id.stringof && !(flags & IgnoreErrors))
+            if (ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
                 error("is forward referenced when looking for `%s`", ident.toChars());
             //*(char*)0=0;
             return null;
@@ -510,33 +482,34 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         if (flags & SearchImportsOnly)
             return s;
 
-        if (!s)
+        if (s)
+            return s;
+
+        // Search bases classes in depth-first, left to right order
+        foreach (b; (*baseclasses)[])
         {
-            // Search bases classes in depth-first, left to right order
-            for (size_t i = 0; i < baseclasses.dim; i++)
+            if (!b.sym)
+                continue;
+
+            if (!b.sym.symtab)
             {
-                BaseClass* b = (*baseclasses)[i];
-                if (b.sym)
-                {
-                    if (!b.sym.symtab)
-                        error("base `%s` is forward referenced", b.sym.ident.toChars());
-                    else
-                    {
-                        import dmd.access : symbolIsVisible;
-
-                        s = b.sym.search(loc, ident, flags);
-                        if (!s)
-                            continue;
-                        else if (s == this) // happens if s is nested in this and derives from this
-                            s = null;
-                        else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
-                            s = null;
-                        else
-                            break;
-                    }
-                }
+                error("base `%s` is forward referenced", b.sym.ident.toChars());
+                continue;
             }
+
+            import dmd.access : symbolIsVisible;
+
+            s = b.sym.search(loc, ident, flags);
+            if (!s)
+                continue;
+            else if (s == this) // happens if s is nested in this and derives from this
+                s = null;
+            else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
+                s = null;
+            else
+                break;
         }
+
         return s;
     }
 
@@ -749,57 +722,59 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
 
                 // the first entry might be a ClassInfo
                 //printf("\t[%d] = %s\n", i, fd.toChars());
-                if (ident == fd.ident && fd.type.covariant(tf) == 1)
+                if (ident != fd.ident || fd.type.covariant(tf) != 1)
                 {
-                    //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
-                    if (!fdmatch)
-                    {
-                        updateBestMatch(fd);
-                        continue;
-                    }
-                    if (fd == fdmatch)
-                        continue;
+                    //printf("\t\t%d\n", fd.type.covariant(tf));
+                    continue;
+                }
 
-                    {
-                    // Function type matching: exact > covariant
-                    MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
-                    MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
-                    if (m1 > m2)
-                    {
-                        updateBestMatch(fd);
-                        continue;
-                    }
-                    else if (m1 < m2)
-                        continue;
-                    }
-                    {
-                    MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
-                    MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
-                    if (m1 > m2)
-                    {
-                        updateBestMatch(fd);
-                        continue;
-                    }
-                    else if (m1 < m2)
-                        continue;
-                    }
-                    {
-                    // The way of definition: non-mixin > mixin
-                    MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
-                    MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
-                    if (m1 > m2)
-                    {
-                        updateBestMatch(fd);
-                        continue;
-                    }
-                    else if (m1 < m2)
-                        continue;
-                    }
+                //printf("fd.parent.isClassDeclaration() = %p\n", fd.parent.isClassDeclaration());
+                if (!fdmatch)
+                {
+                    updateBestMatch(fd);
+                    continue;
+                }
+                if (fd == fdmatch)
+                    continue;
 
-                    fdambig = fd;
-                    //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
+                {
+                // Function type matching: exact > covariant
+                MATCH m1 = tf.equals(fd.type) ? MATCH.exact : MATCH.nomatch;
+                MATCH m2 = tf.equals(fdmatch.type) ? MATCH.exact : MATCH.nomatch;
+                if (m1 > m2)
+                {
+                    updateBestMatch(fd);
+                    continue;
+                }
+                else if (m1 < m2)
+                    continue;
                 }
-                //else printf("\t\t%d\n", fd.type.covariant(tf));
+                {
+                MATCH m1 = (tf.mod == fd.type.mod) ? MATCH.exact : MATCH.nomatch;
+                MATCH m2 = (tf.mod == fdmatch.type.mod) ? MATCH.exact : MATCH.nomatch;
+                if (m1 > m2)
+                {
+                    updateBestMatch(fd);
+                    continue;
+                }
+                else if (m1 < m2)
+                    continue;
+                }
+                {
+                // The way of definition: non-mixin > mixin
+                MATCH m1 = fd.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
+                MATCH m2 = fdmatch.parent.isClassDeclaration() ? MATCH.exact : MATCH.nomatch;
+                if (m1 > m2)
+                {
+                    updateBestMatch(fd);
+                    continue;
+                }
+                else if (m1 < m2)
+                    continue;
+                }
+
+                fdambig = fd;
+                //printf("Lambig fdambig = %s %s [%s]\n", fdambig.toChars(), fdambig.type.toChars(), fdambig.loc.toChars());
             }
         }
 
@@ -985,7 +960,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
         return vtblsym;
     }
 
-    override final inout(ClassDeclaration) isClassDeclaration() inout
+    override final inout(ClassDeclaration) isClassDeclaration() inout @nogc nothrow pure @safe
     {
         return this;
     }
@@ -1032,73 +1007,6 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration
         return sc2;
     }
 
-    /*******************************************
-     * Determine if 'this' is a base class of cd.
-     * (Actually, if it is an interface supported by cd)
-     * Output:
-     *      *poffset        offset to start of class
-     *                      OFFSET_RUNTIME  must determine offset at runtime
-     * Returns:
-     *      false   not a base
-     *      true    is a base
-     */
-    override bool isBaseOf(ClassDeclaration cd, int* poffset)
-    {
-        //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
-        assert(!baseClass);
-        foreach (b; cd.interfaces)
-        {
-            //printf("\tX base %s\n", b.sym.toChars());
-            if (this == b.sym)
-            {
-                //printf("\tfound at offset %d\n", b.offset);
-                if (poffset)
-                {
-                    // don't return incorrect offsets
-                    // https://issues.dlang.org/show_bug.cgi?id=16980
-                    *poffset = cd.sizeok == Sizeok.done ? b.offset : OFFSET_FWDREF;
-                }
-                // printf("\tfound at offset %d\n", b.offset);
-                return true;
-            }
-            if (isBaseOf(b, poffset))
-                return true;
-        }
-        if (cd.baseClass && isBaseOf(cd.baseClass, poffset))
-            return true;
-
-        if (poffset)
-            *poffset = 0;
-        return false;
-    }
-
-    bool isBaseOf(BaseClass* bc, int* poffset)
-    {
-        //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.sym.toChars());
-        for (size_t j = 0; j < bc.baseInterfaces.length; j++)
-        {
-            BaseClass* b = &bc.baseInterfaces[j];
-            //printf("\tY base %s\n", b.sym.toChars());
-            if (this == b.sym)
-            {
-                //printf("\tfound at offset %d\n", b.offset);
-                if (poffset)
-                {
-                    *poffset = b.offset;
-                }
-                return true;
-            }
-            if (isBaseOf(b, poffset))
-            {
-                return true;
-            }
-        }
-
-        if (poffset)
-            *poffset = 0;
-        return false;
-    }
-
     /*******************************************
      */
     override const(char)* kind() const
@@ -1139,3 +1047,110 @@ extern (C++) final class InterfaceDeclaration : ClassDeclaration
         v.visit(this);
     }
 }
+
+
+/**
+ * Returns whether `bc` implements `id`, including indirectly (`bc` implements an interfaces
+ * that inherits from `id`)
+ *
+ * Params:
+ *    id = the interface
+ *    bc = the base class
+ *    poffset = out parameter, offset of the interface in an object
+ *
+ * Returns:
+ *    true if the `bc` implements `id`, false otherwise
+ **/
+private bool baseClassImplementsInterface(InterfaceDeclaration id, BaseClass* bc, int* poffset)
+{
+    //printf("%s.InterfaceDeclaration.isBaseOf(bc = '%s')\n", toChars(), bc.sym.toChars());
+    for (size_t j = 0; j < bc.baseInterfaces.length; j++)
+    {
+        BaseClass* b = &bc.baseInterfaces[j];
+        //printf("\tY base %s\n", b.sym.toChars());
+        if (id == b.sym)
+        {
+            //printf("\tfound at offset %d\n", b.offset);
+            if (poffset)
+            {
+                *poffset = b.offset;
+            }
+            return true;
+        }
+        if (baseClassImplementsInterface(id, b, poffset))
+        {
+            return true;
+        }
+    }
+
+    if (poffset)
+        *poffset = 0;
+    return false;
+}
+
+/*******************************************
+ * Determine if `derived` is a base class of cd.
+ * Or, if `derived` is an interface, is it implemented by `cd`
+ * Params:
+ *      derived = Potentially derived ClassDeclaration
+ *      cd = Potential base class
+ *      poffset = out parameter, offset to start of class. OFFSET_RUNTIME  must determine offset at runtime
+ * Returns:
+ *      false   not a base
+ *      true    is a base
+ */
+extern(C++) bool isBaseOf(ClassDeclaration derived, ClassDeclaration cd, int* poffset)
+{
+    if (auto id = derived.isInterfaceDeclaration())
+    {
+        //printf("%s.InterfaceDeclaration.isBaseOf(cd = '%s')\n", toChars(), cd.toChars());
+        assert(!id.baseClass);
+        foreach (b; cd.interfaces)
+        {
+            //printf("\tX base %s\n", b.sym.toChars());
+            if (id == b.sym)
+            {
+                //printf("\tfound at offset %d\n", b.offset);
+                if (poffset)
+                {
+                    // don't return incorrect offsets
+                    // https://issues.dlang.org/show_bug.cgi?id=16980
+                    *poffset = cd.sizeok == Sizeok.done ? b.offset : ClassDeclaration.OFFSET_FWDREF;
+                }
+                // printf("\tfound at offset %d\n", b.offset);
+                return true;
+            }
+            if (baseClassImplementsInterface(id, b, poffset))
+            return true;
+        }
+        if (cd.baseClass && id.isBaseOf(cd.baseClass, poffset))
+            return true;
+
+        if (poffset)
+            *poffset = 0;
+        return false;
+    }
+
+    //normal Class decl
+    //printf("ClassDeclaration.isBaseOf(this = '%s', cd = '%s')\n", toChars(), cd.toChars());
+    if (poffset)
+        *poffset = 0;
+    while (cd)
+    {
+        /* cd.baseClass might not be set if cd is forward referenced.
+         */
+        if (!cd.baseClass && cd.semanticRun < PASS.semanticdone && !cd.isInterfaceDeclaration())
+        {
+            cd.dsymbolSemantic(null);
+            if (!cd.baseClass && cd.semanticRun < PASS.semanticdone)
+                cd.error("base class is forward referenced by `%s`", derived.toChars());
+        }
+
+        if (derived == cd.baseClass)
+            return true;
+
+        cd = cd.baseClass;
+    }
+    return false;
+
+}
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 2135ef039dd..9426cf2343a 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -171,6 +171,13 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
                         MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
                 }
             }
+            else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+                     var.type.isImmutable())
+            {
+                .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
+                    MODtoChars(var.type.mod), var.kind(), var.toChars());
+                errorSupplemental(loc, "Use `shared static this` instead.");
+            }
             return result;
         }
         else
@@ -526,6 +533,12 @@ extern (C++) abstract class Declaration : Dsymbol
         return (storage_class & STC.ref_) != 0;
     }
 
+    /// Returns: Whether the variable is a reference, annotated with `out` or `ref`
+    final bool isReference() const pure nothrow @nogc @safe
+    {
+        return (storage_class & (STC.ref_ | STC.out_)) != 0;
+    }
+
     final bool isFuture() const pure nothrow @nogc @safe
     {
         return (storage_class & STC.future) != 0;
@@ -536,7 +549,7 @@ extern (C++) abstract class Declaration : Dsymbol
         return visibility;
     }
 
-    override final inout(Declaration) isDeclaration() inout
+    override final inout(Declaration) isDeclaration() inout pure nothrow @nogc @safe
     {
         return this;
     }
@@ -1727,7 +1740,7 @@ extern (C++) class TypeInfoDeclaration : VarDeclaration
         return buf.extractChars();
     }
 
-    override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout
+    override final inout(TypeInfoDeclaration) isTypeInfoDeclaration() inout @nogc nothrow pure @safe
     {
         return this;
     }
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 58f72c6e7a0..b44b6e14a55 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -134,6 +134,7 @@ public:
     bool isIn()  const  { return (storage_class & STCin) != 0; }
     bool isOut() const  { return (storage_class & STCout) != 0; }
     bool isRef() const  { return (storage_class & STCref) != 0; }
+    bool isReference() const { return (storage_class & (STCref | STCout)) != 0; }
 
     bool isFuture() const { return (storage_class & STCfuture) != 0; }
 
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index 2d449af9f7d..54467d8efd4 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -23,7 +23,6 @@ import dmd.dscope;
 import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
@@ -142,121 +141,6 @@ extern (C++) final class EnumDeclaration : ScopeDsymbol
         return visibility;
     }
 
-    /******************************
-     * Get the value of the .max/.min property as an Expression.
-     * Lazily computes the value and caches it in maxval/minval.
-     * Reports any errors.
-     * Params:
-     *      loc = location to use for error messages
-     *      id = Id::max or Id::min
-     * Returns:
-     *      corresponding value of .max/.min
-     */
-    Expression getMaxMinValue(const ref Loc loc, Identifier id)
-    {
-        //printf("EnumDeclaration::getMaxValue()\n");
-
-        static Expression pvalToResult(Expression e, const ref Loc loc)
-        {
-            if (e.op != TOK.error)
-            {
-                e = e.copy();
-                e.loc = loc;
-            }
-            return e;
-        }
-
-        Expression* pval = (id == Id.max) ? &maxval : &minval;
-
-        Expression errorReturn()
-        {
-            *pval = ErrorExp.get();
-            return *pval;
-        }
-
-        if (inuse)
-        {
-            error(loc, "recursive definition of `.%s` property", id.toChars());
-            return errorReturn();
-        }
-        if (*pval)
-            return pvalToResult(*pval, loc);
-
-        if (_scope)
-            dsymbolSemantic(this, _scope);
-        if (errors)
-            return errorReturn();
-        if (!members)
-        {
-            if (isSpecial())
-            {
-                /* Allow these special enums to not need a member list
-                 */
-                return memtype.getProperty(_scope, loc, id, 0);
-            }
-
-            error(loc, "is opaque and has no `.%s`", id.toChars());
-            return errorReturn();
-        }
-        if (!(memtype && memtype.isintegral()))
-        {
-            error(loc, "has no `.%s` property because base type `%s` is not an integral type", id.toChars(), memtype ? memtype.toChars() : "");
-            return errorReturn();
-        }
-
-        bool first = true;
-        for (size_t i = 0; i < members.dim; i++)
-        {
-            EnumMember em = (*members)[i].isEnumMember();
-            if (!em)
-                continue;
-            if (em.errors)
-            {
-                errors = true;
-                continue;
-            }
-
-            if (em.semanticRun < PASS.semanticdone)
-            {
-                em.error("is forward referenced looking for `.%s`", id.toChars());
-                errors = true;
-                continue;
-            }
-
-            if (first)
-            {
-                *pval = em.value;
-                first = false;
-            }
-            else
-            {
-                /* In order to work successfully with UDTs,
-                 * build expressions to do the comparisons,
-                 * and let the semantic analyzer and constant
-                 * folder give us the result.
-                 */
-
-                /* Compute:
-                 *   if (e > maxval)
-                 *      maxval = e;
-                 */
-                Expression e = em.value;
-                Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval);
-                inuse++;
-                ec = ec.expressionSemantic(em._scope);
-                inuse--;
-                ec = ec.ctfeInterpret();
-                if (ec.op == TOK.error)
-                {
-                    errors = true;
-                    continue;
-                }
-                if (ec.toInteger())
-                    *pval = e;
-            }
-        }
-        return errors ? errorReturn() : pvalToResult(*pval, loc);
-    }
 
     /****************
      * Determine if enum is a special one.
@@ -414,23 +298,6 @@ extern (C++) final class EnumMember : VarDeclaration
         return "enum member";
     }
 
-    Expression getVarExp(const ref Loc loc, Scope* sc)
-    {
-        dsymbolSemantic(this, sc);
-        if (errors)
-            return ErrorExp.get();
-        checkDisabled(loc, sc);
-
-        if (depdecl && !depdecl._scope)
-            depdecl._scope = sc;
-        checkDeprecated(loc, sc);
-
-        if (errors)
-            return ErrorExp.get();
-        Expression e = new VarExp(loc, this);
-        return e.expressionSemantic(sc);
-    }
-
     override inout(EnumMember) isEnumMember() inout
     {
         return this;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 853758a7197..541fac7dfb4 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -351,7 +351,7 @@ public:
     extern (C++) void pop(VarDeclaration v)
     {
         assert(!v.isDataseg() || v.isCTFE());
-        assert(!(v.storage_class & (STC.ref_ | STC.out_)));
+        assert(!v.isReference());
         const oldid = v.ctfeAdrOnStack;
         v.ctfeAdrOnStack = cast(uint)cast(size_t)savedId[oldid];
         if (v.ctfeAdrOnStack == values.dim - 1)
@@ -2132,7 +2132,7 @@ public:
                     errorSupplemental(vie.var.loc, "`%s` was uninitialized and used before set", vie.var.toChars());
                     return CTFEExp.cantexp;
                 }
-                if (goal != CTFEGoal.LValue && (v.isRef() || v.isOut()))
+                if (goal != CTFEGoal.LValue && v.isReference())
                     e = interpret(e, istate, goal);
             }
             if (!e)
@@ -2742,12 +2742,6 @@ public:
         {
             printf("%s NewExp::interpret() %s\n", e.loc.toChars(), e.toChars());
         }
-        if (e.allocator)
-        {
-            e.error("member allocators not supported by CTFE");
-            result = CTFEExp.cantexp;
-            return;
-        }
 
         Expression epre = interpret(pue, e.argprefix, istate, CTFEGoal.Nothing);
         if (exceptionOrCant(epre))
@@ -6139,6 +6133,9 @@ public:
             return;
         }
 
+        if (result.isStringExp())
+            return;
+
         if (result.op != TOK.address)
         {
             if (result.op == TOK.null_)
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 841fff6c485..768eaa05a08 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -67,7 +67,7 @@ enum package_di = "package." ~ hdr_ext;
 private const(char)[] lookForSourceFile(const char[] filename, const char*[] path)
 {
     //printf("lookForSourceFile(`%.*s`)\n", cast(int)filename.length, filename.ptr);
-    /* Search along path[] for .di file, then .d file.
+    /* Search along path[] for .di file, then .d file, then .i file, then .c file.
      */
     const sdi = FileName.forceExt(filename, hdr_ext);
     if (FileName.exists(sdi) == 1)
@@ -79,6 +79,11 @@ private const(char)[] lookForSourceFile(const char[] filename, const char*[] pat
         return sd;
     scope(exit) FileName.free(sd.ptr);
 
+    const si = FileName.forceExt(filename, i_ext);
+    if (FileName.exists(si) == 1)
+        return si;
+    scope(exit) FileName.free(si.ptr);
+
     const sc = FileName.forceExt(filename, c_ext);
     if (FileName.exists(sc) == 1)
         return sc;
@@ -120,6 +125,12 @@ private const(char)[] lookForSourceFile(const char[] filename, const char*[] pat
         }
         FileName.free(n.ptr);
 
+        n = FileName.combine(p, si);
+        if (FileName.exists(n) == 1) {
+            return n;
+        }
+        FileName.free(n.ptr);
+
         n = FileName.combine(p, sc);
         if (FileName.exists(n) == 1) {
             return n;
@@ -554,6 +565,7 @@ extern (C++) final class Module : Package
         else if (!FileName.equalsExt(srcfilename, mars_ext) &&
                  !FileName.equalsExt(srcfilename, hdr_ext) &&
                  !FileName.equalsExt(srcfilename, c_ext) &&
+                 !FileName.equalsExt(srcfilename, i_ext) &&
                  !FileName.equalsExt(srcfilename, dd_ext))
         {
 
@@ -1041,8 +1053,9 @@ extern (C++) final class Module : Package
         }
 
         /* If it has the extension ".c", it is a "C" file.
+         * If it has the extension ".i", it is a preprocessed "C" file.
          */
-        if (FileName.equalsExt(arg, c_ext))
+        if (FileName.equalsExt(arg, c_ext) || FileName.equalsExt(arg, i_ext))
         {
             isCFile = true;
 
@@ -1086,6 +1099,8 @@ extern (C++) final class Module : Package
                 foreach (id; md.packages[1 .. $]) // [b, c]
                 {
                     p = cast(Package) p.symtab.lookup(id);
+                    if (p is null)
+                        break;
                     addAccessiblePackage(p, Visibility(Visibility.Kind.private_));
                 }
             }
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 10ea91188e4..cddd08b4bab 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -24,14 +24,12 @@ import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
 import dmd.mtype;
 import dmd.opover;
-import dmd.semantic3;
 import dmd.target;
 import dmd.tokens;
 import dmd.typesem;
@@ -248,58 +246,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         return sd;
     }
 
-    final void semanticTypeInfoMembers()
-    {
-        if (xeq &&
-            xeq._scope &&
-            xeq.semanticRun < PASS.semantic3done)
-        {
-            uint errors = global.startGagging();
-            xeq.semantic3(xeq._scope);
-            if (global.endGagging(errors))
-                xeq = xerreq;
-        }
-
-        if (xcmp &&
-            xcmp._scope &&
-            xcmp.semanticRun < PASS.semantic3done)
-        {
-            uint errors = global.startGagging();
-            xcmp.semantic3(xcmp._scope);
-            if (global.endGagging(errors))
-                xcmp = xerrcmp;
-        }
-
-        FuncDeclaration ftostr = search_toString(this);
-        if (ftostr &&
-            ftostr._scope &&
-            ftostr.semanticRun < PASS.semantic3done)
-        {
-            ftostr.semantic3(ftostr._scope);
-        }
-
-        if (xhash &&
-            xhash._scope &&
-            xhash.semanticRun < PASS.semantic3done)
-        {
-            xhash.semantic3(xhash._scope);
-        }
-
-        if (postblit &&
-            postblit._scope &&
-            postblit.semanticRun < PASS.semantic3done)
-        {
-            postblit.semantic3(postblit._scope);
-        }
-
-        if (dtor &&
-            dtor._scope &&
-            dtor.semanticRun < PASS.semantic3done)
-        {
-            dtor.semantic3(dtor._scope);
-        }
-    }
-
     override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
     {
         //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
@@ -309,7 +255,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         if (!members || !symtab) // opaque or semantic() is not yet called
         {
             // .stringof is always defined (but may be hidden by some other symbol)
-            if(ident != Id.stringof && !(flags & IgnoreErrors))
+            if(ident != Id.stringof && !(flags & IgnoreErrors) && semanticRun < PASS.semanticdone)
                 error("is forward referenced when looking for `%s`", ident.toChars());
             return null;
         }
@@ -415,117 +361,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         argTypes = target.toArgTypes(type);
     }
 
-    /***************************************
-     * Fit elements[] to the corresponding types of the struct's fields.
-     *
-     * Params:
-     *      loc = location to use for error messages
-     *      sc = context
-     *      elements = explicit arguments used to construct object
-     *      stype = the constructed object type.
-     * Returns:
-     *      false if any errors occur,
-     *      otherwise true and elements[] are rewritten for the output.
-     */
-    final bool fit(const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
-    {
-        if (!elements)
-            return true;
-
-        const nfields = nonHiddenFields();
-        size_t offset = 0;
-        for (size_t i = 0; i < elements.dim; i++)
-        {
-            Expression e = (*elements)[i];
-            if (!e)
-                continue;
-
-            e = resolveProperties(sc, e);
-            if (i >= nfields)
-            {
-                if (i <= fields.dim && e.op == TOK.null_)
-                {
-                    // CTFE sometimes creates null as hidden pointer; we'll allow this.
-                    continue;
-                }
-                .error(loc, "more initializers than fields (%zu) of `%s`", nfields, toChars());
-                return false;
-            }
-            VarDeclaration v = fields[i];
-            if (v.offset < offset)
-            {
-                .error(loc, "overlapping initialization for `%s`", v.toChars());
-                if (!isUnionDeclaration())
-                {
-                    enum errorMsg = "`struct` initializers that contain anonymous unions" ~
-                                        " must initialize only the first member of a `union`. All subsequent" ~
-                                        " non-overlapping fields are default initialized";
-                    .errorSupplemental(loc, errorMsg);
-                }
-                return false;
-            }
-            offset = cast(uint)(v.offset + v.type.size());
-
-            Type t = v.type;
-            if (stype)
-                t = t.addMod(stype.mod);
-            Type origType = t;
-            Type tb = t.toBasetype();
-
-            const hasPointers = tb.hasPointers();
-            if (hasPointers)
-            {
-                if ((stype.alignment() < target.ptrsize ||
-                     (v.offset & (target.ptrsize - 1))) &&
-                    (sc.func && sc.func.setUnsafe()))
-                {
-                    .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
-                        toChars(), v.toChars());
-                    return false;
-                }
-            }
-
-            /* Look for case of initializing a static array with a too-short
-             * string literal, such as:
-             *  char[5] foo = "abc";
-             * Allow this by doing an explicit cast, which will lengthen the string
-             * literal.
-             */
-            if (e.op == TOK.string_ && tb.ty == Tsarray)
-            {
-                StringExp se = cast(StringExp)e;
-                Type typeb = se.type.toBasetype();
-                TY tynto = tb.nextOf().ty;
-                if (!se.committed &&
-                    (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
-                    se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
-                {
-                    e = se.castTo(sc, t);
-                    goto L1;
-                }
-            }
-
-            while (!e.implicitConvTo(t) && tb.ty == Tsarray)
-            {
-                /* Static array initialization, as in:
-                 *  T[3][5] = e;
-                 */
-                t = tb.nextOf();
-                tb = t.toBasetype();
-            }
-            if (!e.implicitConvTo(t))
-                t = origType; // restore type for better diagnostic
-
-            e = e.implicitCastTo(sc, t);
-        L1:
-            if (e.op == TOK.error)
-                return false;
-
-            (*elements)[i] = doCopyOrMove(sc, e);
-        }
-        return true;
-    }
-
     /***************************************
      * Determine if struct is POD (Plain Old Data).
      *
@@ -580,7 +415,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
         return (ispod == StructPOD.yes);
     }
 
-    override final inout(StructDeclaration) isStructDeclaration() inout
+    override final inout(StructDeclaration) isStructDeclaration() inout @nogc nothrow pure @safe
     {
         return this;
     }
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 09d8dc67e8b..a90ed019a5b 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -17,6 +17,7 @@ import core.stdc.string;
 
 import dmd.aggregate;
 import dmd.aliasthis;
+import dmd.apply;
 import dmd.arraytypes;
 import dmd.astcodegen;
 import dmd.astenums;
@@ -1977,18 +1978,23 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
-        ed.semanticRun = PASS.semanticdone;
-
         if (!ed.members) // enum ident : memtype;
+        {
+            ed.semanticRun = PASS.semanticdone;
             return;
+        }
 
         if (ed.members.dim == 0)
         {
             ed.error("enum `%s` must have at least one member", ed.toChars());
             ed.errors = true;
+            ed.semanticRun = PASS.semanticdone;
             return;
         }
 
+        if (!(sc.flags & SCOPE.Cfile))  // C enum remains incomplete until members are done
+            ed.semanticRun = PASS.semanticdone;
+
         Module.dprogress++;
 
         Scope* sce;
@@ -2017,6 +2023,69 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
          */
         addEnumMembers(ed, sc, sc.getScopesym());
 
+        if (sc.flags & SCOPE.Cfile)
+        {
+            /* C11 6.7.2.2
+             */
+            ed.memtype = Type.tint32; // C11 6.7.2.2-4 implementation defined
+            int nextValue = 0;        // C11 6.7.2.2-3 first member value defaults to 0
+
+            void emSemantic(EnumMember em, ref int nextValue)
+            {
+                static void errorReturn(EnumMember em)
+                {
+                    em.errors = true;
+                    em.semanticRun = PASS.semanticdone;
+                }
+
+                em.semanticRun = PASS.semantic;
+                em.type = Type.tint32;
+                em.linkage = LINK.c;
+                em.storage_class |= STC.manifest;
+                if (em.value)
+                {
+                    Expression e = em.value;
+                    assert(e.dyncast() == DYNCAST.expression);
+                    e = e.expressionSemantic(sc);
+                    e = resolveProperties(sc, e);
+                    e = e.integralPromotions(sc);
+                    e = e.ctfeInterpret();
+                    if (e.op == TOK.error)
+                        return errorReturn(em);
+                    auto ie = e.isIntegerExp();
+                    if (!ie)
+                    {
+                        // C11 6.7.2.2-2
+                        em.error("enum member must be an integral constant expression, not `%s` of type `%s`", e.toChars(), e.type.toChars());
+                        return errorReturn(em);
+                    }
+                    const sinteger_t v = ie.toInteger();
+                    if (v < int.min || v > uint.max)
+                    {
+                        // C11 6.7.2.2-2
+                        em.error("enum member value `%s` does not fit in an `int`", e.toChars());
+                        return errorReturn(em);
+                    }
+                    em.value = new IntegerExp(em.loc, cast(int)v, Type.tint32);
+                    nextValue = cast(int)v;
+                }
+                else
+                {
+                    em.value = new IntegerExp(em.loc, nextValue, Type.tint32);
+                }
+                ++nextValue; // C11 6.7.2.2-3 add 1 to value of previous enumeration constant
+                em.semanticRun = PASS.semanticdone;
+            }
+
+            ed.members.foreachDsymbol( (s)
+            {
+                if (EnumMember em = s.isEnumMember())
+                    emSemantic(em, nextValue);
+            });
+            ed.semanticRun = PASS.semanticdone;
+            return;
+        }
+
         ed.members.foreachDsymbol( (s)
         {
             if (EnumMember em = s.isEnumMember())
@@ -4146,55 +4215,10 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
     override void visit(NewDeclaration nd)
     {
         //printf("NewDeclaration::semantic()\n");
-
-        // `@disable new();` should not be deprecated
-        if (!nd.isDisabled())
-        {
-            // @@@DEPRECATED_2.091@@@
-            // Made an error in 2.087.
-            // Should be removed in 2.091
-            error(nd.loc, "class allocators are obsolete, consider moving the allocation strategy outside of the class");
-        }
-
         if (nd.semanticRun >= PASS.semanticdone)
             return;
-        if (nd._scope)
-        {
-            sc = nd._scope;
-            nd._scope = null;
-        }
-
-        nd.parent = sc.parent;
-        Dsymbol p = nd.parent.pastMixin();
-        if (!p.isAggregateDeclaration())
-        {
-            error(nd.loc, "allocator can only be a member of aggregate, not %s `%s`", p.kind(), p.toChars());
-            nd.type = Type.terror;
-            nd.errors = true;
-            return;
-        }
-        Type tret = Type.tvoid.pointerTo();
         if (!nd.type)
-            nd.type = new TypeFunction(nd.parameterList, tret, LINK.d, nd.storage_class);
-
-        nd.type = nd.type.typeSemantic(nd.loc, sc);
-
-        // allow for `@disable new();` to force users of a type to use an external allocation strategy
-        if (!nd.isDisabled())
-        {
-            // Check that there is at least one argument of type size_t
-            TypeFunction tf = nd.type.toTypeFunction();
-            if (tf.parameterList.length < 1)
-            {
-                nd.error("at least one argument of type `size_t` expected");
-            }
-            else
-            {
-                Parameter fparam = tf.parameterList[0];
-                if (!fparam.type.equals(Type.tsize_t))
-                    nd.error("first argument must be type `size_t`, not `%s`", fparam.type.toChars());
-            }
-        }
+            nd.type = new TypeFunction(ParameterList(), Type.tvoid.pointerTo(), LINK.d, nd.storage_class);
 
         funcDeclarationSemantic(nd);
     }
@@ -4323,7 +4347,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         /* Look for special member functions.
          */
-        sd.aggNew = cast(NewDeclaration)sd.search(Loc.initial, Id.classNew);
+        sd.disableNew = sd.search(Loc.initial, Id.classNew) !is null;
 
         // Look for the constructor
         sd.ctor = sd.searchCtor();
@@ -4916,7 +4940,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
          * They must be in this class, not in a base class.
          */
         // Can be in base class
-        cldec.aggNew = cast(NewDeclaration)cldec.search(Loc.initial, Id.classNew);
+        cldec.disableNew = cldec.search(Loc.initial, Id.classNew) !is null;
 
         // Look for the constructor
         cldec.ctor = cldec.searchCtor();
@@ -6475,3 +6499,91 @@ private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
 
     ds.semanticRun = PASS.semanticdone;
 }
+
+/***************************************
+ * Find all instance fields in `ad`, then push them into `fields`.
+ *
+ * Runs semantic() for all instance field variables, but also
+ * the field types can remain yet not resolved forward references,
+ * except direct recursive definitions.
+ * After the process sizeok is set to Sizeok.fwd.
+ *
+ * Params:
+ *      ad = the AggregateDeclaration to examine
+ * Returns:
+ *      false if any errors occur.
+ */
+bool determineFields(AggregateDeclaration ad)
+{
+    if (ad._scope)
+        dsymbolSemantic(ad, null);
+    if (ad.sizeok != Sizeok.none)
+        return true;
+
+    //printf("determineFields() %s, fields.dim = %d\n", toChars(), fields.dim);
+    // determineFields can be called recursively from one of the fields's v.semantic
+    ad.fields.setDim(0);
+
+    static int func(Dsymbol s, AggregateDeclaration ad)
+    {
+        auto v = s.isVarDeclaration();
+        if (!v)
+            return 0;
+        if (v.storage_class & STC.manifest)
+            return 0;
+
+        if (v.semanticRun < PASS.semanticdone)
+            v.dsymbolSemantic(null);
+        // Return in case a recursive determineFields triggered by v.semantic already finished
+        if (ad.sizeok != Sizeok.none)
+            return 1;
+
+        if (v.aliassym)
+            return 0;   // If this variable was really a tuple, skip it.
+
+        if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
+            return 0;
+        if (!v.isField() || v.semanticRun < PASS.semanticdone)
+            return 1;   // unresolvable forward reference
+
+        ad.fields.push(v);
+
+        if (v.storage_class & STC.ref_)
+            return 0;
+        auto tv = v.type.baseElemOf();
+        if (auto tvs = tv.isTypeStruct())
+        {
+            if (ad == tvs.sym)
+            {
+                const(char)* psz = (v.type.toBasetype().ty == Tsarray) ? "static array of " : "";
+                ad.error("cannot have field `%s` with %ssame struct type", v.toChars(), psz);
+                ad.type = Type.terror;
+                ad.errors = true;
+                return 1;
+            }
+        }
+        return 0;
+    }
+
+    if (ad.members)
+    {
+        for (size_t i = 0; i < ad.members.dim; i++)
+        {
+            auto s = (*ad.members)[i];
+            if (s.apply(&func, ad))
+            {
+                if (ad.sizeok != Sizeok.none)
+                {
+                    // recursive determineFields already finished
+                    return true;
+                }
+                return false;
+            }
+        }
+    }
+
+    if (ad.sizeok != Sizeok.done)
+        ad.sizeok = Sizeok.fwd;
+
+    return true;
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 524f62484a9..60058977701 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -1842,7 +1842,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
                     // https://issues.dlang.org/show_bug.cgi?id=12876
                     // Optimize argument to allow CT-known length matching
-                    farg = farg.optimize(WANTvalue, (fparam.storageClass & (STC.ref_ | STC.out_)) != 0);
+                    farg = farg.optimize(WANTvalue, fparam.isReference());
                     //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
 
                     RootObject oarg = farg;
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 00f8a0e61b1..867e7802913 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -271,6 +271,9 @@ public:
 
         /// Processing a type that can be forward referenced
         bool forwarding;
+
+        /// Inside of an anonymous struct/union (AnonDeclaration)
+        bool inAnonymousDecl;
     }
 
     /// Informations about the current context in the AST
@@ -378,7 +381,7 @@ public:
     private void writeProtection(const AST.Visibility.Kind kind)
     {
         // Don't write visibility for global declarations
-        if (!adparent)
+        if (!adparent || inAnonymousDecl)
             return;
 
         string token;
@@ -518,20 +521,15 @@ public:
     {
         debug (Debug_DtoH)
         {
-            printf("[AST.Dsymbol enter] %s\n", s.toChars());
+            mixin(traceVisit!s);
             import dmd.asttypename;
             printf("[AST.Dsymbol enter] %s\n", s.astTypeName().ptr);
-            scope(exit) printf("[AST.Dsymbol exit] %s\n", s.toChars());
         }
     }
 
     override void visit(AST.Import i)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.Import enter] %s\n", i.toChars());
-            scope(exit) printf("[AST.Import exit] %s\n", i.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!i);
 
         /// Writes `using <alias_> = <sym.ident>` into `buf`
         const(char*) writeImport(AST.Dsymbol sym, const Identifier alias_)
@@ -644,11 +642,8 @@ public:
 
     override void visit(AST.AttribDeclaration pd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.AttribDeclaration enter] %s\n", pd.toChars());
-            scope(exit) printf("[AST.AttribDeclaration exit] %s\n", pd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!pd);
+
         Dsymbols* decl = pd.include(null);
         if (!decl)
             return;
@@ -662,11 +657,8 @@ public:
 
     override void visit(AST.StorageClassDeclaration scd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.StorageClassDeclaration enter] %s\n", scd.toChars());
-            scope(exit) printf("[AST.StorageClassDeclaration exit] %s\n", scd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!scd);
+
         const stcStash = this.storageClass;
         this.storageClass |= scd.stc;
         visit(cast(AST.AttribDeclaration) scd);
@@ -675,11 +667,8 @@ public:
 
     override void visit(AST.LinkDeclaration ld)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.LinkDeclaration enter] %s\n", ld.toChars());
-            scope(exit) printf("[AST.LinkDeclaration exit] %s\n", ld.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ld);
+
         auto save = linkage;
         linkage = ld.linkage;
         visit(cast(AST.AttribDeclaration)ld);
@@ -688,6 +677,8 @@ public:
 
     override void visit(AST.CPPMangleDeclaration md)
     {
+        debug (Debug_DtoH) mixin(traceVisit!md);
+
         const oldLinkage = this.linkage;
         this.linkage = LINK.cpp;
         visit(cast(AST.AttribDeclaration) md);
@@ -696,11 +687,8 @@ public:
 
     override void visit(AST.Module m)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.Module enter] %s\n", m.toChars());
-            scope(exit) printf("[AST.Module exit] %s\n", m.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!m);
+
         foreach (s; *m.members)
         {
             if (s.visible().kind < AST.Visibility.Kind.public_)
@@ -711,11 +699,8 @@ public:
 
     override void visit(AST.FuncDeclaration fd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.FuncDeclaration enter] %s\n", fd.toChars());
-            scope(exit) printf("[AST.FuncDeclaration exit] %s\n", fd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!fd);
+
         if (cast(void*)fd in visited)
             return;
         // printf("FuncDeclaration %s %s\n", fd.toPrettyChars(), fd.type.toChars());
@@ -840,20 +825,13 @@ public:
 
     override void visit(AST.UnitTestDeclaration utd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.UnitTestDeclaration enter] %s\n", utd.toChars());
-            scope(exit) printf("[AST.UnitTestDeclaration exit] %s\n", utd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!utd);
     }
 
     override void visit(AST.VarDeclaration vd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.VarDeclaration enter] %s\n", vd.toChars());
-            scope(exit) printf("[AST.VarDeclaration exit] %s\n", vd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!vd);
+
         if (!shouldEmit(vd))
             return;
 
@@ -1006,20 +984,12 @@ public:
 
     override void visit(AST.TypeInfoDeclaration tid)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeInfoDeclaration enter] %s\n", tid.toChars());
-            scope(exit) printf("[AST.TypeInfoDeclaration exit] %s\n", tid.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!tid);
     }
 
     override void visit(AST.AliasDeclaration ad)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.AliasDeclaration enter] %s\n", ad.toChars());
-            scope(exit) printf("[AST.AliasDeclaration exit] %s\n", ad.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ad);
 
         if (!shouldEmit(ad))
             return;
@@ -1141,11 +1111,13 @@ public:
 
     override void visit(AST.Nspace ns)
     {
+        debug (Debug_DtoH) mixin(traceVisit!ns);
         handleNspace(ns, ns.members);
     }
 
     override void visit(AST.CPPNamespaceDeclaration ns)
     {
+        debug (Debug_DtoH) mixin(traceVisit!ns);
         handleNspace(ns, ns.decl);
     }
 
@@ -1169,11 +1141,11 @@ public:
 
     override void visit(AST.AnonDeclaration ad)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.AnonDeclaration enter] %s\n", ad.toChars());
-            scope(exit) printf("[AST.AnonDeclaration exit] %s\n", ad.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ad);
+
+        const anonStash = inAnonymousDecl;
+        inAnonymousDecl = true;
+        scope (exit) inAnonymousDecl = anonStash;
 
         buf.writestringln(ad.isunion ? "union" : "struct");
         buf.writestringln("{");
@@ -1201,11 +1173,7 @@ public:
 
     override void visit(AST.StructDeclaration sd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.StructDeclaration enter] %s\n", sd.toChars());
-            scope(exit) printf("[AST.StructDeclaration exit] %s\n", sd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!sd);
 
         if (!shouldEmit(sd))
             return;
@@ -1407,11 +1375,7 @@ public:
 
     override void visit(AST.ClassDeclaration cd)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.ClassDeclaration enter] %s\n", cd.toChars());
-            scope(exit) printf("[AST.ClassDeclaration exit] %s\n", cd.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!cd);
 
         if (!shouldEmit(cd))
             return;
@@ -1475,11 +1439,8 @@ public:
 
     override void visit(AST.EnumDeclaration ed)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.EnumDeclaration enter] %s\n", ed.toChars());
-            scope(exit) printf("[AST.EnumDeclaration exit] %s\n", ed.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ed);
+
         if (!shouldEmit(ed))
             return;
 
@@ -1749,32 +1710,21 @@ public:
 
     override void visit(AST.Type t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.Type enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.Type exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
         printf("Invalid type: %s\n", t.toPrettyChars());
         assert(0);
     }
 
     override void visit(AST.TypeNoreturn t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeNoreturn enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeNoreturn exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         buf.writestring("/* noreturn */ char");
     }
 
     override void visit(AST.TypeIdentifier t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeIdentifier enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeIdentifier exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
 
         // Try to resolve the referenced symbol
         if (auto sym = findSymbol(t.ident))
@@ -1802,11 +1752,8 @@ public:
 
     override void visit(AST.TypeNull t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeNull enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeNull exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         if (global.params.cplusplus >= CppStdRevision.cpp11)
             buf.writestring("nullptr_t");
         else
@@ -1816,11 +1763,8 @@ public:
 
     override void visit(AST.TypeTypeof t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeInstance enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeInstance exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         assert(t.exp);
 
         if (t.exp.type)
@@ -1845,11 +1789,8 @@ public:
 
     override void visit(AST.TypeBasic t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeBasic enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeBasic exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         if (t.isConst() || t.isImmutable())
             buf.writestring("const ");
         string typeName;
@@ -1897,11 +1838,8 @@ public:
 
     override void visit(AST.TypePointer t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypePointer enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypePointer exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         auto ts = t.next.isTypeStruct();
         if (ts && !strcmp(ts.sym.ident.toChars(), "__va_list_tag"))
         {
@@ -1923,31 +1861,20 @@ public:
 
     override void visit(AST.TypeSArray t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeSArray enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeSArray exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
         t.next.accept(this);
     }
 
     override void visit(AST.TypeAArray t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeAArray enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeAArray exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
         AST.Type.tvoidptr.accept(this);
     }
 
     override void visit(AST.TypeFunction tf)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeFunction enter] %s\n", tf.toChars());
-            scope(exit) printf("[AST.TypeFunction exit] %s\n", tf.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!tf);
+
         tf.next.accept(this);
         buf.writeByte('(');
         buf.writeByte('*');
@@ -1975,11 +1902,8 @@ public:
     /// (Might not be `ed` for special enums or enums that were emitted as namespaces)
     private void enumToBuffer(AST.EnumDeclaration ed)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[enumToBuffer(AST.EnumDeclaration) enter] %s\n", ed.toChars());
-            scope(exit) printf("[enumToBuffer(AST.EnumDeclaration) exit] %s\n", ed.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ed);
+
         if (ed.isSpecial())
         {
             if (ed.ident == DMDType.c_long)
@@ -2025,11 +1949,7 @@ public:
 
     override void visit(AST.TypeEnum t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeEnum enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeEnum exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
 
         if (t.isConst() || t.isImmutable())
             buf.writestring("const ");
@@ -2038,11 +1958,7 @@ public:
 
     override void visit(AST.TypeStruct t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeStruct enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeStruct exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
 
         if (t.isConst() || t.isImmutable())
             buf.writestring("const ");
@@ -2051,11 +1967,8 @@ public:
 
     override void visit(AST.TypeDArray t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeDArray enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeDArray exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         if (t.isConst() || t.isImmutable())
             buf.writestring("const ");
         buf.writestring("_d_dynamicArray< ");
@@ -2065,21 +1978,12 @@ public:
 
     override void visit(AST.TypeInstance t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeInstance enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeInstance exit] %s\n", t.toChars());
-        }
         visitTi(t.tempinst);
     }
 
     private void visitTi(AST.TemplateInstance ti)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[visitTi(AST.TemplateInstance) enter] %s\n", ti.toChars());
-            scope(exit) printf("[visitTi(AST.TemplateInstance) exit] %s\n", ti.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!ti);
 
         // Ensure that the TD appears before the instance
         if (auto td = findTemplateDeclaration(ti))
@@ -2112,11 +2016,8 @@ public:
 
     override void visit(AST.TemplateDeclaration td)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TemplateDeclaration enter] %s\n", td.toChars());
-            scope(exit) printf("[AST.TemplateDeclaration exit] %s\n", td.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!td);
+
         if (!shouldEmit(td))
             return;
 
@@ -2171,11 +2072,7 @@ public:
     /// Emit declarations of the TemplateMixin in the current scope
     override void visit(AST.TemplateMixin tm)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TemplateMixin enter] %s\n", tm.toChars());
-            scope(exit) printf("[AST.TemplateMixin exit] %s\n", tm.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!tm);
 
         auto members = tm.members;
 
@@ -2256,11 +2153,7 @@ public:
 
     override void visit(AST.TypeClass t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.TypeClass enter] %s\n", t.toChars());
-            scope(exit) printf("[AST.TypeClass exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
 
         // Classes are emitted as pointer and hence can be forwarded
         const fwdSave = forwarding;
@@ -2340,13 +2233,18 @@ public:
 
     override void visit(AST.Parameter p)
     {
-        debug (Debug_DtoH)
+        debug (Debug_DtoH) mixin(traceVisit!p);
+
+        ident = p.ident;
+
         {
-            printf("[AST.Parameter enter] %s\n", p.toChars());
-            scope(exit) printf("[AST.Parameter exit] %s\n", p.toChars());
+            // Reference parameters can be forwarded
+            const fwdStash = this.forwarding;
+            this.forwarding = !!(p.storageClass & AST.STC.ref_);
+            p.type.accept(this);
+            this.forwarding = fwdStash;
         }
-        ident = p.ident;
-        p.type.accept(this);
+
         if (p.storageClass & AST.STC.ref_)
             buf.writeByte('&');
         buf.writeByte(' ');
@@ -2479,11 +2377,8 @@ public:
 
     override void visit(AST.Expression e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.Expression enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.Expression exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
+
         // Valid in most cases, others should be overriden below
         // to use the appropriate operators  (:: and ->)
         buf.writestring(e.toString());
@@ -2491,11 +2386,7 @@ public:
 
     override void visit(AST.UnaExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.UnaExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.UnaExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         buf.writestring(tokToString(e.op));
         e.e1.accept(this);
@@ -2503,11 +2394,7 @@ public:
 
     override void visit(AST.BinExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.BinExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.BinExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         e.e1.accept(this);
         buf.writeByte(' ');
@@ -2530,11 +2417,7 @@ public:
 
     override void visit(AST.VarExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.VarExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.VarExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         // Local members don't need another prefix and might've been renamed
         if (e.var.isThis())
@@ -2558,11 +2441,7 @@ public:
 
     override void visit(AST.CallExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.CallExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.CallExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         // Dereferencing function pointers requires additional braces: (*f)(args)
         const isFp = e.e1.isPtrExp();
@@ -2588,11 +2467,7 @@ public:
 
     override void visit(AST.DotVarExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.DotVarExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.DotVarExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         if (auto sym = symbolFromType(e.e1.type))
             includeSymbol(outermostSymbol(sym));
@@ -2617,11 +2492,7 @@ public:
 
     override void visit(AST.DotIdExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.DotIdExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.DotIdExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         e.e1.accept(this);
         buf.writestring("::");
@@ -2630,11 +2501,7 @@ public:
 
     override void visit(AST.ScopeExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.ScopeExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.ScopeExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         // Usually a template instance in a TemplateDeclaration
         if (auto ti = e.sds.isTemplateInstance())
@@ -2645,11 +2512,8 @@ public:
 
     override void visit(AST.NullExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.NullExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.NullExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
+
         if (global.params.cplusplus >= CppStdRevision.cpp11)
             buf.writestring("nullptr");
         else
@@ -2658,21 +2522,13 @@ public:
 
     override void visit(AST.ArrayLiteralExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.ArrayLiteralExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.ArrayLiteralExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
         buf.writestring("arrayliteral");
     }
 
     override void visit(AST.StringExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.StringExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.StringExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         if (e.sz == 2)
             buf.writeByte('u');
@@ -2709,11 +2565,7 @@ public:
 
     override void visit(AST.RealExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.RealExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.RealExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
 
         import dmd.root.ctfloat : CTFloat;
 
@@ -2740,22 +2592,15 @@ public:
 
     override void visit(AST.IntegerExp e)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.IntegerExp enter] %s\n", e.toChars());
-            scope(exit) printf("[AST.IntegerExp exit] %s\n", e.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!e);
         visitInteger(e.toInteger, e.type);
     }
 
     /// Writes `v` as type `t` into `buf`
     private void visitInteger(dinteger_t v, AST.Type t)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[visitInteger(AST.Type) enter] %s\n", t.toChars());
-            scope(exit) printf("[visitInteger(AST.Type) exit] %s\n", t.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!t);
+
         switch (t.ty)
         {
             case AST.Tenum:
@@ -2808,11 +2653,8 @@ public:
 
     override void visit(AST.StructLiteralExp sle)
     {
-        debug (Debug_DtoH)
-        {
-            printf("[AST.StructLiteralExp enter] %s\n", sle.toChars());
-            scope(exit) printf("[AST.StructLiteralExp exit] %s\n", sle.toChars());
-        }
+        debug (Debug_DtoH) mixin(traceVisit!sle);
+
         const isUnion = sle.sd.isUnionDeclaration();
         sle.sd.type.accept(this);
         buf.writeByte('(');
@@ -3014,8 +2856,12 @@ public:
     /**
      * Writes the qualified name of `sym` into `buf` including parent
      * symbols and template parameters.
+     *
+     * Params:
+     *   sym         = the symbol
+     *   mustInclude = whether sym may not be forward declared
      */
-    private void writeFullName(AST.Dsymbol sym)
+    private void writeFullName(AST.Dsymbol sym, const bool mustInclude = false)
     in
     {
         assert(sym);
@@ -3059,13 +2905,20 @@ public:
             nested = !par.isModule();
             if (nested && !isNestedIn(par, adparent))
             {
-                writeFullName(par);
+                writeFullName(par, true);
                 buf.writestring("::");
             }
         }
 
         if (!nested)
-            ensureDeclared(sym);
+        {
+            // Cannot forward the symbol when called recursively
+            // for a nested symbol
+            if (mustInclude)
+                includeSymbol(sym);
+            else
+                ensureDeclared(sym);
+        }
 
         if (ti)
             visitTi(ti);
@@ -3316,3 +3169,17 @@ ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
 
     return search(sds.members, name);
 }
+
+debug (Debug_DtoH)
+{
+    /// Generates code to trace the entry and exit of the enclosing `visit` function
+    string traceVisit(alias node)()
+    {
+        const type = typeof(node).stringof;
+        const method = __traits(hasMember, node, "toPrettyChars") ? "toPrettyChars" : "toChars";
+        const arg = __traits(identifier, node) ~ '.' ~ method;
+
+        return `printf("[` ~ type ~  ` enter] %s\n", ` ~ arg ~ `());
+                scope(exit) printf("[` ~ type ~ ` exit] %s\n", ` ~ arg ~ `());`;
+    }
+}
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index eb3e2bc183f..76c1235715b 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -49,7 +49,6 @@ public:
     Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
     bool isDeprecated() const;                // is Dsymbol deprecated?
     Visibility visible();
-    Expression *getMaxMinValue(const Loc &loc, Identifier *id);
     bool isSpecial() const;
     Expression *getDefaultValue(const Loc &loc);
     Type *getMemtype(const Loc &loc);
@@ -81,7 +80,6 @@ public:
 
     EnumMember *syntaxCopy(Dsymbol *s);
     const char *kind() const;
-    Expression *getVarExp(const Loc &loc, Scope *sc);
 
     EnumMember *isEnumMember() { return this; }
     void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 8d5857461e9..2b0b242a90e 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -374,7 +374,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
 
         notMaybeScope(v);
 
-        if ((v.storage_class & (STC.ref_ | STC.out_)) == 0 && p == sc.func)
+        if (!v.isReference() && p == sc.func)
         {
             if (par && (par.storageClass & (STC.scope_ | STC.return_)) == STC.scope_)
                 continue;
@@ -399,7 +399,7 @@ bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
 
             notMaybeScope(v);
 
-            if ((v.storage_class & (STC.ref_ | STC.out_ | STC.scope_)) && p == sc.func)
+            if ((v.isReference() || v.isScope()) && p == sc.func)
             {
                 unsafeAssign(v, "reference to local");
                 continue;
@@ -471,12 +471,9 @@ bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
     if (!ce.arguments && ce.arguments.dim)
         return false;
 
-    assert(ce.e1.op == TOK.dotVariable);
-    DotVarExp dve = cast(DotVarExp)ce.e1;
+    DotVarExp dve = ce.e1.isDotVarExp();
     CtorDeclaration ctor = dve.var.isCtorDeclaration();
-    assert(ctor);
-    assert(ctor.type.ty == Tfunction);
-    TypeFunction tf = cast(TypeFunction)ctor.type;
+    TypeFunction tf = ctor.type.isTypeFunction();
 
     const nparams = tf.parameterList.length;
     const n = ce.arguments.dim;
@@ -590,12 +587,12 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
     // Try to infer 'scope' for va if in a function not marked @system
     bool inferScope = false;
     if (va && sc.func && sc.func.type && sc.func.type.ty == Tfunction)
-        inferScope = (cast(TypeFunction)sc.func.type).trust != TRUST.system;
+        inferScope = sc.func.type.isTypeFunction().trust != TRUST.system;
     //printf("inferScope = %d, %d\n", inferScope, (va.storage_class & STCmaybescope) != 0);
 
     // Determine if va is a parameter that is an indirect reference
     const bool vaIsRef = va && va.storage_class & STC.parameter &&
-        (va.storage_class & (STC.ref_ | STC.out_) || va.type.toBasetype().ty == Tclass);
+        (va.isReference() || va.type.toBasetype().ty == Tclass);
     if (log && vaIsRef) printf("va is ref `%s`\n", va.toChars());
 
     /* Determine if va is the first parameter, through which other 'return' parameters
@@ -609,7 +606,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
         FuncDeclaration fd = sc.func;
         if (p == fd && fd.type && fd.type.ty == Tfunction)
         {
-            TypeFunction tf = cast(TypeFunction)fd.type;
+            TypeFunction tf = fd.type.isTypeFunction();
             if (!tf.nextOf() || (tf.nextOf().ty != Tvoid && !fd.isCtorDeclaration()))
                 return false;
             if (va == fd.vthis)
@@ -688,7 +685,7 @@ bool checkAssignEscape(Scope* sc, Expression e, bool gag)
                  // va is class reference
                  ae.e1.op == TOK.dotVariable && va.type.toBasetype().ty == Tclass && (va.enclosesLifetimeOf(v) || !va.isScope()) ||
                  vaIsRef ||
-                 va.storage_class & (STC.ref_ | STC.out_) && !(v.storage_class & (STC.parameter | STC.temp))) &&
+                 va.isReference() && !(v.storage_class & (STC.parameter | STC.temp))) &&
                 sc.func.setUnsafe())
             {
                 if (!gag)
@@ -757,7 +754,7 @@ ByRef:
 
         if (global.params.useDIP1000 == FeatureState.enabled)
         {
-            if (va && va.isScope() && (v.storage_class & (STC.ref_ | STC.out_)) == 0)
+            if (va && va.isScope() && !v.isReference())
             {
                 if (!(va.storage_class & STC.return_))
                 {
@@ -787,7 +784,7 @@ ByRef:
             continue;
         }
 
-        if (va && v.storage_class & (STC.ref_ | STC.out_))
+        if (va && v.isReference())
         {
             Dsymbol pva = va.toParent2();
             for (Dsymbol pv = p; pv; )
@@ -810,7 +807,7 @@ ByRef:
         if (!(va && va.isScope()))
             notMaybeScope(v);
 
-        if ((v.storage_class & (STC.ref_ | STC.out_)) || p != sc.func)
+        if (v.isReference() || p != sc.func)
             continue;
 
         if (va && !va.isDataseg() && !va.doNotInferScope)
@@ -855,7 +852,7 @@ ByRef:
             if (!(va && va.isScope()))
                 notMaybeScope(v);
 
-            if (!(v.storage_class & (STC.ref_ | STC.out_ | STC.scope_)) || p != sc.func)
+            if (!(v.isReference() || v.isScope()) || p != sc.func)
                 continue;
 
             if (va && !va.isDataseg() && !va.doNotInferScope)
@@ -1086,7 +1083,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
 
         Dsymbol p = v.toParent2();
 
-        if ((v.storage_class & (STC.ref_ | STC.out_)) == 0)
+        if (!v.isReference())
         {
             if (p == sc.func)
             {
@@ -1098,7 +1095,7 @@ bool checkNewEscape(Scope* sc, Expression e, bool gag)
         /* Check for returning a ref variable by 'ref', but should be 'return ref'
          * Infer the addition of 'return', or set result to be the offending expression.
          */
-        if (!(v.storage_class & (STC.ref_ | STC.out_)))
+        if (!v.isReference())
             continue;
 
         if (!sc._module || !sc._module.isRoot())
@@ -1285,11 +1282,18 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
 
     foreach (VarDeclaration v; er.byref)
     {
-        if (log) printf("byref `%s`\n", v.toChars());
+        if (log)
+        {
+            printf("byref `%s`\n", v.toChars());
+            if (v.storage_class & STC.return_) printf(" return");
+            if (v.storage_class & STC.ref_)    printf(" ref");
+            if (v.storage_class & STC.scope_)  printf(" scope");
+            printf("\n");
+        }
 
         // 'featureState' tells us whether to emit an error or a deprecation,
         // depending on the flag passed to the CLI for DIP25
-        void escapingRef(VarDeclaration v, FeatureState featureState = FeatureState.enabled)
+        void escapingRef(VarDeclaration v, ScopeRef vsr, FeatureState featureState = FeatureState.enabled)
         {
             if (!gag)
             {
@@ -1298,7 +1302,9 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                     (v.type.hasPointers() || v.storage_class & STC.ref_))
                 {
                     msg = "returning `%s` escapes a reference to parameter `%s`";
-                    supplemental = "perhaps annotate the parameter with `return`";
+                    supplemental = vsr == ScopeRef.Ref_ReturnScope
+                                              ? "perhaps remove `scope` parameter annotation so `return` applies to `ref`"
+                                              : "perhaps annotate the parameter with `return`";
                 }
                 else
                 {
@@ -1317,17 +1323,23 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
         if (v.isDataseg())
             continue;
 
+        auto stc = v.storage_class;
+        if (stc & STC.out_)
+            stc |= STC.ref_;  // temporary hack until we adjust buildScopeRef()
+
+        const vsr = buildScopeRef(refs, stc);
+
         Dsymbol p = v.toParent2();
 
         // https://issues.dlang.org/show_bug.cgi?id=19965
         if (!refs && sc.func.vthis == v)
             notMaybeScope(v);
 
-        if ((v.storage_class & (STC.ref_ | STC.out_)) == 0)
+        if (!v.isReference())
         {
             if (p == sc.func)
             {
-                escapingRef(v);
+                escapingRef(v, vsr, FeatureState.enabled);
                 continue;
             }
             FuncDeclaration fd = p.isFuncDeclaration();
@@ -1345,16 +1357,18 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                     sc.func.storage_class |= STC.return_ | STC.returninferred;
                 }
             }
-
         }
 
         /* Check for returning a ref variable by 'ref', but should be 'return ref'
          * Infer the addition of 'return', or set result to be the offending expression.
          */
-        if ( (v.storage_class & (STC.ref_ | STC.out_)) &&
-            !(v.storage_class & (STC.return_ | STC.foreach_)))
+        if ((vsr == ScopeRef.Ref ||
+             vsr == ScopeRef.RefScope ||
+             vsr == ScopeRef.Ref_ReturnScope) &&
+            !(v.storage_class & STC.foreach_))
         {
-            if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func)
+            if (sc.func.flags & FUNCFLAG.returnInprocess && p == sc.func &&
+                (vsr == ScopeRef.Ref || vsr == ScopeRef.RefScope))
             {
                 inferReturn(sc.func, v);        // infer addition of 'return'
             }
@@ -1366,14 +1380,14 @@ private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                 {
                     //printf("escaping reference to local ref variable %s\n", v.toChars());
                     //printf("storage class = x%llx\n", v.storage_class);
-                    escapingRef(v, global.params.useDIP25);
+                    escapingRef(v, vsr, global.params.useDIP25);
                     continue;
                 }
                 // Don't need to be concerned if v's parent does not return a ref
                 FuncDeclaration fd = p.isFuncDeclaration();
                 if (fd && fd.type && fd.type.ty == Tfunction)
                 {
-                    TypeFunction tf = cast(TypeFunction)fd.type;
+                    TypeFunction tf = fd.type.isTypeFunction();
                     if (tf.isref)
                     {
                         const(char)* msg = "escaping reference to outer local variable `%s`";
@@ -1414,13 +1428,12 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v)
     //printf("for function '%s' inferring 'return' for variable '%s'\n", fd.toChars(), v.toChars());
     v.storage_class |= STC.return_ | STC.returninferred;
 
-    TypeFunction tf = cast(TypeFunction)fd.type;
     if (v == fd.vthis)
     {
         /* v is the 'this' reference, so mark the function
          */
         fd.storage_class |= STC.return_ | STC.returninferred;
-        if (tf.ty == Tfunction)
+        if (auto tf = fd.type.isTypeFunction())
         {
             //printf("'this' too %p %s\n", tf, sc.func.toChars());
             tf.isreturn = true;
@@ -1430,7 +1443,7 @@ private void inferReturn(FuncDeclaration fd, VarDeclaration v)
     else
     {
         // Perform 'return' inference on parameter
-        if (tf.ty == Tfunction)
+        if (auto tf = fd.type.isTypeFunction())
         {
             foreach (i, p; tf.parameterList)
             {
@@ -1607,9 +1620,9 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
 
         override void visit(SliceExp e)
         {
-            if (e.e1.op == TOK.variable)
+            if (auto ve = e.e1.isVarExp())
             {
-                VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+                VarDeclaration v = ve.var.isVarDeclaration();
                 Type tb = e.type.toBasetype();
                 if (v)
                 {
@@ -1684,11 +1697,11 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
             TypeDelegate dg;
             if (t1.ty == Tdelegate)
             {
-                dg = cast(TypeDelegate)t1;
-                tf = cast(TypeFunction)(cast(TypeDelegate)t1).next;
+                dg = t1.isTypeDelegate();
+                tf = dg.next.isTypeFunction();
             }
             else if (t1.ty == Tfunction)
-                tf = cast(TypeFunction)t1;
+                tf = t1.isTypeFunction();
             else
                 return;
 
@@ -1731,7 +1744,7 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
             // If 'this' is returned, check it too
             if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
             {
-                DotVarExp dve = cast(DotVarExp)e.e1;
+                DotVarExp dve = e.e1.isDotVarExp();
                 FuncDeclaration fd = dve.var.isFuncDeclaration();
                 AggregateDeclaration ad;
                 if (global.params.useDIP1000 == FeatureState.enabled && tf.isreturn && fd && (ad = fd.isThis()) !is null)
@@ -1779,9 +1792,8 @@ void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
 
             /* If it's a nested function that is 'return scope'
              */
-            if (e.e1.op == TOK.variable)
+            if (auto ve = e.e1.isVarExp())
             {
-                VarExp ve = cast(VarExp)e.e1;
                 FuncDeclaration fd = ve.var.isFuncDeclaration();
                 if (fd && fd.isNested())
                 {
@@ -1875,9 +1887,9 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
         override void visit(IndexExp e)
         {
             Type tb = e.e1.type.toBasetype();
-            if (e.e1.op == TOK.variable)
+            if (auto ve = e.e1.isVarExp())
             {
-                VarDeclaration v = (cast(VarExp)e.e1).var.isVarDeclaration();
+                VarDeclaration v = ve.var.isVarDeclaration();
                 if (tb.ty == Tarray || tb.ty == Tsarray)
                 {
                     if (v && v.storage_class & STC.variadic)
@@ -1949,9 +1961,9 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
             Type t1 = e.e1.type.toBasetype();
             TypeFunction tf;
             if (t1.ty == Tdelegate)
-                tf = cast(TypeFunction)(cast(TypeDelegate)t1).next;
+                tf = t1.isTypeDelegate().next.isTypeFunction();
             else if (t1.ty == Tfunction)
-                tf = cast(TypeFunction)t1;
+                tf = t1.isTypeFunction();
             else
                 return;
             if (tf.isref)
@@ -1974,9 +1986,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                                 arg.accept(this);
                             else if ((stc & STC.scope_) && (stc & STC.return_))
                             {
-                                if (arg.op == TOK.delegate_)
+                                if (auto de = arg.isDelegateExp())
                                 {
-                                    DelegateExp de = cast(DelegateExp)arg;
                                     if (de.func.isNested())
                                         er.byexp.push(de);
                                 }
@@ -1989,7 +2000,7 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                 // If 'this' is returned by ref, check it too
                 if (e.e1.op == TOK.dotVariable && t1.ty == Tfunction)
                 {
-                    DotVarExp dve = cast(DotVarExp)e.e1;
+                    DotVarExp dve = e.e1.isDotVarExp();
 
                     // https://issues.dlang.org/show_bug.cgi?id=20149#c10
                     if (dve.var.isCtorDeclaration())
@@ -2021,9 +2032,8 @@ void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
 
                 /* If it's a nested function that is 'return ref'
                  */
-                if (e.e1.op == TOK.variable)
+                if (auto ve = e.e1.isVarExp())
                 {
-                    VarExp ve = cast(VarExp)e.e1;
                     FuncDeclaration fd = ve.var.isFuncDeclaration();
                     if (fd && fd.isNested())
                     {
@@ -2161,7 +2171,7 @@ public void eliminateMaybeScopes(VarDeclaration[] array)
                         {
                             // v cannot be scope since it is assigned to a non-scope va
                             notMaybeScope(v);
-                            if (!(v.storage_class & (STC.ref_ | STC.out_)))
+                            if (!v.isReference())
                                 v.storage_class &= ~(STC.return_ | STC.returninferred);
                             changes = true;
                         }
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 9545642af6e..51034867e5c 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -1546,57 +1546,7 @@ extern (C++) abstract class Expression : ASTNode
         return type ? Modifiable.yes : Modifiable.no; // default modifiable
     }
 
-    /*****************************
-     * If expression can be tested for true or false,
-     * returns the modified expression.
-     * Otherwise returns ErrorExp.
-     */
-    Expression toBoolean(Scope* sc)
-    {
-        // Default is 'yes' - do nothing
-        Expression e = this;
-        Type t = type;
-        Type tb = type.toBasetype();
-        Type att = null;
-
-        while (1)
-        {
-            // Structs can be converted to bool using opCast(bool)()
-            if (auto ts = tb.isTypeStruct())
-            {
-                AggregateDeclaration ad = ts.sym;
-                /* Don't really need to check for opCast first, but by doing so we
-                 * get better error messages if it isn't there.
-                 */
-                if (Dsymbol fd = search_function(ad, Id._cast))
-                {
-                    e = new CastExp(loc, e, Type.tbool);
-                    e = e.expressionSemantic(sc);
-                    return e;
-                }
-
-                // Forward to aliasthis.
-                if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
-                {
-                    e = resolveAliasThis(sc, e);
-                    t = e.type;
-                    tb = e.type.toBasetype();
-                    continue;
-                }
-            }
-            break;
-        }
-
-        if (!t.isBoolean())
-        {
-            if (tb != Type.terror)
-                error("expression `%s` of type `%s` does not have a boolean value", toChars(), t.toChars());
-            return ErrorExp.get();
-        }
-        return e;
-    }
-
-    /************************************************
+   /************************************************
      * Destructors are attached to VarDeclarations.
      * Hence, if expression returns a temp that needs a destructor,
      * make sure and create a VarDeclaration for that temp.
@@ -1666,7 +1616,7 @@ extern (C++) abstract class Expression : ASTNode
         return true;
     }
 
-    final pure inout nothrow @nogc
+    final pure inout nothrow @nogc @safe
     {
         inout(IntegerExp)   isIntegerExp() { return op == TOK.int64 ? cast(typeof(return))this : null; }
         inout(ErrorExp)     isErrorExp() { return op == TOK.error ? cast(typeof(return))this : null; }
@@ -3379,6 +3329,14 @@ extern (C++) final class StructLiteralExp : Expression
         return this;
     }
 
+    override Expression toLvalue(Scope* sc, Expression e)
+    {
+        if (sc.flags & SCOPE.Cfile)
+            return this;  // C struct literals are lvalues
+        else
+            return Expression.toLvalue(sc, e);
+    }
+
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3561,7 +3519,6 @@ extern (C++) final class NewExp : Expression
 
     Expression argprefix;       // expression to be evaluated just before arguments[]
     CtorDeclaration member;     // constructor function
-    NewDeclaration allocator;   // allocator function
     bool onstack;               // allocate on stack
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
@@ -4634,7 +4591,7 @@ extern (C++) class BinAssignExp : BinExp
         return toLvalue(sc, this);
     }
 
-    override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc
+    override inout(BinAssignExp) isBinAssignExp() pure inout nothrow @nogc @safe
     {
         return this;
     }
@@ -5373,12 +5330,6 @@ extern (C++) final class DeleteExp : UnaExp
         this.isRAII = isRAII;
     }
 
-    override Expression toBoolean(Scope* sc)
-    {
-        error("`delete` does not give a boolean result");
-        return ErrorExp.get();
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -5722,16 +5673,6 @@ extern (C++) final class CommaExp : BinExp
         return e2.isBool(result);
     }
 
-    override Expression toBoolean(Scope* sc)
-    {
-        auto ex2 = e2.toBoolean(sc);
-        if (ex2.op == TOK.error)
-            return ex2;
-        e2 = ex2;
-        type = e2.type;
-        return this;
-    }
-
     override Expression addDtorHook(Scope* sc)
     {
         e2 = e2.addDtorHook(sc);
@@ -6037,16 +5978,6 @@ extern (C++) class AssignExp : BinExp
         return this;
     }
 
-    override final Expression toBoolean(Scope* sc)
-    {
-        // Things like:
-        //  if (a = b) ...
-        // are usually mistakes.
-
-        error("assignment cannot be used as a condition, perhaps `==` was meant?");
-        return ErrorExp.get();
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -6071,7 +6002,7 @@ extern (C++) final class ConstructExp : AssignExp
 
         super(loc, TOK.construct, ve, e2);
 
-        if (v.storage_class & (STC.ref_ | STC.out_))
+        if (v.isReference())
             memset = MemorySet.referenceInit;
     }
 
@@ -6099,7 +6030,7 @@ extern (C++) final class BlitExp : AssignExp
 
         super(loc, TOK.blit, ve, e2);
 
-        if (v.storage_class & (STC.ref_ | STC.out_))
+        if (v.isReference())
             memset = MemorySet.referenceInit;
     }
 
@@ -6567,15 +6498,6 @@ extern (C++) final class LogicalExp : BinExp
         assert(op == TOK.andAnd || op == TOK.orOr);
     }
 
-    override Expression toBoolean(Scope* sc)
-    {
-        auto ex2 = e2.toBoolean(sc);
-        if (ex2.op == TOK.error)
-            return ex2;
-        e2 = ex2;
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -6731,19 +6653,6 @@ extern (C++) final class CondExp : BinExp
         return toLvalue(sc, this);
     }
 
-    override Expression toBoolean(Scope* sc)
-    {
-        auto ex1 = e1.toBoolean(sc);
-        auto ex2 = e2.toBoolean(sc);
-        if (ex1.op == TOK.error)
-            return ex1;
-        if (ex2.op == TOK.error)
-            return ex2;
-        e1 = ex1;
-        e2 = ex2;
-        return this;
-    }
-
     void hookDtors(Scope* sc)
     {
         extern (C++) final class DtorVisitor : StoppableVisitor
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 855c82bfacc..5e60917e804 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -27,7 +27,6 @@ class VarDeclaration;
 class FuncDeclaration;
 class FuncLiteralDeclaration;
 class CtorDeclaration;
-class NewDeclaration;
 class Dsymbol;
 class ScopeDsymbol;
 class Expression;
@@ -97,7 +96,6 @@ public:
     virtual bool checkValue();
     bool checkDeprecated(Scope *sc, Dsymbol *s);
     virtual int checkModifiable(Scope *sc, int flag = 0);
-    virtual Expression *toBoolean(Scope *sc);
     virtual Expression *addDtorHook(Scope *sc);
     Expression *addressOf();
     Expression *deref();
@@ -463,6 +461,7 @@ public:
     Expression *getField(Type *type, unsigned offset);
     int getFieldIndex(Type *type, unsigned offset);
     Expression *addDtorHook(Scope *sc);
+    Expression *toLvalue(Scope *sc, Expression *e);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -513,7 +512,6 @@ public:
     Expression *argprefix;      // expression to be evaluated just before arguments[]
 
     CtorDeclaration *member;    // constructor function
-    NewDeclaration *allocator;  // allocator function
     bool onstack;               // allocate on stack
     bool thrownew;              // this NewExp is the expression of a ThrowStatement
 
@@ -861,7 +859,6 @@ class DeleteExp : public UnaExp
 {
 public:
     bool isRAII;
-    Expression *toBoolean(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -988,7 +985,6 @@ public:
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
     bool isBool(bool result);
-    Expression *toBoolean(Scope *sc);
     Expression *addDtorHook(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -1039,7 +1035,6 @@ public:
 
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *ex);
-    Expression *toBoolean(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -1215,7 +1210,6 @@ public:
 class LogicalExp : public BinExp
 {
 public:
-    Expression *toBoolean(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -1265,7 +1259,6 @@ public:
     bool isLvalue();
     Expression *toLvalue(Scope *sc, Expression *e);
     Expression *modifiableLvalue(Scope *sc, Expression *e);
-    Expression *toBoolean(Scope *sc);
     void hookDtors(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 36e657a62af..5069e8f51a0 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -190,9 +190,8 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
          *      (ref __dop = e1, __dop).opSlice( ... __dop.opDollar ...)
          */
         e1 = extractSideEffect(sc, "__dop", e0, e1, false);
-        assert(e1.op == TOK.variable);
-        VarExp ve = cast(VarExp)e1;
-        ve.var.storage_class |= STC.exptemp;     // lifetime limited to expression
+        assert(e1.isVarExp());
+        e1.isVarExp().var.storage_class |= STC.exptemp;     // lifetime limited to expression
     }
     ue.e1 = e1;
     return e0;
@@ -243,10 +242,8 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
         }
         sc = sc.pop();
 
-        if (e.op == TOK.interval)
+        if (auto ie = e.isIntervalExp())
         {
-            IntervalExp ie = cast(IntervalExp)e;
-
             auto tiargs = new Objects();
             Expression edim = new IntegerExp(ae.loc, i, Type.tsize_t);
             edim = edim.expressionSemantic(sc);
@@ -372,7 +369,7 @@ private bool checkPropertyCall(Expression e)
             if (!tf.deco && ce.f.semanticRun < PASS.semanticdone)
             {
                 ce.f.dsymbolSemantic(null);
-                tf = cast(TypeFunction)ce.f.type;
+                tf = ce.f.type.isTypeFunction();
             }
         }
         else if (!ce.e1.type.isFunction_Delegate_PtrToFunction())
@@ -454,9 +451,8 @@ private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
         }
     }
 
-    if (ue.op == TOK.dotTemplateInstance)
+    if (auto dti = ue.isDotTemplateInstanceExp())
     {
-        DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ue;
         auto ti = new TemplateInstance(loc, s.ident, dti.ti.tiargs);
         if (!ti.updateTempDecl(sc, s))
             return ErrorExp.get();
@@ -478,9 +474,8 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
     Expression eleft;
     Expression e;
 
-    if (ce.e1.op == TOK.dotIdentifier)
+    if (auto die = ce.e1.isDotIdExp())
     {
-        DotIdExp die = cast(DotIdExp)ce.e1;
         Identifier ident = die.ident;
 
         Expression ex = die.semanticX(sc);
@@ -519,7 +514,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
                 key = key.expressionSemantic(sc);
                 key = resolveProperties(sc, key);
 
-                TypeAArray taa = cast(TypeAArray)t;
+                TypeAArray taa = t.isTypeAArray();
                 key = key.implicitCastTo(sc, taa.index);
 
                 if (key.checkValue() || key.checkSharedAccess(sc))
@@ -592,7 +587,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
                     die.e1 = alias_e;
                     CallExp ce2 = ce.syntaxCopy();
                     ce2.e1 = die;
-                    e = cast(CallExp)ce2.trySemantic(sc);
+                    e = ce2.isCallExp().trySemantic(sc);
                     if (e)
                         return e;
                 }
@@ -601,9 +596,8 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
             searchUFCS(sc, die, ident);
         }
     }
-    else if (ce.e1.op == TOK.dotTemplateInstance)
+    else if (auto dti = ce.e1.isDotTemplateInstanceExp())
     {
-        DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)ce.e1;
         if (Expression ey = dti.semanticY(sc, 1))
         {
             ce.e1 = ey;
@@ -633,16 +627,13 @@ private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
     Expression eleft;
     Expression e;
 
-    if (e1.op == TOK.dotIdentifier)
+    if (auto die = e1.isDotIdExp())
     {
-        DotIdExp die = cast(DotIdExp)e1;
         eleft = die.e1;
         e = searchUFCS(sc, die, die.ident);
     }
-    else if (e1.op == TOK.dotTemplateInstance)
+    else if (auto dti = e1.isDotTemplateInstanceExp())
     {
-        DotTemplateInstanceExp dti;
-        dti = cast(DotTemplateInstanceExp)e1;
         eleft = dti.e1;
         e = searchUFCS(sc, dti, dti.ti.name);
     }
@@ -728,12 +719,12 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
             auto td = s.isTemplateDeclaration();
             if (fd)
             {
-                if ((cast(TypeFunction)fd.type).isproperty)
+                if (fd.type.isTypeFunction().isproperty)
                     return resolveProperties(sc, e1);
             }
             else if (td && td.onemember && (fd = td.onemember.isFuncDeclaration()) !is null)
             {
-                if ((cast(TypeFunction)fd.type).isproperty ||
+                if (fd.type.isTypeFunction().isproperty ||
                     (fd.storage_class2 & STC.property) ||
                     (td._scope.stc & STC.property))
                     return resolveProperties(sc, e1);
@@ -749,7 +740,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
         {
             if (auto fd = td.onemember.isFuncDeclaration())
             {
-                if ((cast(TypeFunction)fd.type).isproperty ||
+                if (fd.type.isTypeFunction().isproperty ||
                     (fd.storage_class2 & STC.property) ||
                     (td._scope.stc & STC.property))
                     return resolveProperties(sc, e1);
@@ -761,7 +752,7 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
     Expression handleFuncDecl(FuncDeclaration fd)
     {
         assert(fd);
-        if ((cast(TypeFunction)fd.type).isproperty)
+        if (fd.type.isTypeFunction().isproperty)
             return resolveProperties(sc, e1);
         return e1;
     }
@@ -781,23 +772,23 @@ Expression resolvePropertiesOnly(Scope* sc, Expression e1)
     }
     else if (auto dte = e1.isDotTemplateExp())
         return handleTemplateDecl(dte.td);
-    else if (e1.op == TOK.scope_)
+    else if (auto se = e1.isScopeExp())
     {
-        Dsymbol s = (cast(ScopeExp)e1).sds;
+        Dsymbol s = se.sds;
         TemplateInstance ti = s.isTemplateInstance();
         if (ti && !ti.semanticRun && ti.tempdecl)
             if (auto td = ti.tempdecl.isTemplateDeclaration())
                 return handleTemplateDecl(td);
     }
-    else if (e1.op == TOK.template_)
-        return handleTemplateDecl((cast(TemplateExp)e1).td);
-    else if (e1.op == TOK.dotVariable && e1.type.ty == Tfunction)
+    else if (auto et = e1.isTemplateExp())
+        return handleTemplateDecl(et.td);
+    else if (e1.isDotVarExp() && e1.type.isTypeFunction())
     {
-        DotVarExp dve = cast(DotVarExp)e1;
+        DotVarExp dve = e1.isDotVarExp();
         return handleFuncDecl(dve.var.isFuncDeclaration());
     }
-    else if (e1.op == TOK.variable && e1.type && e1.type.ty == Tfunction && (sc.intypeof || !(cast(VarExp)e1).var.needThis()))
-        return handleFuncDecl((cast(VarExp)e1).var.isFuncDeclaration());
+    else if (e1.isVarExp() && e1.type && e1.type.isTypeFunction() && (sc.intypeof || !e1.isVarExp().var.needThis()))
+        return handleFuncDecl(e1.isVarExp().var.isFuncDeclaration());
     return e1;
 }
 
@@ -1040,7 +1031,7 @@ L1:
              var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
              var.isFuncDeclaration.objc.selector)
     {
-        return new ObjcClassReferenceExp(e1.loc, cast(ClassDeclaration) ad);
+        return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
     }
 
     /* Access of a member which is a template parameter in dual-scope scenario
@@ -1068,8 +1059,8 @@ L1:
     /* If e1 is not the 'this' pointer for ad
      */
     if (ad &&
-        !(t.ty == Tpointer && t.nextOf().ty == Tstruct && (cast(TypeStruct)t.nextOf()).sym == ad) &&
-        !(t.ty == Tstruct && (cast(TypeStruct)t).sym == ad))
+        !(t.isTypePointer() && t.nextOf().isTypeStruct() && t.nextOf().isTypeStruct().sym == ad) &&
+        !(t.isTypeStruct() && t.isTypeStruct().sym == ad))
     {
         ClassDeclaration cd = ad.isClassDeclaration();
         ClassDeclaration tcd = t.isClassHandle();
@@ -1124,22 +1115,21 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
     Dsymbol s;
     Objects* tiargs;
     Type tthis;
-    if (e1.op == TOK.dot)
+    if (auto de = e1.isDotExp())
     {
-        DotExp de = cast(DotExp)e1;
-        if (de.e2.op == TOK.overloadSet)
+        if (auto oe = de.e2.isOverExp())
         {
             tiargs = null;
             tthis = de.e1.type;
-            os = (cast(OverExp)de.e2).vars;
+            os = oe.vars;
             goto Los;
         }
     }
-    else if (e1.op == TOK.overloadSet)
+    else if (e1.isOverExp())
     {
         tiargs = null;
         tthis = null;
-        os = (cast(OverExp)e1).vars;
+        os = e1.isOverExp().vars;
     Los:
         assert(os);
         FuncDeclaration fd = null;
@@ -1178,7 +1168,7 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                         return ErrorExp.get();
                     fd = f;
                     assert(fd.type.ty == Tfunction);
-                    TypeFunction tf = cast(TypeFunction)fd.type;
+                    auto tf = fd.type.isTypeFunction();
                     if (!tf.isref && e2)
                     {
                         error(loc, "%s is not an lvalue", e1.toChars());
@@ -1197,9 +1187,8 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if (e2)
             goto Leprop;
     }
-    else if (e1.op == TOK.dotTemplateInstance)
+    else if (auto dti = e1.isDotTemplateInstanceExp())
     {
-        DotTemplateInstanceExp dti = cast(DotTemplateInstanceExp)e1;
         if (!dti.findTempDecl(sc))
             goto Leprop;
         if (!dti.ti.semanticTiargs(sc))
@@ -1211,17 +1200,16 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         if ((s = dti.ti.tempdecl) !is null)
             goto Lfd;
     }
-    else if (e1.op == TOK.dotTemplateDeclaration)
+    else if (auto dte = e1.isDotTemplateExp())
     {
-        DotTemplateExp dte = cast(DotTemplateExp)e1;
         s = dte.td;
         tiargs = null;
         tthis = dte.e1.type;
         goto Lfd;
     }
-    else if (e1.op == TOK.scope_)
+    else if (auto se = e1.isScopeExp())
     {
-        s = (cast(ScopeExp)e1).sds;
+        s = se.sds;
         TemplateInstance ti = s.isTemplateInstance();
         if (ti && !ti.semanticRun && ti.tempdecl)
         {
@@ -1236,9 +1224,9 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                 goto Lfd;
         }
     }
-    else if (e1.op == TOK.template_)
+    else if (auto te = e1.isTemplateExp())
     {
-        s = (cast(TemplateExp)e1).td;
+        s = te.td;
         tiargs = null;
         tthis = null;
         goto Lfd;
@@ -1872,8 +1860,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
         L1:
             if (!(p.storageClass & STC.lazy_ && p.type.ty == Tvoid))
             {
-                const isRef = (p.storageClass & (STC.ref_ | STC.out_)) != 0;
-                if (ubyte wm = arg.type.deduceWild(p.type, isRef))
+                if (ubyte wm = arg.type.deduceWild(p.type, p.isReference()))
                 {
                     wildmatch = wildmatch ? MODmerge(wildmatch, wm) : wm;
                     //printf("[%d] p = %s, a = %s, wm = %d, wildmatch = %d\n", i, p.type.toChars(), arg.type.toChars(), wm, wildmatch);
@@ -3684,28 +3671,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
 
-            if (cd.aggNew)
+            if (cd.disableNew)
             {
-                // Prepend the size argument to newargs[]
-                Expression e = new IntegerExp(exp.loc, cd.size(exp.loc), Type.tsize_t);
-                if (!exp.newargs)
-                    exp.newargs = new Expressions();
-                exp.newargs.shift(e);
-
-                FuncDeclaration f = resolveFuncCall(exp.loc, sc, cd.aggNew, null, tb, exp.newargs, FuncResolveFlag.standard);
-                if (!f || f.errors)
-                    return setError();
-
-                checkFunctionAttributes(exp, sc, f);
-                checkAccess(cd, exp.loc, sc, f);
-
-                TypeFunction tf = cast(TypeFunction)f.type;
-                Type rettype;
-                if (functionParameters(exp.loc, sc, tf, null, null, exp.newargs, f, &rettype, &newprefix))
-                    return setError();
-
-                exp.allocator = f.isNewDeclaration();
-                assert(exp.allocator);
+                exp.error("cannot allocate `class %s` with `new` because it is annotated with `@disable new()`",
+                          originalNewtype.toChars());
+                return setError();
             }
             else
             {
@@ -3774,28 +3744,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             // checkDeprecated() is already done in newtype.typeSemantic().
 
-            if (sd.aggNew)
+            if (sd.disableNew)
             {
-                // Prepend the uint size argument to newargs[]
-                Expression e = new IntegerExp(exp.loc, sd.size(exp.loc), Type.tsize_t);
-                if (!exp.newargs)
-                    exp.newargs = new Expressions();
-                exp.newargs.shift(e);
-
-                FuncDeclaration f = resolveFuncCall(exp.loc, sc, sd.aggNew, null, tb, exp.newargs, FuncResolveFlag.standard);
-                if (!f || f.errors)
-                    return setError();
-
-                checkFunctionAttributes(exp, sc, f);
-                checkAccess(sd, exp.loc, sc, f);
-
-                TypeFunction tf = cast(TypeFunction)f.type;
-                Type rettype;
-                if (functionParameters(exp.loc, sc, tf, null, null, exp.newargs, f, &rettype, &newprefix))
-                    return setError();
-
-                exp.allocator = f.isNewDeclaration();
-                assert(exp.allocator);
+                exp.error("cannot allocate `struct %s` with `new` because it is annotated with `@disable new()`",
+                          originalNewtype.toChars());
+                return setError();
             }
             else
             {
@@ -4464,6 +4417,40 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 // Rewrite (*fp)(arguments) to fp(arguments)
                 exp.e1 = (cast(PtrExp)exp.e1).e1;
             }
+            else if (exp.e1.op == TOK.type && (sc && sc.flags & SCOPE.Cfile))
+            {
+                /* Ambiguous cases arise from CParser where there is not enough
+                 * information to determine if we have a function call or declaration.
+                 *   type-name ( identifier ) ;
+                 *   identifier ( identifier ) ;
+                 * If exp.e1 is a type-name, then this is a declaration. C11 does not
+                 * have type construction syntax, so don't convert this to a cast().
+                 */
+                if (exp.arguments && exp.arguments.dim == 1)
+                {
+                    Expression arg = (*exp.arguments)[0];
+                    if (auto ie = (*exp.arguments)[0].isIdentifierExp())
+                    {
+                        TypeExp te = cast(TypeExp)exp.e1;
+                        auto initializer = new VoidInitializer(ie.loc);
+                        Dsymbol s = new VarDeclaration(ie.loc, te.type, ie.ident, initializer);
+                        auto decls = new Dsymbols(1);
+                        (*decls)[0] = s;
+                        s = new LinkDeclaration(s.loc, LINK.c, decls);
+                        result = new DeclarationExp(exp.loc, s);
+                        result = result.expressionSemantic(sc);
+                    }
+                    else
+                    {
+                        arg.error("identifier or `(` expected");
+                        result = ErrorExp.get();
+                    }
+                    return;
+                }
+                exp.error("identifier or `(` expected before `)`");
+                result = ErrorExp.get();
+                return;
+            }
         }
 
         Type t1 = exp.e1.type ? exp.e1.type.toBasetype() : null;
@@ -6700,6 +6687,25 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
+        if (sc.flags & SCOPE.Cfile)
+        {
+            /* Special handling for &"string"
+             * since C regards a string literal as an lvalue
+             */
+            if (auto se = exp.e1.isStringExp())
+            {
+                if (auto tp = se.type.toBasetype().isTypePointer())
+                {
+                    /* Switch from pointer-to-char to pointer-to-static-array-of-char
+                     */
+                    auto ts = new TypeSArray(tp.nextOf(), new IntegerExp(Loc.initial, se.len + 1, Type.tsize_t));
+                    se.type = typeSemantic(ts, Loc.initial, sc).pointerTo();
+                    result = se;
+                    return;
+                }
+            }
+        }
+
         int wasCond = exp.e1.op == TOK.question;
 
         if (exp.e1.op == TOK.dotTemplateInstance)
@@ -7297,6 +7303,39 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
+        if ((sc && sc.flags & SCOPE.Cfile) &&
+            exp.to && exp.to.ty == Tident &&
+            (exp.e1.op == TOK.address || exp.e1.op == TOK.star ||
+             exp.e1.op == TOK.uadd || exp.e1.op == TOK.negate))
+        {
+            /* Ambiguous cases arise from CParser if type-name is just an identifier.
+             *   ( identifier ) 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.
+             */
+            Loc loc = exp.loc;
+            Type t;
+            Expression e;
+            Dsymbol s;
+            exp.to.resolve(loc, sc, e, t, s);
+            if (e !is null)
+            {
+                if (auto ex = exp.e1.isAddrExp())       // (ident) &exp -> (ident & exp)
+                    result = new AndExp(loc, e, ex.e1);
+                else if (auto ex = exp.e1.isPtrExp())   // (ident) *exp -> (ident * exp)
+                    result = new MulExp(loc, e, ex.e1);
+                else if (auto ex = exp.e1.isUAddExp())  // (ident) +exp -> (ident + exp)
+                    result = new AddExp(loc, e, ex.e1);
+                else if (auto ex = exp.e1.isNegExp())   // (ident) -exp -> (ident - exp)
+                    result = new MinExp(loc, e, ex.e1);
+
+                assert(result);
+                result = result.expressionSemantic(sc);
+                return;
+            }
+        }
+
         if (exp.to)
         {
             exp.to = exp.to.typeSemantic(exp.loc, sc);
@@ -8770,15 +8809,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp = new ConstructExp(exp.loc, exp.e1, exp.e2);
             exp.type = t;
 
-            // @@@DEPRECATED_2020-06@@@
-            // When removing, alter `checkModifiable` to return the correct value.
-            if (sc.func.isStaticCtorDeclaration() && !sc.func.isSharedStaticCtorDeclaration() &&
-                exp.e1.type.isImmutable())
-            {
-                deprecation(exp.loc, "initialization of `immutable` variable from `static this` is deprecated.");
-                deprecationSupplemental(exp.loc, "Use `shared static this` instead.");
-            }
-
             // https://issues.dlang.org/show_bug.cgi?id=13515
             // set Index::modifiable flag for complex AA element initialization
             if (auto ie1 = exp.e1.isIndexExp())
@@ -12658,3 +12688,246 @@ bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string desc
     error(loc, "`%s.%s` not found. The current runtime does not support %.*s, or the runtime is corrupt.", module_.toChars(), id.toChars(), cast(int)description.length, description.ptr);
     return false;
 }
+
+/***************************************
+ * Fit elements[] to the corresponding types of the `sd`'s fields.
+ *
+ * Params:
+ *      sd = the struct declaration
+ *      loc = location to use for error messages
+ *      sc = context
+ *      elements = explicit arguments used to construct object
+ *      stype = the constructed object type.
+ * Returns:
+ *      false if any errors occur,
+ *      otherwise true and elements[] are rewritten for the output.
+ */
+private bool fit(StructDeclaration sd, const ref Loc loc, Scope* sc, Expressions* elements, Type stype)
+{
+    if (!elements)
+        return true;
+
+    const nfields = sd.nonHiddenFields();
+    size_t offset = 0;
+    for (size_t i = 0; i < elements.dim; i++)
+    {
+        Expression e = (*elements)[i];
+        if (!e)
+            continue;
+
+        e = resolveProperties(sc, e);
+        if (i >= nfields)
+        {
+            if (i <= sd.fields.dim && e.op == TOK.null_)
+            {
+                // CTFE sometimes creates null as hidden pointer; we'll allow this.
+                continue;
+            }
+                .error(loc, "more initializers than fields (%zu) of `%s`", nfields, sd.toChars());
+            return false;
+        }
+        VarDeclaration v = sd.fields[i];
+        if (v.offset < offset)
+        {
+            .error(loc, "overlapping initialization for `%s`", v.toChars());
+            if (!sd.isUnionDeclaration())
+            {
+                enum errorMsg = "`struct` initializers that contain anonymous unions" ~
+                    " must initialize only the first member of a `union`. All subsequent" ~
+                    " non-overlapping fields are default initialized";
+                .errorSupplemental(loc, errorMsg);
+            }
+            return false;
+        }
+        offset = cast(uint)(v.offset + v.type.size());
+
+        Type t = v.type;
+        if (stype)
+            t = t.addMod(stype.mod);
+        Type origType = t;
+        Type tb = t.toBasetype();
+
+        const hasPointers = tb.hasPointers();
+        if (hasPointers)
+        {
+            if ((stype.alignment() < target.ptrsize ||
+                 (v.offset & (target.ptrsize - 1))) &&
+                (sc.func && sc.func.setUnsafe()))
+            {
+                .error(loc, "field `%s.%s` cannot assign to misaligned pointers in `@safe` code",
+                       sd.toChars(), v.toChars());
+                return false;
+            }
+        }
+
+        /* Look for case of initializing a static array with a too-short
+         * string literal, such as:
+         *  char[5] foo = "abc";
+         * Allow this by doing an explicit cast, which will lengthen the string
+         * literal.
+         */
+        if (e.op == TOK.string_ && tb.ty == Tsarray)
+        {
+            StringExp se = cast(StringExp)e;
+            Type typeb = se.type.toBasetype();
+            TY tynto = tb.nextOf().ty;
+            if (!se.committed &&
+                (typeb.ty == Tarray || typeb.ty == Tsarray) && tynto.isSomeChar &&
+                se.numberOfCodeUnits(tynto) < (cast(TypeSArray)tb).dim.toInteger())
+            {
+                e = se.castTo(sc, t);
+                goto L1;
+            }
+        }
+
+        while (!e.implicitConvTo(t) && tb.ty == Tsarray)
+        {
+            /* Static array initialization, as in:
+             *  T[3][5] = e;
+             */
+            t = tb.nextOf();
+            tb = t.toBasetype();
+        }
+        if (!e.implicitConvTo(t))
+            t = origType; // restore type for better diagnostic
+
+        e = e.implicitCastTo(sc, t);
+    L1:
+        if (e.op == TOK.error)
+            return false;
+
+        (*elements)[i] = doCopyOrMove(sc, e);
+    }
+    return true;
+}
+
+
+/**
+ * Returns `em` as a VariableExp
+ * Params:
+ *     em = the EnumMember to wrap
+ *     loc = location of use of em
+ *     sc = scope of use of em
+ * Returns:
+ *     VarExp referenceing `em` or ErrorExp if `em` if disabled/deprecated
+ */
+Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
+{
+    dsymbolSemantic(em, sc);
+    if (em.errors)
+        return ErrorExp.get();
+    em.checkDisabled(loc, sc);
+
+    if (em.depdecl && !em.depdecl._scope)
+        em.depdecl._scope = sc;
+    em.checkDeprecated(loc, sc);
+
+    if (em.errors)
+        return ErrorExp.get();
+    Expression e = new VarExp(loc, em);
+    return e.expressionSemantic(sc);
+}
+
+
+/*****************************
+ * Try to treat `exp` as a boolean,
+ * Params:
+ *     exp = the expression
+ *     sc = scope to evalute `exp` in
+ * Returns:
+ *     Modified expression on success, ErrorExp on error
+ */
+Expression toBoolean(Expression exp, Scope* sc)
+{
+    switch(exp.op)
+    {
+        case TOK.delete_:
+            exp.error("`delete` does not give a boolean result");
+            return ErrorExp.get();
+
+        case TOK.comma:
+            auto ce = exp.isCommaExp();
+            auto ex2 = ce.e2.toBoolean(sc);
+            if (ex2.op == TOK.error)
+                return ex2;
+            ce.e2 = ex2;
+            ce.type = ce.e2.type;
+            return ce;
+
+        case TOK.assign:
+        case TOK.construct:
+        case TOK.blit:
+            // Things like:
+            //  if (a = b) ...
+            // are usually mistakes.
+            exp.error("assignment cannot be used as a condition, perhaps `==` was meant?");
+            return ErrorExp.get();
+
+        //LogicalExp
+        case TOK.andAnd:
+        case TOK.orOr:
+            auto le = exp.isLogicalExp();
+            auto ex2 = le.e2.toBoolean(sc);
+            if (ex2.op == TOK.error)
+                return ex2;
+            le.e2 = ex2;
+            return le;
+
+        case TOK.question:
+            auto ce = exp.isCondExp();
+            auto ex1 = ce.e1.toBoolean(sc);
+            auto ex2 = ce.e2.toBoolean(sc);
+            if (ex1.op == TOK.error)
+                return ex1;
+            if (ex2.op == TOK.error)
+                return ex2;
+            ce.e1 = ex1;
+            ce.e2 = ex2;
+            return ce;
+
+
+        default:
+            // Default is 'yes' - do nothing
+            Expression e = exp;
+            Type t = exp.type;
+            Type tb = t.toBasetype();
+            Type att = null;
+
+            while (1)
+            {
+                // Structs can be converted to bool using opCast(bool)()
+                if (auto ts = tb.isTypeStruct())
+                {
+                    AggregateDeclaration ad = ts.sym;
+                    /* Don't really need to check for opCast first, but by doing so we
+                     * get better error messages if it isn't there.
+                     */
+                    if (Dsymbol fd = search_function(ad, Id._cast))
+                    {
+                        e = new CastExp(exp.loc, e, Type.tbool);
+                        e = e.expressionSemantic(sc);
+                        return e;
+                    }
+
+                    // Forward to aliasthis.
+                    if (ad.aliasthis && !isRecursiveAliasThis(att, tb))
+                    {
+                        e = resolveAliasThis(sc, e);
+                        t = e.type;
+                        tb = e.type.toBasetype();
+                        continue;
+                    }
+                }
+                break;
+            }
+
+            if (!t.isBoolean())
+            {
+                if (tb != Type.terror)
+                    exp.error("expression `%s` of type `%s` does not have a boolean value",
+                              exp.toChars(), t.toChars());
+                return ErrorExp.get();
+            }
+            return e;
+    }
+}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index eff9bc63da4..b73bf62d455 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -3760,32 +3760,32 @@ extern (C++) class StaticCtorDeclaration : FuncDeclaration
         return scd;
     }
 
-    override final inout(AggregateDeclaration) isThis() inout
+    override final inout(AggregateDeclaration) isThis() inout @nogc nothrow pure @safe
     {
         return null;
     }
 
-    override final bool isVirtual() const
+    override final bool isVirtual() const @nogc nothrow pure @safe
     {
         return false;
     }
 
-    override final bool addPreInvariant()
+    override final bool addPreInvariant() @nogc nothrow pure @safe
     {
         return false;
     }
 
-    override final bool addPostInvariant()
+    override final bool addPostInvariant() @nogc nothrow pure @safe
     {
         return false;
     }
 
-    override final bool hasStaticCtorOrDtor()
+    override final bool hasStaticCtorOrDtor() @nogc nothrow pure @safe
     {
         return true;
     }
 
-    override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout
+    override final inout(StaticCtorDeclaration) isStaticCtorDeclaration() inout @nogc nothrow pure @safe
     {
         return this;
     }
@@ -4015,19 +4015,15 @@ extern (C++) final class UnitTestDeclaration : FuncDeclaration
  */
 extern (C++) final class NewDeclaration : FuncDeclaration
 {
-    ParameterList parameterList;
-
-    extern (D) this(const ref Loc loc, const ref Loc endloc, StorageClass stc, ref ParameterList parameterList)
+    extern (D) this(const ref Loc loc, StorageClass stc)
     {
-        super(loc, endloc, Id.classNew, STC.static_ | stc, null);
-        this.parameterList = parameterList;
+        super(loc, Loc.initial, Id.classNew, STC.static_ | stc, null);
     }
 
     override NewDeclaration syntaxCopy(Dsymbol s)
     {
         assert(!s);
-        auto parameterList = parameterList.syntaxCopy();
-        auto f = new NewDeclaration(loc, endloc, storage_class, parameterList);
+        auto f = new NewDeclaration(loc, storage_class);
         FuncDeclaration.syntaxCopy(f);
         return f;
     }
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 2a355581af6..9b65d024b97 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -275,6 +275,7 @@ enum hdr_ext  = "di";       // for D 'header' import files
 enum json_ext = "json";     // for JSON files
 enum map_ext  = "map";      // for .map files
 enum c_ext    = "c";        // for C source files
+enum i_ext    = "i";        // for preprocessed C source file
 
 /**
  * Collection of global compiler settings and global state used by the frontend
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index 2b733063244..debb9ca62d4 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -32,21 +32,6 @@ version (NoBackend)
 
     extern (C++)
     {
-        version (NoMain) {} else
-        {
-            import dmd.lib : Library;
-
-            // glue
-            void obj_write_deferred(Library library)        {}
-            void obj_start(const(char)* srcfile)            {}
-            void obj_end(Library library, const(char)* objfilename) {}
-            void genObjFile(Module m, bool multiobj)        {}
-
-            // msc
-            void backend_init() {}
-            void backend_term() {}
-        }
-
         // iasm
         Statement asmSemantic(AsmStatement s, Scope* sc)
         {
@@ -65,8 +50,6 @@ version (NoBackend)
 }
 else version (MARS)
 {
-    import dmd.lib : Library;
-
     public import dmd.backend.cc : block, Blockx, Symbol;
     public import dmd.backend.type : type;
     public import dmd.backend.el : elem;
@@ -74,14 +57,6 @@ else version (MARS)
 
     extern (C++)
     {
-        void obj_write_deferred(Library library);
-        void obj_start(const(char)* srcfile);
-        void obj_end(Library library, const(char)* objfilename);
-        void genObjFile(Module m, bool multiobj);
-
-        void backend_init();
-        void backend_term();
-
         Statement asmSemantic(AsmStatement s, Scope* sc);
 
         void toObjFile(Dsymbol ds, bool multiobj);
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 685acae8dc0..e870612ba7d 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -1765,9 +1765,7 @@ public:
     {
         if (stcToBuffer(buf, d.storage_class & ~STC.static_))
             buf.writeByte(' ');
-        buf.writestring("new");
-        parametersToBuffer(d.parameterList, buf, hgs);
-        bodyToBuffer(d);
+        buf.writestring("new();");
     }
 
     override void visit(Module m)
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index 2ba9a005a86..e61fb23eb5d 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -240,13 +240,13 @@ Lerror:
  *      |     GotoAsmInstruction
  *      |
  *      | BasicAsmInstruction:
- *      |     Expression
+ *      |     AssignExpression
  *      |
  *      | ExtAsmInstruction:
- *      |     Expression : Operands(opt) : Operands(opt) : Clobbers(opt)
+ *      |     AssignExpression : Operands(opt) : Operands(opt) : Clobbers(opt)
  *      |
  *      | GotoAsmInstruction:
- *      |     Expression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
+ *      |     AssignExpression : : Operands(opt) : Clobbers(opt) : GotoLabels(opt)
  * Params:
  *      p = parser state
  *      s = asm statement to parse
@@ -255,7 +255,7 @@ Lerror:
  */
 GccAsmStatement parseGccAsm(Parser)(Parser p, GccAsmStatement s)
 {
-    s.insn = p.parseExpression();
+    s.insn = p.parseAssignExp();
     if (p.token.value == TOK.semicolon || p.token.value == TOK.endOfFile)
         goto Ldone;
 
@@ -523,6 +523,10 @@ unittest
                :
                : "g" (a ? b : : c);
         } },
+
+        // Found ',' when expecting ':'
+        q{ asm { "", "";
+        } },
     ];
 
     foreach (test; passAsmTests)
diff --git a/gcc/d/dmd/identifier.h b/gcc/d/dmd/identifier.h
index 986f479f497..790d5a036d4 100644
--- a/gcc/d/dmd/identifier.h
+++ b/gcc/d/dmd/identifier.h
@@ -11,7 +11,7 @@
 #pragma once
 
 #include "root/dcompat.h"
-#include "root/root.h"
+#include "root/object.h"
 
 class Identifier : public RootObject
 {
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index 1df109af99f..45e101b903a 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -64,33 +64,33 @@ extern (C++) class Initializer : ASTNode
         return buf.extractChars();
     }
 
-    final inout(ErrorInitializer) isErrorInitializer() inout pure
+    final inout(ErrorInitializer) isErrorInitializer() inout @nogc nothrow pure
     {
         // Use void* cast to skip dynamic casting call
         return kind == InitKind.error ? cast(inout ErrorInitializer)cast(void*)this : null;
     }
 
-    final inout(VoidInitializer) isVoidInitializer() inout pure
+    final inout(VoidInitializer) isVoidInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
     }
 
-    final inout(StructInitializer) isStructInitializer() inout pure
+    final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
     }
 
-    final inout(ArrayInitializer) isArrayInitializer() inout pure
+    final inout(ArrayInitializer) isArrayInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.array ? cast(inout ArrayInitializer)cast(void*)this : null;
     }
 
-    final inout(ExpInitializer) isExpInitializer() inout pure
+    final inout(ExpInitializer) isExpInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.exp ? cast(inout ExpInitializer)cast(void*)this : null;
     }
 
-    final inout(CInitializer) isCInitializer() inout pure
+    final inout(CInitializer) isCInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.C_ ? cast(inout CInitializer)cast(void*)this : null;
     }
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 1554fc722a1..c7f4be1bb25 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -2593,7 +2593,7 @@ extern (C++) abstract class Type : ASTNode
         }
     }
 
-    final pure inout nothrow @nogc
+    final pure inout nothrow @nogc @safe
     {
         inout(TypeError)      isTypeError()      { return ty == Terror     ? cast(typeof(return))this : null; }
         inout(TypeVector)     isTypeVector()     { return ty == Tvector    ? cast(typeof(return))this : null; }
@@ -7025,53 +7025,16 @@ extern (C++) final class Parameter : ASTNode
         if (from == to)
             return true;
 
-        /* Shrinking the representation is necessary because StorageClass is so wide
-         * Params:
-         *   returnByRef = true if the function returns by ref
-         *   stc = storage class of parameter
-         */
-        static uint buildSR(bool returnByRef, StorageClass stc) pure nothrow @nogc @safe
-        {
-            uint result;
-            final switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
-            {
-                case 0:                    result = SR.None;        break;
-                case STC.ref_:               result = SR.Ref;         break;
-                case STC.scope_:             result = SR.Scope;       break;
-                case STC.return_ | STC.ref_:   result = SR.ReturnRef;   break;
-                case STC.return_ | STC.scope_: result = SR.ReturnScope; break;
-                case STC.ref_    | STC.scope_: result = SR.RefScope;    break;
-                case STC.return_ | STC.ref_ | STC.scope_:
-                    result = returnByRef ? SR.ReturnRef_Scope : SR.Ref_ReturnScope;
-                    break;
-            }
-            return result;
-        }
-
         /* result is true if the 'from' can be used as a 'to'
          */
 
         if ((from ^ to) & STC.ref_)               // differing in 'ref' means no covariance
             return false;
 
-        return covariant[buildSR(returnByRef, from)][buildSR(returnByRef, to)];
+        return covariant[buildScopeRef(returnByRef, from)][buildScopeRef(returnByRef, to)];
     }
 
-    /* Classification of 'scope-return-ref' possibilities
-     */
-    private enum SR
-    {
-        None,
-        Scope,
-        ReturnScope,
-        Ref,
-        ReturnRef,
-        RefScope,
-        ReturnRef_Scope,
-        Ref_ReturnScope,
-    }
-
-    extern (D) private static bool[SR.max + 1][SR.max + 1] covariantInit() pure nothrow @nogc @safe
+    extern (D) private static bool[ScopeRef.max + 1][ScopeRef.max + 1] covariantInit() pure nothrow @nogc @safe
     {
         /* Initialize covariant[][] with this:
 
@@ -7087,26 +7050,26 @@ extern (C++) final class Parameter : ASTNode
              ReturnRef-Scope       X       X
              Ref-ReturnScope   X   X            X
         */
-        bool[SR.max + 1][SR.max + 1] covariant;
+        bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant;
 
-        foreach (i; 0 .. SR.max + 1)
+        foreach (i; 0 .. ScopeRef.max + 1)
         {
             covariant[i][i] = true;
-            covariant[SR.RefScope][i] = true;
+            covariant[ScopeRef.RefScope][i] = true;
         }
-        covariant[SR.ReturnScope][SR.None]        = true;
-        covariant[SR.Scope      ][SR.None]        = true;
-        covariant[SR.Scope      ][SR.ReturnScope] = true;
+        covariant[ScopeRef.ReturnScope][ScopeRef.None]        = true;
+        covariant[ScopeRef.Scope      ][ScopeRef.None]        = true;
+        covariant[ScopeRef.Scope      ][ScopeRef.ReturnScope] = true;
 
-        covariant[SR.Ref            ][SR.ReturnRef] = true;
-        covariant[SR.ReturnRef_Scope][SR.ReturnRef] = true;
-        covariant[SR.Ref_ReturnScope][SR.Ref      ] = true;
-        covariant[SR.Ref_ReturnScope][SR.ReturnRef] = true;
+        covariant[ScopeRef.Ref            ][ScopeRef.ReturnRef] = true;
+        covariant[ScopeRef.ReturnRef_Scope][ScopeRef.ReturnRef] = true;
+        covariant[ScopeRef.Ref_ReturnScope][ScopeRef.Ref      ] = true;
+        covariant[ScopeRef.Ref_ReturnScope][ScopeRef.ReturnRef] = true;
 
         return covariant;
     }
 
-    extern (D) private static immutable bool[SR.max + 1][SR.max + 1] covariant = covariantInit();
+    extern (D) private static immutable bool[ScopeRef.max + 1][ScopeRef.max + 1] covariant = covariantInit();
 
     extern (D) bool opEquals(const Parameter other) const
     {
@@ -7252,3 +7215,53 @@ bool isCopyable(Type t)
     }
     return true;
 }
+
+/***************************************
+ * Computes how a parameter may be returned.
+ * Shrinking the representation is necessary because StorageClass is so wide
+ * Params:
+ *   returnByRef = true if the function returns by ref
+ *   stc = storage class of parameter
+ * Returns:
+ *   value from enum ScopeRef
+ */
+ScopeRef buildScopeRef(bool returnByRef, StorageClass stc) pure nothrow @nogc @safe
+{
+    if (stc & STC.out_)
+        stc |= STC.ref_;        // treat `out` and `ref` the same
+
+    ScopeRef result;
+    final switch (stc & (STC.ref_ | STC.scope_ | STC.return_))
+    {
+        case STC.return_:
+        case 0:                        result = ScopeRef.None;        break;
+        case STC.ref_:                 result = ScopeRef.Ref;         break;
+        case STC.scope_:               result = ScopeRef.Scope;       break;
+        case STC.return_ | STC.ref_:   result = ScopeRef.ReturnRef;   break;
+        case STC.return_ | STC.scope_: result = ScopeRef.ReturnScope; break;
+        case STC.ref_    | STC.scope_: result = ScopeRef.RefScope;    break;
+
+        case STC.return_ | STC.ref_ | STC.scope_:
+            result = returnByRef ? ScopeRef.ReturnRef_Scope
+                                 : ScopeRef.Ref_ReturnScope;
+            break;
+    }
+    return result;
+}
+
+/**
+ * Classification of 'scope-return-ref' possibilities
+ */
+enum ScopeRef
+{
+    None,
+    Scope,
+    ReturnScope,
+    Ref,
+    ReturnRef,
+    RefScope,
+    ReturnRef_Scope,
+    Ref_ReturnScope,
+}
+
+
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index 7d134a966ca..4bb2907c9ba 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -122,8 +122,6 @@ public:
         }
         if (e.onstack)
             return;
-        if (e.allocator)
-            return;
         if (global.params.ehnogc && e.thrownew)
             return;                     // separate allocator is called for this, not the GC
         if (f.setGC())
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 5a5fb0b73ed..3ae30619a20 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -461,7 +461,7 @@ Expression Expression_optimize(Expression e, int result, bool keepLvalue)
             if (e.e1.op == TOK.variable)
             {
                 VarExp ve = cast(VarExp)e.e1;
-                if (!ve.var.isOut() && !ve.var.isRef() && !ve.var.isImportedSymbol())
+                if (!ve.var.isReference() && !ve.var.isImportedSymbol())
                 {
                     ret = new SymOffExp(e.loc, ve.var, 0, ve.hasOverloads);
                     ret.type = e.type;
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 572f1782cea..34635eac7e4 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1482,7 +1482,11 @@ class Parser(AST) : Lexer
             return 0;
         }
 
-        error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
+        if (token.isKeyword())
+            error("`%s` is a keyword, not an `@` attribute", token.toChars());
+        else
+            error("`@identifier` or `@(ArgumentList)` expected, not `@%s`", token.toChars());
+
         return 0;
     }
 
@@ -2818,20 +2822,47 @@ class Parser(AST) : Lexer
 
     /*****************************************
      * Parse a new definition:
-     *      new(parameters) { body }
+     *      @disable new();
      * Current token is 'new'.
      */
     private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
     {
         const loc = token.loc;
         StorageClass stc = getStorageClass!AST(pAttrs);
-
+        if (!(stc & STC.disable))
+        {
+            error("`new` allocator must be annotated with `@disabled`");
+        }
         nextToken();
 
-        auto parameterList = parseParameterList(null);
-        auto f = new AST.NewDeclaration(loc, Loc.initial, stc, parameterList);
-        AST.Dsymbol s = parseContracts(f);
-        return s;
+        /* @@@DEPRECATED_2.098@@@
+         * After deprecation period (2.108), remove all code in the version(all) block.
+         */
+        version (all)
+        {
+            auto parameterList = parseParameterList(null);  // parameterList ignored
+            if (parameterList.parameters.length > 0 || parameterList.varargs != VarArg.none)
+                deprecation("`new` allocator with non-empty parameter list is deprecated");
+            auto f = new AST.NewDeclaration(loc, stc);
+            if (token.value != TOK.semicolon)
+            {
+                deprecation("`new` allocator with function definition is deprecated");
+                parseContracts(f);  // body ignored
+                f.fbody = null;
+                f.fensures = null;
+                f.frequires = null;
+            }
+            else
+                nextToken();
+            return f;
+        }
+        else
+        {
+            check(TOK.leftParenthesis);
+            check(TOK.rightParenthesis);
+            check(TOK.semicolon);
+            return new AST.NewDeclaration(loc, stc);
+        }
     }
 
     /**********************************************
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 79c3272870f..728b1df790f 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -1112,7 +1112,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
 
                     foreach (v; *funcdecl.parameters)
                     {
-                        if (v.storage_class & (STC.ref_ | STC.out_ | STC.lazy_))
+                        if (v.isReference() || (v.storage_class & STC.lazy_))
                             continue;
                         if (v.needsScopeDtor())
                         {
@@ -1570,3 +1570,55 @@ private struct FuncDeclSem3
         }
     }
 }
+
+private void semanticTypeInfoMembers(StructDeclaration sd)
+{
+    if (sd.xeq &&
+        sd.xeq._scope &&
+        sd.xeq.semanticRun < PASS.semantic3done)
+    {
+        uint errors = global.startGagging();
+        sd.xeq.semantic3(sd.xeq._scope);
+        if (global.endGagging(errors))
+            sd.xeq = sd.xerreq;
+    }
+
+    if (sd.xcmp &&
+        sd.xcmp._scope &&
+        sd.xcmp.semanticRun < PASS.semantic3done)
+    {
+        uint errors = global.startGagging();
+        sd.xcmp.semantic3(sd.xcmp._scope);
+        if (global.endGagging(errors))
+            sd.xcmp = sd.xerrcmp;
+    }
+
+    FuncDeclaration ftostr = search_toString(sd);
+    if (ftostr &&
+        ftostr._scope &&
+        ftostr.semanticRun < PASS.semantic3done)
+    {
+        ftostr.semantic3(ftostr._scope);
+    }
+
+    if (sd.xhash &&
+        sd.xhash._scope &&
+        sd.xhash.semanticRun < PASS.semantic3done)
+    {
+        sd.xhash.semantic3(sd.xhash._scope);
+    }
+
+    if (sd.postblit &&
+        sd.postblit._scope &&
+        sd.postblit.semanticRun < PASS.semantic3done)
+    {
+        sd.postblit.semantic3(sd.postblit._scope);
+    }
+
+    if (sd.dtor &&
+        sd.dtor._scope &&
+        sd.dtor.semanticRun < PASS.semantic3done)
+    {
+        sd.dtor.semantic3(sd.dtor._scope);
+    }
+}
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index f76f37edceb..b49c9035d3f 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -18,8 +18,6 @@ import core.stdc.stdio;
 
 import dmd.aggregate;
 import dmd.arraytypes;
-import dmd.attrib;
-import dmd.astcodegen;
 import dmd.astenums;
 import dmd.ast_node;
 import dmd.gluelayer;
@@ -31,11 +29,9 @@ import dmd.denum;
 import dmd.dimport;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
 import dmd.hdrgen;
@@ -43,7 +39,6 @@ import dmd.id;
 import dmd.identifier;
 import dmd.dinterpret;
 import dmd.mtype;
-import dmd.parse;
 import dmd.root.outbuffer;
 import dmd.root.rootobject;
 import dmd.sapply;
@@ -327,40 +322,6 @@ extern (C++) abstract class Statement : ASTNode
         return walkPostorder(this, hc);
     }
 
-    /****************************************
-     * If this statement has code that needs to run in a finally clause
-     * at the end of the current scope, return that code in the form of
-     * a Statement.
-     * Params:
-     *     sc = context
-     *     sentry     = set to code executed upon entry to the scope
-     *     sexception = set to code executed upon exit from the scope via exception
-     *     sfinally   = set to code executed in finally block
-     * Returns:
-     *    code to be run in the finally clause
-     */
-    Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
-    {
-        //printf("Statement::scopeCode()\n");
-        *sentry = null;
-        *sexception = null;
-        *sfinally = null;
-        return this;
-    }
-
-    /*********************************
-     * Flatten out the scope by presenting the statement
-     * as an array of statements.
-     * Params:
-     *     sc = context
-     * Returns:
-     *     The array of `Statements`, or `null` if no flattening necessary
-     */
-    Statements* flatten(Scope* sc)
-    {
-        return null;
-    }
-
     /*******************************
      * Find last statement in a sequence of statements.
      * Returns:
@@ -392,7 +353,7 @@ extern (C++) abstract class Statement : ASTNode
     pure nothrow @nogc
     inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
 
-  final pure inout nothrow @nogc:
+    final pure inout nothrow @nogc @safe:
 
     /********************
      * A cheaper method of doing downcasting of Statements.
@@ -405,6 +366,8 @@ extern (C++) abstract class Statement : ASTNode
     inout(CompoundStatement)    isCompoundStatement()    { return stmt == STMT.Compound    ? cast(typeof(return))this : null; }
     inout(ReturnStatement)      isReturnStatement()      { return stmt == STMT.Return      ? cast(typeof(return))this : null; }
     inout(IfStatement)          isIfStatement()          { return stmt == STMT.If          ? cast(typeof(return))this : null; }
+    inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
+    inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
     inout(CaseStatement)        isCaseStatement()        { return stmt == STMT.Case        ? cast(typeof(return))this : null; }
     inout(DefaultStatement)     isDefaultStatement()     { return stmt == STMT.Default     ? cast(typeof(return))this : null; }
     inout(LabelStatement)       isLabelStatement()       { return stmt == STMT.Label       ? cast(typeof(return))this : null; }
@@ -413,6 +376,7 @@ extern (C++) abstract class Statement : ASTNode
     inout(GotoCaseStatement)    isGotoCaseStatement()    { return stmt == STMT.GotoCase    ? cast(typeof(return))this : null; }
     inout(BreakStatement)       isBreakStatement()       { return stmt == STMT.Break       ? cast(typeof(return))this : null; }
     inout(DtorExpStatement)     isDtorExpStatement()     { return stmt == STMT.DtorExp     ? cast(typeof(return))this : null; }
+    inout(CompileStatement)     isCompileStatement()     { return stmt == STMT.Compile     ? cast(typeof(return))this : null; }
     inout(ForwardingStatement)  isForwardingStatement()  { return stmt == STMT.Forwarding  ? cast(typeof(return))this : null; }
     inout(DoStatement)          isDoStatement()          { return stmt == STMT.Do          ? cast(typeof(return))this : null; }
     inout(WhileStatement)       isWhileStatement()       { return stmt == STMT.While       ? cast(typeof(return))this : null; }
@@ -423,7 +387,9 @@ extern (C++) abstract class Statement : ASTNode
     inout(WithStatement)        isWithStatement()        { return stmt == STMT.With        ? cast(typeof(return))this : null; }
     inout(TryCatchStatement)    isTryCatchStatement()    { return stmt == STMT.TryCatch    ? cast(typeof(return))this : null; }
     inout(ThrowStatement)       isThrowStatement()       { return stmt == STMT.Throw       ? cast(typeof(return))this : null; }
+    inout(DebugStatement)       isDebugStatement()       { return stmt == STMT.Debug       ? cast(typeof(return))this : null; }
     inout(TryFinallyStatement)  isTryFinallyStatement()  { return stmt == STMT.TryFinally  ? cast(typeof(return))this : null; }
+    inout(ScopeGuardStatement)  isScopeGuardStatement()  { return stmt == STMT.ScopeGuard  ? cast(typeof(return))this : null; }
     inout(SwitchErrorStatement)  isSwitchErrorStatement()  { return stmt == STMT.SwitchError  ? cast(typeof(return))this : null; }
     inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
     inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
@@ -471,163 +437,6 @@ extern (C++) final class PeelStatement : Statement
     }
 }
 
-/***********************************************************
- * Convert TemplateMixin members (== Dsymbols) to Statements.
- */
-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);
-        }
-
-        override void visit(Dsymbol s)
-        {
-            .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
-            result = new ErrorStatement();
-        }
-
-        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);
-        }
-
-        /* 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);
-        }
-
-        /* 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)
-        {
-            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));
-        }
-    }
-
-    if (!s)
-        return null;
-
-    scope ToStmt v = new ToStmt();
-    s.accept(v);
-    return v.result;
-}
 
 /***********************************************************
  * https://dlang.org/spec/statement.html#ExpressionStatement
@@ -664,68 +473,6 @@ extern (C++) class ExpStatement : Statement
         return new ExpStatement(loc, exp ? exp.syntaxCopy() : null);
     }
 
-    override final Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
-    {
-        //printf("ExpStatement::scopeCode()\n");
-
-        *sentry = null;
-        *sexception = null;
-        *sfinally = null;
-
-        if (exp && exp.op == TOK.declaration)
-        {
-            auto de = cast(DeclarationExp)exp;
-            auto v = de.declaration.isVarDeclaration();
-            if (v && !v.isDataseg())
-            {
-                if (v.needsScopeDtor())
-                {
-                    *sfinally = new DtorExpStatement(loc, v.edtor, v);
-                    v.storage_class |= STC.nodtor; // don't add in dtor again
-                }
-            }
-        }
-        return this;
-    }
-
-    override final Statements* flatten(Scope* sc)
-    {
-        /* https://issues.dlang.org/show_bug.cgi?id=14243
-         * expand template mixin in statement scope
-         * to handle variable destructors.
-         */
-        if (exp && exp.op == TOK.declaration)
-        {
-            Dsymbol d = (cast(DeclarationExp)exp).declaration;
-            if (TemplateMixin tm = d.isTemplateMixin())
-            {
-                Expression e = exp.expressionSemantic(sc);
-                if (e.op == TOK.error || tm.errors)
-                {
-                    auto a = new Statements();
-                    a.push(new ErrorStatement());
-                    return a;
-                }
-                assert(tm.members);
-
-                Statement s = toStatement(tm);
-                version (none)
-                {
-                    OutBuffer buf;
-                    buf.doindent = 1;
-                    HdrGenState hgs;
-                    hgs.hdrgen = true;
-                    toCBuffer(s, &buf, &hgs);
-                    printf("tm ==> s = %s\n", buf.peekChars());
-                }
-                auto a = new Statements();
-                a.push(s);
-                return a;
-            }
-        }
-        return null;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -781,46 +528,6 @@ extern (C++) final class CompileStatement : Statement
         return new CompileStatement(loc, Expression.arraySyntaxCopy(exps));
     }
 
-    private Statements* compileIt(Scope* sc)
-    {
-        //printf("CompileStatement::compileIt() %s\n", exp.toChars());
-
-        auto errorStatements()
-        {
-            auto a = new Statements();
-            a.push(new ErrorStatement());
-            return a;
-        }
-
-
-        OutBuffer buf;
-        if (expressionsToString(buf, sc, exps))
-            return errorStatements();
-
-        const errors = global.errors;
-        const len = buf.length;
-        buf.writeByte(0);
-        const str = buf.extractSlice()[0 .. len];
-        scope p = new Parser!ASTCodegen(loc, sc._module, str, false);
-        p.nextToken();
-
-        auto a = new Statements();
-        while (p.token.value != TOK.endOfFile)
-        {
-            Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
-            if (!s || global.errors != errors)
-                return errorStatements();
-            a.push(s);
-        }
-        return a;
-    }
-
-    override Statements* flatten(Scope* sc)
-    {
-        //printf("CompileStatement::flatten() %s\n", exp.toChars());
-        return compileIt(sc);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -880,11 +587,6 @@ extern (C++) class CompoundStatement : Statement
         return new CompoundStatement(loc, Statement.arraySyntaxCopy(statements));
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        return statements;
-    }
-
     override final inout(ReturnStatement) endsWithReturnStatement() inout nothrow pure
     {
         foreach (s; *statements)
@@ -1062,39 +764,6 @@ extern (C++) final class ForwardingStatement : Statement
         return new ForwardingStatement(loc, statement.syntaxCopy());
     }
 
-    /***********************
-     * ForwardingStatements are distributed over the flattened
-     * sequence of statements. This prevents flattening to be
-     * "blocked" by a ForwardingStatement and is necessary, for
-     * example, to support generating scope guards with `static
-     * foreach`:
-     *
-     *     static foreach(i; 0 .. 10) scope(exit) writeln(i);
-     *     writeln("this is printed first");
-     *     // then, it prints 10, 9, 8, 7, ...
-     */
-
-    override Statements* flatten(Scope* sc)
-    {
-        if (!statement)
-        {
-            return null;
-        }
-        sc = sc.push(sym);
-        auto a = statement.flatten(sc);
-        sc = sc.pop();
-        if (!a)
-        {
-            return a;
-        }
-        auto b = new Statements(a.dim);
-        foreach (i, s; *a)
-        {
-            (*b)[i] = s ? new ForwardingStatement(s.loc, sym, s) : null;
-        }
-        return b;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -1222,13 +891,6 @@ extern (C++) final class ForStatement : Statement
             endloc);
     }
 
-    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
-    {
-        //printf("ForStatement::scopeCode()\n");
-        Statement.scopeCode(sc, sentry, sexception, sfinally);
-        return this;
-    }
-
     override Statement getRelatedLabeled()
     {
         return relatedLabeled ? relatedLabeled : this;
@@ -1411,66 +1073,12 @@ extern (C++) final class ConditionalStatement : Statement
         return new ConditionalStatement(loc, condition.syntaxCopy(), ifbody.syntaxCopy(), elsebody ? elsebody.syntaxCopy() : null);
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        Statement s;
-
-        //printf("ConditionalStatement::flatten()\n");
-        if (condition.include(sc))
-        {
-            DebugCondition dc = condition.isDebugCondition();
-            if (dc)
-            {
-                s = new DebugStatement(loc, ifbody);
-                debugThrowWalker(ifbody);
-            }
-            else
-                s = ifbody;
-        }
-        else
-            s = elsebody;
-
-        auto a = new Statements();
-        a.push(s);
-        return a;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
     }
 }
 
-/**
-Marks all occurring ThrowStatements as internalThrows.
-This is intended to be called from a DebugStatement as it allows
-to mark all its nodes as nothrow.
-
-Params:
-    s = AST Node to traverse
-*/
-private void debugThrowWalker(Statement s)
-{
-
-    extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor
-    {
-        alias visit = SemanticTimeTransitiveVisitor.visit;
-    public:
-
-        override void visit(ThrowStatement s)
-        {
-            s.internalThrow = true;
-        }
-
-        override void visit(CallExp s)
-        {
-            s.inDebugStatement = true;
-        }
-    }
-
-    scope walker = new DebugWalker();
-    s.accept(walker);
-}
 
 /***********************************************************
  * https://dlang.org/spec/version.html#StaticForeachStatement
@@ -1498,30 +1106,6 @@ extern (C++) final class StaticForeachStatement : Statement
         return new StaticForeachStatement(loc, sfe.syntaxCopy());
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        sfe.prepare(sc);
-        if (sfe.ready())
-        {
-            import dmd.statementsem;
-            auto s = makeTupleForeach!(true, false)(sc, sfe.aggrfe, sfe.needExpansion);
-            auto result = s.flatten(sc);
-            if (result)
-            {
-                return result;
-            }
-            result = new Statements();
-            result.push(s);
-            return result;
-        }
-        else
-        {
-            auto result = new Statements();
-            result.push(new ErrorStatement());
-            return result;
-        }
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2097,52 +1681,6 @@ extern (C++) final class ScopeGuardStatement : Statement
         return new ScopeGuardStatement(loc, tok, statement.syntaxCopy());
     }
 
-    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexception, Statement* sfinally)
-    {
-        //printf("ScopeGuardStatement::scopeCode()\n");
-        *sentry = null;
-        *sexception = null;
-        *sfinally = null;
-
-        Statement s = new PeelStatement(statement);
-
-        switch (tok)
-        {
-        case TOK.onScopeExit:
-            *sfinally = s;
-            break;
-
-        case TOK.onScopeFailure:
-            *sexception = s;
-            break;
-
-        case TOK.onScopeSuccess:
-            {
-                /* Create:
-                 *  sentry:   bool x = false;
-                 *  sexception:    x = true;
-                 *  sfinally: if (!x) statement;
-                 */
-                auto v = copyToTemp(0, "__os", IntegerExp.createBool(false));
-                v.dsymbolSemantic(sc);
-                *sentry = new ExpStatement(loc, v);
-
-                Expression e = IntegerExp.createBool(true);
-                e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e);
-                *sexception = new ExpStatement(Loc.initial, e);
-
-                e = new VarExp(Loc.initial, v);
-                e = new NotExp(Loc.initial, e);
-                *sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial);
-
-                break;
-            }
-        default:
-            assert(0);
-        }
-        return null;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2195,19 +1733,6 @@ extern (C++) final class DebugStatement : Statement
         return new DebugStatement(loc, statement ? statement.syntaxCopy() : null);
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        Statements* a = statement ? statement.flatten(sc) : null;
-        if (a)
-        {
-            foreach (ref s; *a)
-            {
-                s = new DebugStatement(loc, s);
-            }
-        }
-        return a;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2343,41 +1868,6 @@ extern (C++) final class LabelStatement : Statement
         return new LabelStatement(loc, ident, statement ? statement.syntaxCopy() : null);
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        Statements* a = null;
-        if (statement)
-        {
-            a = statement.flatten(sc);
-            if (a)
-            {
-                if (!a.dim)
-                {
-                    a.push(new ExpStatement(loc, cast(Expression)null));
-                }
-
-                // reuse 'this' LabelStatement
-                this.statement = (*a)[0];
-                (*a)[0] = this;
-            }
-        }
-        return a;
-    }
-
-    override Statement scopeCode(Scope* sc, Statement* sentry, Statement* sexit, Statement* sfinally)
-    {
-        //printf("LabelStatement::scopeCode()\n");
-        if (statement)
-            statement = statement.scopeCode(sc, sentry, sexit, sfinally);
-        else
-        {
-            *sentry = null;
-            *sexit = null;
-            *sfinally = null;
-        }
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2527,11 +2017,6 @@ extern (C++) final class CompoundAsmStatement : CompoundStatement
         return new CompoundAsmStatement(loc, a, stc);
     }
 
-    override Statements* flatten(Scope* sc)
-    {
-        return null;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index 58937724f53..7825762db9e 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -122,8 +122,6 @@ public:
     bool usesEH();
     bool comeFrom();
     bool hasCode();
-    virtual Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
-    virtual Statements *flatten(Scope *sc);
     virtual Statement *last();
 
     virtual ReturnStatement *endsWithReturnStatement() { return NULL; }
@@ -134,6 +132,8 @@ public:
     CompoundStatement    *isCompoundStatement()    { return stmt == STMTcompound    ? (CompoundStatement*)this    : NULL; }
     ReturnStatement      *isReturnStatement()      { return stmt == STMTreturn      ? (ReturnStatement*)this      : NULL; }
     IfStatement          *isIfStatement()          { return stmt == STMTif          ? (IfStatement*)this          : NULL; }
+    ConditionalStatement *isConditionalStatement() { return stmt == STMTconditional ? (ConditionalStatement*)this : NULL; }
+    StaticForeachStatement *isStaticForeachStatement() { return stmt == STMTstaticForeach ? (StaticForeachStatement*)this : NULL; }
     CaseStatement        *isCaseStatement()        { return stmt == STMTcase        ? (CaseStatement*)this        : NULL; }
     DefaultStatement     *isDefaultStatement()     { return stmt == STMTdefault     ? (DefaultStatement*)this     : NULL; }
     LabelStatement       *isLabelStatement()       { return stmt == STMTlabel       ? (LabelStatement*)this       : NULL; }
@@ -141,6 +141,7 @@ public:
     GotoCaseStatement    *isGotoCaseStatement()    { return stmt == STMTgotoCase    ? (GotoCaseStatement*)this    : NULL; }
     BreakStatement       *isBreakStatement()       { return stmt == STMTbreak       ? (BreakStatement*)this       : NULL; }
     DtorExpStatement     *isDtorExpStatement()     { return stmt == STMTdtorExp     ? (DtorExpStatement*)this     : NULL; }
+    CompileStatement     *isCompileStatement()     { return stmt == STMTcompile     ? (CompileStatement*)this     : NULL; }
     ForwardingStatement  *isForwardingStatement()  { return stmt == STMTforwarding  ? (ForwardingStatement*)this  : NULL; }
     DoStatement          *isDoStatement()          { return stmt == STMTdo          ? (DoStatement*)this          : NULL; }
     ForStatement         *isForStatement()         { return stmt == STMTfor         ? (ForStatement*)this         : NULL; }
@@ -150,7 +151,9 @@ public:
     WithStatement        *isWithStatement()        { return stmt == STMTwith        ? (WithStatement*)this        : NULL; }
     TryCatchStatement    *isTryCatchStatement()    { return stmt == STMTtryCatch    ? (TryCatchStatement*)this    : NULL; }
     ThrowStatement       *isThrowStatement()       { return stmt == STMTthrow       ? (ThrowStatement*)this       : NULL; }
+    DebugStatement       *isDebugStatement()       { return stmt == STMTdebug       ? (DebugStatement*)this       : NULL; }
     TryFinallyStatement  *isTryFinallyStatement()  { return stmt == STMTtryFinally  ? (TryFinallyStatement*)this  : NULL; }
+    ScopeGuardStatement  *isScopeGuardStatement()  { return stmt == STMTscopeGuard  ? (ScopeGuardStatement*)this  : NULL; }
     SwitchErrorStatement  *isSwitchErrorStatement()  { return stmt == STMTswitchError  ? (SwitchErrorStatement*)this  : NULL; }
     UnrolledLoopStatement *isUnrolledLoopStatement() { return stmt == STMTunrolledLoop ? (UnrolledLoopStatement*)this : NULL; }
     ForeachRangeStatement *isForeachRangeStatement() { return stmt == STMTforeachRange ? (ForeachRangeStatement*)this : NULL; }
@@ -185,8 +188,6 @@ public:
 
     static ExpStatement *create(Loc loc, Expression *exp);
     ExpStatement *syntaxCopy();
-    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
-    Statements *flatten(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -209,7 +210,6 @@ public:
     Expressions *exps;
 
     CompileStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -220,7 +220,6 @@ public:
 
     static CompoundStatement *create(Loc loc, Statement *s1, Statement *s2);
     CompoundStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
     ReturnStatement *endsWithReturnStatement();
     Statement *last();
 
@@ -270,7 +269,6 @@ public:
     Statement *statement;
 
     ForwardingStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -318,7 +316,6 @@ public:
     Statement *relatedLabeled;
 
     ForStatement *syntaxCopy();
-    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
     Statement *getRelatedLabeled() { return relatedLabeled ? relatedLabeled : this; }
     bool hasBreak() const;
     bool hasContinue() const;
@@ -392,7 +389,6 @@ public:
     Statement *elsebody;
 
     ConditionalStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -403,7 +399,6 @@ public:
     StaticForeach *sfe;
 
     StaticForeachStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -635,7 +630,6 @@ public:
     Statement *statement;
 
     ScopeGuardStatement *syntaxCopy();
-    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -659,7 +653,6 @@ public:
     Statement *statement;
 
     DebugStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
     void accept(Visitor *v) { v->visit(this); }
 };
 
@@ -692,8 +685,6 @@ public:
     bool breaks;                // someone did a 'break ident'
 
     LabelStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
-    Statement *scopeCode(Scope *sc, Statement **sentry, Statement **sexit, Statement **sfinally);
 
     void accept(Visitor *v) { v->visit(this); }
 };
@@ -760,7 +751,6 @@ public:
     StorageClass stc; // postfix attributes like nothrow/pure/@trusted
 
     CompoundAsmStatement *syntaxCopy();
-    Statements *flatten(Scope *sc);
 
     void accept(Visitor *v) { v->visit(this); }
 };
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index b391b05603c..cd9ad8fdd09 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -19,7 +19,10 @@ import dmd.aggregate;
 import dmd.aliasthis;
 import dmd.arrayop;
 import dmd.arraytypes;
+import dmd.astcodegen;
 import dmd.astenums;
+import dmd.ast_node;
+import dmd.attrib;
 import dmd.blockexit;
 import dmd.clone;
 import dmd.cond;
@@ -49,12 +52,14 @@ import dmd.intrange;
 import dmd.mtype;
 import dmd.nogc;
 import dmd.opover;
+import dmd.parse;
 import dmd.printast;
 import dmd.root.outbuffer;
 import dmd.root.string;
 import dmd.semantic2;
 import dmd.sideeffect;
 import dmd.statement;
+import dmd.staticassert;
 import dmd.target;
 import dmd.tokens;
 import dmd.typesem;
@@ -273,7 +278,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             Statement sexception;
             Statement sfinally;
 
-            (*cs.statements)[i] = s.scopeCode(sc, &sentry, &sexception, &sfinally);
+            (*cs.statements)[i] = s.scopeCode(sc, sentry, sexception, sfinally);
             if (sentry)
             {
                 sentry = sentry.statementSemantic(sc);
@@ -474,7 +479,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
             Statement sentry;
             Statement sexception;
             Statement sfinally;
-            ss.statement = ss.statement.scopeCode(sc, &sentry, &sexception, &sfinally);
+            ss.statement = ss.statement.scopeCode(sc, sentry, sexception, sfinally);
             assert(!sentry);
             assert(!sexception);
             if (sfinally)
@@ -538,7 +543,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         const inLoopSave = sc.inLoop;
         sc.inLoop = true;
         if (ds._body)
-            ds._body = ds._body.semanticScope(sc, ds, ds);
+            ds._body = ds._body.semanticScope(sc, ds, ds, null);
         sc.inLoop = inLoopSave;
 
         if (ds.condition.op == TOK.dotIdentifier)
@@ -1433,7 +1438,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     auto var = new VarDeclaration(loc, p.type, p.ident, null);
                     var.storage_class |= STC.foreach_;
                     var.storage_class |= p.storageClass & (STC.IOR | STC.TYPECTOR);
-                    if (var.storage_class & (STC.ref_ | STC.out_))
+                    if (var.isReference())
                         var.storage_class |= STC.nodtor;
 
                     fs.value = var;
@@ -2349,7 +2354,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         CtorFlow ctorflow_then = sc.ctorflow;   // move flow results
         sc.ctorflow = ctorflow_root;            // reset flow analysis back to root
         if (ifs.elsebody)
-            ifs.elsebody = ifs.elsebody.semanticScope(sc, null, null);
+            ifs.elsebody = ifs.elsebody.semanticScope(sc, null, null, null);
 
         // Merge 'then' results into 'else' results
         sc.merge(ifs.loc, ctorflow_then);
@@ -2686,9 +2691,11 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                 ed = ds.isEnumDeclaration(); // typedef'ed enum
             if (!ed && te && ((ds = te.toDsymbol(sc)) !is null))
                 ed = ds.isEnumDeclaration();
-            if (ed)
+            if (ed && ss.cases.length < ed.members.length)
             {
-              Lmembers:
+                int missingMembers = 0;
+                const maxShown = !global.params.verbose ? 6 : int.max;
+            Lmembers:
                 foreach (es; *ed.members)
                 {
                     EnumMember em = es.isEnumMember();
@@ -2696,14 +2703,25 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                     {
                         foreach (cs; *ss.cases)
                         {
-                            if (cs.exp.equals(em.value) || (!cs.exp.type.isString() && !em.value.type.isString() && cs.exp.toInteger() == em.value.toInteger()))
+                            if (cs.exp.equals(em.value) || (!cs.exp.type.isString() &&
+                                !em.value.type.isString() && cs.exp.toInteger() == em.value.toInteger()))
                                 continue Lmembers;
                         }
-                        ss.error("`enum` member `%s` not represented in `final switch`", em.toChars());
-                        sc.pop();
-                        return setError();
+                        if (missingMembers == 0)
+                            ss.error("missing cases for `enum` members in `final switch`:");
+
+                        if (missingMembers < maxShown)
+                            errorSupplemental(ss.loc, "`%s`", em.toChars());
+                        missingMembers++;
                     }
                 }
+                if (missingMembers > 0)
+                {
+                    if (missingMembers > maxShown)
+                        errorSupplemental(ss.loc, "... (%d more, -v to show) ...", missingMembers - maxShown);
+                    sc.pop();
+                    return setError();
+                }
             }
             else
                 needswitcherror = true;
@@ -2895,7 +2913,7 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
                      */
                     if (!v.isConst() && !v.isImmutable())
                     {
-                        cs.deprecation("`case` variables have to be `const` or `immutable`");
+                        cs.error("`case` variables have to be `const` or `immutable`");
                     }
 
                     if (sw.isFinal)
@@ -3933,13 +3951,9 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
         enum FLAGcpp = 1;
         enum FLAGd = 2;
 
-        tcs.tryBody = sc.tryBody;
-
-        scope sc2 = sc.push();
-        sc2.tryBody = tcs;
-        tcs._body = tcs._body.semanticScope(sc2, null, null);
+        tcs.tryBody = sc.tryBody;   // chain on the in-flight tryBody
+        tcs._body = tcs._body.semanticScope(sc, null, null, tcs);
         assert(tcs._body);
-        sc2.pop();
 
         /* Even if body is empty, still do semantic analysis on catches
          */
@@ -4020,12 +4034,8 @@ private extern (C++) final class StatementSemanticVisitor : Visitor
     override void visit(TryFinallyStatement tfs)
     {
         //printf("TryFinallyStatement::semantic()\n");
-        tfs.tryBody = sc.tryBody;
-
-        auto sc2 = sc.push();
-        sc2.tryBody = tfs;
-        tfs._body = tfs._body.statementSemantic(sc2);
-        sc2.pop();
+        tfs.tryBody = sc.tryBody;   // chain on in-flight tryBody
+        tfs._body = tfs._body.semanticScope(sc, null, null, tfs);
 
         sc = sc.push();
         sc.tf = tfs;
@@ -4458,7 +4468,7 @@ Statement semanticNoScope(Statement s, Scope* sc)
 }
 
 // Same as semanticNoScope(), but do create a new scope
-Statement semanticScope(Statement s, Scope* sc, Statement sbreak, Statement scontinue)
+private Statement semanticScope(Statement s, Scope* sc, Statement sbreak, Statement scontinue, Statement tryBody)
 {
     auto sym = new ScopeDsymbol();
     sym.parent = sc.scopesym;
@@ -4467,12 +4477,98 @@ Statement semanticScope(Statement s, Scope* sc, Statement sbreak, Statement scon
         scd.sbreak = sbreak;
     if (scontinue)
         scd.scontinue = scontinue;
+    if (tryBody)
+        scd.tryBody = tryBody;
     s = s.semanticNoScope(scd);
     scd.pop();
     return s;
 }
 
 
+/****************************************
+ * If `statement` has code that needs to run in a finally clause
+ * at the end of the current scope, return that code in the form of
+ * a Statement.
+ * Params:
+ *     statement = the statement
+ *     sc = context
+ *     sentry     = set to code executed upon entry to the scope
+ *     sexception = set to code executed upon exit from the scope via exception
+ *     sfinally   = set to code executed in finally block
+ * Returns:
+ *    code to be run in the finally clause
+ */
+Statement scopeCode(Statement statement, Scope* sc, out Statement sentry, out Statement sexception, out Statement sfinally)
+{
+    if (auto es = statement.isExpStatement())
+    {
+        if (es.exp && es.exp.op == TOK.declaration)
+        {
+            auto de = cast(DeclarationExp)es.exp;
+            auto v = de.declaration.isVarDeclaration();
+            if (v && !v.isDataseg())
+            {
+                if (v.needsScopeDtor())
+                {
+                    sfinally = new DtorExpStatement(es.loc, v.edtor, v);
+                    v.storage_class |= STC.nodtor; // don't add in dtor again
+                }
+            }
+        }
+        return es;
+
+    }
+    else if (auto sgs = statement.isScopeGuardStatement())
+    {
+        Statement s = new PeelStatement(sgs.statement);
+
+        switch (sgs.tok)
+        {
+        case TOK.onScopeExit:
+            sfinally = s;
+            break;
+
+        case TOK.onScopeFailure:
+            sexception = s;
+            break;
+
+        case TOK.onScopeSuccess:
+            {
+                /* Create:
+                 *  sentry:   bool x = false;
+                 *  sexception:    x = true;
+                 *  sfinally: if (!x) statement;
+                 */
+                auto v = copyToTemp(0, "__os", IntegerExp.createBool(false));
+                v.dsymbolSemantic(sc);
+                sentry = new ExpStatement(statement.loc, v);
+
+                Expression e = IntegerExp.createBool(true);
+                e = new AssignExp(Loc.initial, new VarExp(Loc.initial, v), e);
+                sexception = new ExpStatement(Loc.initial, e);
+
+                e = new VarExp(Loc.initial, v);
+                e = new NotExp(Loc.initial, e);
+                sfinally = new IfStatement(Loc.initial, null, e, s, null, Loc.initial);
+
+                break;
+            }
+        default:
+            assert(0);
+        }
+        return null;
+    }
+    else if (auto ls = statement.isLabelStatement())
+    {
+        if (ls.statement)
+            ls.statement = ls.statement.scopeCode(sc, sentry, sexception, sfinally);
+        return ls;
+    }
+
+    return statement;
+}
+
+
 /*******************
  * Determines additional argument types for makeTupleForeach.
  */
@@ -4513,3 +4609,387 @@ TupleForeachRet!(isStatic, isDecl) makeTupleForeach(bool isStatic, bool isDecl)(
         return v.makeTupleForeach!(isStatic, isDecl)(fs, args);
     }
 }
+
+/*********************************
+ * Flatten out the scope by presenting `statement`
+ * as an array of statements.
+ * Params:
+ *     statement = the statement to flatten
+ *     sc = context
+ * Returns:
+ *     The array of `Statements`, or `null` if no flattening necessary
+ */
+private Statements* flatten(Statement statement, Scope* sc)
+{
+    static auto errorStatements()
+    {
+        auto a = new Statements();
+        a.push(new ErrorStatement());
+        return a;
+    }
+
+
+    /*compound and expression statements have classes that inherit from them with the same
+     *flattening behavior, so the isXXX methods won't work
+     */
+    switch(statement.stmt)
+    {
+        case STMT.Compound:
+        case STMT.CompoundDeclaration:
+            return (cast(CompoundStatement)statement).statements;
+
+        case STMT.Exp:
+        case STMT.DtorExp:
+            auto es = cast(ExpStatement)statement;
+            /* https://issues.dlang.org/show_bug.cgi?id=14243
+             * expand template mixin in statement scope
+             * to handle variable destructors.
+             */
+            if (!es.exp || es.exp.op != TOK.declaration)
+                return null;
+
+            Dsymbol d = (cast(DeclarationExp)es.exp).declaration;
+            auto tm = d.isTemplateMixin();
+            if (!tm)
+                return null;
+
+            Expression e = es.exp.expressionSemantic(sc);
+            if (e.op == TOK.error || tm.errors)
+                return errorStatements();
+            assert(tm.members);
+
+            Statement s = toStatement(tm);
+            version (none)
+            {
+                OutBuffer buf;
+                buf.doindent = 1;
+                HdrGenState hgs;
+                hgs.hdrgen = true;
+                toCBuffer(s, &buf, &hgs);
+                printf("tm ==> s = %s\n", buf.peekChars());
+            }
+            auto a = new Statements();
+            a.push(s);
+            return a;
+
+        case STMT.Forwarding:
+            /***********************
+             * ForwardingStatements are distributed over the flattened
+             * sequence of statements. This prevents flattening to be
+             * "blocked" by a ForwardingStatement and is necessary, for
+             * example, to support generating scope guards with `static
+             * foreach`:
+             *
+             *     static foreach(i; 0 .. 10) scope(exit) writeln(i);
+             *     writeln("this is printed first");
+             *     // then, it prints 10, 9, 8, 7, ...
+             */
+            auto fs = statement.isForwardingStatement();
+            if (!fs.statement)
+            {
+                return null;
+            }
+            sc = sc.push(fs.sym);
+            auto a = fs.statement.flatten(sc);
+            sc = sc.pop();
+            if (!a)
+            {
+                return a;
+            }
+            auto b = new Statements(a.dim);
+            foreach (i, s; *a)
+            {
+                (*b)[i] = s ? new ForwardingStatement(s.loc, fs.sym, s) : null;
+            }
+            return b;
+
+        case STMT.Conditional:
+            auto cs = statement.isConditionalStatement();
+            Statement s;
+
+            //printf("ConditionalStatement::flatten()\n");
+            if (cs.condition.include(sc))
+            {
+                DebugCondition dc = cs.condition.isDebugCondition();
+                if (dc)
+                {
+                    s = new DebugStatement(cs.loc, cs.ifbody);
+                    debugThrowWalker(cs.ifbody);
+                }
+                else
+                    s = cs.ifbody;
+            }
+            else
+                s = cs.elsebody;
+
+            auto a = new Statements();
+            a.push(s);
+            return a;
+
+        case STMT.StaticForeach:
+            auto sfs = statement.isStaticForeachStatement();
+            sfs.sfe.prepare(sc);
+            if (sfs.sfe.ready())
+            {
+                auto s = makeTupleForeach!(true, false)(sc, sfs.sfe.aggrfe, sfs.sfe.needExpansion);
+                auto result = s.flatten(sc);
+                if (result)
+                {
+                    return result;
+                }
+                result = new Statements();
+                result.push(s);
+                return result;
+            }
+            else
+                return errorStatements();
+
+        case STMT.Debug:
+            auto ds = statement.isDebugStatement();
+            Statements* a = ds.statement ? ds.statement.flatten(sc) : null;
+            if (!a)
+                return null;
+
+            foreach (ref s; *a)
+            {
+                s = new DebugStatement(ds.loc, s);
+            }
+            return a;
+
+        case STMT.Label:
+            auto ls = statement.isLabelStatement();
+            if (!ls.statement)
+                return null;
+
+            Statements* a = null;
+            a = ls.statement.flatten(sc);
+            if (!a)
+                return null;
+
+            if (!a.dim)
+            {
+                a.push(new ExpStatement(ls.loc, cast(Expression)null));
+            }
+
+            // reuse 'this' LabelStatement
+            ls.statement = (*a)[0];
+            (*a)[0] = ls;
+            return a;
+
+        case STMT.Compile:
+            auto cs = statement.isCompileStatement();
+
+
+            OutBuffer buf;
+            if (expressionsToString(buf, sc, cs.exps))
+                return errorStatements();
+
+            const errors = global.errors;
+            const len = buf.length;
+            buf.writeByte(0);
+            const str = buf.extractSlice()[0 .. len];
+            scope p = new Parser!ASTCodegen(cs.loc, sc._module, str, false);
+            p.nextToken();
+
+            auto a = new Statements();
+            while (p.token.value != TOK.endOfFile)
+            {
+                Statement s = p.parseStatement(ParseStatementFlags.semi | ParseStatementFlags.curlyScope);
+                if (!s || global.errors != errors)
+                    return errorStatements();
+                a.push(s);
+            }
+            return a;
+        default:
+            return null;
+    }
+}
+
+/***********************************************************
+ * Convert TemplateMixin members (== Dsymbols) to Statements.
+ */
+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);
+        }
+
+        override void visit(Dsymbol s)
+        {
+            .error(Loc.initial, "Internal Compiler Error: cannot mixin %s `%s`\n", s.kind(), s.toChars());
+            result = new ErrorStatement();
+        }
+
+        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);
+        }
+
+        /* 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);
+        }
+
+        /* 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)
+        {
+            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));
+        }
+    }
+
+    if (!s)
+        return null;
+
+    scope ToStmt v = new ToStmt();
+    s.accept(v);
+    return v.result;
+}
+
+/**
+Marks all occurring ThrowStatements as internalThrows.
+This is intended to be called from a DebugStatement as it allows
+to mark all its nodes as nothrow.
+
+Params:
+    s = AST Node to traverse
+*/
+private void debugThrowWalker(Statement s)
+{
+
+    extern(C++) final class DebugWalker : SemanticTimeTransitiveVisitor
+    {
+        alias visit = SemanticTimeTransitiveVisitor.visit;
+    public:
+
+        override void visit(ThrowStatement s)
+        {
+            s.internalThrow = true;
+        }
+
+        override void visit(CallExp s)
+        {
+            s.inDebugStatement = true;
+        }
+    }
+
+    scope walker = new DebugWalker();
+    s.accept(walker);
+}
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 1170fee2392..5e57d1f466d 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -879,8 +879,6 @@ package mixin template ParseVisitMethods(AST)
     override void visit(AST.NewDeclaration d)
     {
         //printf("Visiting NewDeclaration\n");
-        visitParameters(d.parameterList.parameters);
-        visitFuncBody(d);
     }
 
 //   Initializers
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index ab1f3d17861..cd1eee38250 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -2007,6 +2007,11 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 auto scopesym = sc.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);
+                }
                 sd.parent = sc.parent;
                 sd.dsymbolSemantic(sc);
             }
@@ -2387,8 +2392,12 @@ Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
                     error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
                     if (auto dsym = mt.toDsymbol(scope_))
                         if (auto sym = dsym.isAggregateDeclaration())
+                        {
                             if (auto fd = search_function(sym, Id.opDispatch))
                                 errorSupplemental(loc, "potentially malformed `opDispatch`. Use an explicit instantiation to get a better error message");
+                            else if (!sym.members)
+                                errorSupplemental(sym.loc, "`%s %s` is opaque and has no members.", sym.kind, mt.toPrettyChars(true));
+                        }
                 }
             }
             e = ErrorExp.get();
@@ -3730,7 +3739,11 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         assert(mt.ty == Tstruct || mt.ty == Tclass);
         auto sym = mt.toDsymbol(sc).isAggregateDeclaration();
         assert(sym);
-        if (ident != Id.__sizeof &&
+        if (// https://issues.dlang.org/show_bug.cgi?id=22054
+            // if a class or struct does not have a body
+            // there is no point in searching for its members
+            sym.members &&
+            ident != Id.__sizeof &&
             ident != Id.__xalignof &&
             ident != Id._init &&
             ident != Id._mangleof &&
@@ -4738,3 +4751,122 @@ Expression defaultInit(Type mt, const ref Loc loc)
                                 null;
     }
 }
+
+
+/******************************
+ * Get the value of the .max/.min property of `ed` as an Expression.
+ * Lazily computes the value and caches it in maxval/minval.
+ * Reports any errors.
+ * Params:
+ *      ed = the EnumDeclaration being examined
+ *      loc = location to use for error messages
+ *      id = Id::max or Id::min
+ * Returns:
+ *      corresponding value of .max/.min
+ */
+private Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
+{
+    //printf("EnumDeclaration::getMaxValue()\n");
+
+    static Expression pvalToResult(Expression e, const ref Loc loc)
+    {
+        if (e.op != TOK.error)
+        {
+            e = e.copy();
+            e.loc = loc;
+        }
+        return e;
+    }
+
+    Expression* pval = (id == Id.max) ? &ed.maxval : &ed.minval;
+
+    Expression errorReturn()
+    {
+        *pval = ErrorExp.get();
+        return *pval;
+    }
+
+    if (ed.inuse)
+    {
+        ed.error(loc, "recursive definition of `.%s` property", id.toChars());
+        return errorReturn();
+    }
+    if (*pval)
+        return pvalToResult(*pval, loc);
+
+    if (ed._scope)
+        dsymbolSemantic(ed, ed._scope);
+    if (ed.errors)
+        return errorReturn();
+    if (!ed.members)
+    {
+        if (ed.isSpecial())
+        {
+            /* Allow these special enums to not need a member list
+             */
+            return ed.memtype.getProperty(ed._scope, loc, id, 0);
+        }
+
+        ed.error(loc, "is opaque and has no `.%s`", id.toChars());
+        return errorReturn();
+    }
+    if (!(ed.memtype && ed.memtype.isintegral()))
+    {
+        ed.error(loc, "has no `.%s` property because base type `%s` is not an integral type",
+              id.toChars(), ed.memtype ? ed.memtype.toChars() : "");
+        return errorReturn();
+    }
+
+    bool first = true;
+    for (size_t i = 0; i < ed.members.dim; i++)
+    {
+        EnumMember em = (*ed.members)[i].isEnumMember();
+        if (!em)
+            continue;
+        if (em.errors)
+        {
+            ed.errors = true;
+            continue;
+        }
+
+        if (em.semanticRun < PASS.semanticdone)
+        {
+            em.error("is forward referenced looking for `.%s`", id.toChars());
+            ed.errors = true;
+            continue;
+        }
+
+        if (first)
+        {
+            *pval = em.value;
+            first = false;
+        }
+        else
+        {
+            /* In order to work successfully with UDTs,
+             * build expressions to do the comparisons,
+             * and let the semantic analyzer and constant
+             * folder give us the result.
+             */
+
+            /* Compute:
+             *   if (e > maxval)
+             *      maxval = e;
+             */
+            Expression e = em.value;
+            Expression ec = new CmpExp(id == Id.max ? TOK.greaterThan : TOK.lessThan, em.loc, e, *pval);
+            ed.inuse++;
+            ec = ec.expressionSemantic(em._scope);
+            ed.inuse--;
+            ec = ec.ctfeInterpret();
+            if (ec.op == TOK.error)
+            {
+                ed.errors = true;
+                continue;
+            }
+            if (ec.toInteger())
+                *pval = e;
+        }
+    }
+    return ed.errors ? errorReturn() : pvalToResult(*pval, loc);
+}
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 6b44bebd6c1..86578aa8c5f 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -2318,9 +2318,6 @@ public:
     Type *tb = e->type->toBasetype ();
     tree result;
 
-    if (e->allocator)
-      gcc_assert (e->newargs);
-
     if (tb->ty == TY::Tclass)
       {
 	/* Allocating a new class.  */
@@ -2340,15 +2337,6 @@ public:
 	    new_call = build_nop (type, build_address (var));
 	    setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
 	  }
-	else if (e->allocator)
-	  {
-	    /* Call class allocator, and copy the initializer into memory.  */
-	    new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
-	    new_call = d_save_expr (new_call);
-	    new_call = build_nop (type, new_call);
-	    setup_exp = modify_expr (build_deref (new_call),
-				     aggregate_initializer_decl (cd));
-	  }
 	else
 	  {
 	    /* Generate: _d_newclass()  */
@@ -2376,7 +2364,7 @@ public:
 		  {
 		    ClassDeclaration *ocd = outer->isClassDeclaration ();
 		    int offset = 0;
-		    gcc_assert (ocd->isBaseOf (tcd, &offset));
+		    gcc_assert (isBaseOf (ocd, tcd, &offset));
 		    /* Could just add offset...  */
 		    value = convert_expr (value, e->thisexp->type, ocd->type);
 		  }
@@ -2423,20 +2411,11 @@ public:
 	    return;
 	  }
 
-	if (e->allocator)
-	  {
-	    /* Call struct allocator.  */
-	    new_call = d_build_call_expr (e->allocator, NULL_TREE, e->newargs);
-	    new_call = build_nop (build_ctype (tb), new_call);
-	  }
-	else
-	  {
-	    /* Generate: _d_newitemT()  */
-	    libcall_fn libcall = htype->isZeroInit ()
-	      ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
-	    tree arg = build_typeinfo (e->loc, e->newtype);
-	    new_call = build_libcall (libcall, tb, 1, arg);
-	  }
+	/* Generate: _d_newitemT()  */
+	libcall_fn libcall = htype->isZeroInit ()
+	  ? LIBCALL_NEWITEMT : LIBCALL_NEWITEMIT;
+	tree arg = build_typeinfo (e->loc, e->newtype);
+	new_call = build_libcall (libcall, tb, 1, arg);
 
 	if (e->member || !e->arguments)
 	  {
@@ -2485,7 +2464,6 @@ public:
 	tb = e->newtype->toBasetype ();
 	TypeDArray *tarray = tb->isTypeDArray ();
 
-	gcc_assert (!e->allocator);
 	gcc_assert (e->arguments && e->arguments->length >= 1);
 
 	if (e->arguments->length == 1)
@@ -3073,7 +3051,7 @@ public:
 	    ClassDeclaration *from = e->originalClass ();
 	    int offset = 0;
 
-	    gcc_assert (to->isBaseOf (from, &offset) != 0);
+	    gcc_assert (isBaseOf (to, from, &offset) != 0);
 
 	    if (offset != 0)
 	      var = build_offset (var, size_int (offset));
diff --git a/gcc/d/lang-specs.h b/gcc/d/lang-specs.h
index 266e2a98265..2225677dafb 100644
--- a/gcc/d/lang-specs.h
+++ b/gcc/d/lang-specs.h
@@ -23,8 +23,7 @@ along with GCC; see the file COPYING3.  If not see
 {".di", "@d", 0, 1, 0 },
 {"@d",
   "%{!E:d21 %i %(cc1_options) %I %{nostdinc*} %{i*} %{I*} %{J*} \
-    %{H} %{Hd*} %{Hf*} %{HC} %{HCd*} %{HCf*} \
-    %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \
+    %{H} %{Hd*} %{Hf*} %{MD:-MD %b.deps} %{MMD:-MMD %b.deps} \
     %{M} %{MM} %{MF*} %{MG} %{MP} %{MQ*} %{MT*} \
     %{X:-Xf %b.json} %{Xf*} \
     %{v} %{!fsyntax-only:%(invoke_as)}}", 0, 1, 0 },
diff --git a/gcc/testsuite/gdc.test/compilable/b17111.d b/gcc/testsuite/gdc.test/compilable/b17111.d
index 6bf5da9f3e2..9e79a20780c 100644
--- a/gcc/testsuite/gdc.test/compilable/b17111.d
+++ b/gcc/testsuite/gdc.test/compilable/b17111.d
@@ -1,16 +1,7 @@
-/*
-TEST_OUTPUT:
----
-compilable/b17111.d(16): Deprecation: `case` variables have to be `const` or `immutable`
-compilable/b17111.d(17): Deprecation: `case` variables have to be `const` or `immutable`
----
-*/
 alias TestType = ubyte;
 
-void test()
+void test(immutable TestType a, immutable TestType b, TestType c)
 {
-    TestType a,b,c;
-
     switch(c)
     {
         case a: break;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d
index efb83ce4799..8242b98e89a 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_breaks.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_breaks.html
 
 /++
 # Thematic Breaks
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d
index 3a83223459d..1ff26b07499 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_breaks_verbose.d
@@ -1,15 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_breaks_verbose.d(21): Ddoc: converted '___' to a thematic break
-compilable/ddoc_markdown_breaks_verbose.d(21): Ddoc: converted '- - -' to a thematic break
-compilable/ddoc_markdown_breaks_verbose.d(21): Ddoc: converted '***' to a thematic break
-----
-*/
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_breaks_verbose.html
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_breaks_verbose.html
 
 /++
 Thematic Breaks
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d
index 7fed9ed0f84..56e6be36538 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code.d
@@ -1,12 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_code.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_code.html
 
 /++
 # Code Blocks
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d
index d2be2d274a7..eb64c04363d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_code_verbose.d
@@ -1,13 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_code_verbose.d(19): Ddoc: adding code block for language 'ruby'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_code_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_code_verbose.html
 
 /++
 Code:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d
index bef13c9d4c4..8bbcbdf91a3 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_emphasis.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_emphasis.html
 
 /++
 Markdown Emphasis:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d
index 68e936492a2..07904c1e42f 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_emphasis_verbose.d
@@ -1,14 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -wi -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_emphasis_verbose.d(20): Ddoc: emphasized text 'emphasized text'
-compilable/ddoc_markdown_emphasis_verbose.d(20): Ddoc: emphasized text 'strongly emphasized text'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_emphasis_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_emphasis_verbose.html
 
 /++
 Markdown Emphasis:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d
index 1fbe1c78042..4d8c8aeb945 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_escapes.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_escapes.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_escapes.html
 
 /++
 Backslash Escapes:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d
index 733a1b8cdfe..e7191f89769 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_headings.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_headings.html
 
 /++
 # ATX-Style Headings
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d
index 0717b7ba017..64484632b4e 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_headings_verbose.d
@@ -1,13 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_headings_verbose.d(15): Ddoc: added heading 'Heading'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_headings_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_headings_verbose.html
 
 /++
 # Heading
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d
index 0e3a99c57a2..349175b0484 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_links.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_links.html
 
 /++
 # Links
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d
index 5d8cffd388d..435b426e03e 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_links_verbose.d
@@ -1,18 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: found link reference 'dub' to 'https://code.dlang.org'
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: linking '[Object]' to '$(DOC_ROOT_object)object$(DOC_EXTENSION)#.Object'
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: linking '[the D homepage](https://dlang.org)' to 'https://dlang.org'
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: linking '[dub]' to 'https://code.dlang.org'
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: linking '[dub][]' to 'https://code.dlang.org'
-compilable/ddoc_markdown_links_verbose.d(28): Ddoc: linking '![D-Man](https://dlang.org/images/d3.png)' to 'https://dlang.org/images/d3.png'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_links_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_links_verbose.html
 
 /++
 Links:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d
index 00ef30649c5..1e5ff560d64 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_lists.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_lists.html
 
 /++
 # Lists
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d
index f3223f34d31..4fd1a80c58b 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_lists_verbose.d
@@ -1,13 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_lists_verbose.d(15): Ddoc: starting list item 'list item'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_lists_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_lists_verbose.html
 
 /++
 - list item
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d
index be9f7866c9f..27cfc430b8d 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote.d
@@ -1,12 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_quote.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_quote.html
 
 /++
 # Quote Blocks
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d
index 5490278b5f6..f16e5390ece 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_quote_verbose.d
@@ -1,13 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_quote_verbose.d(17): Ddoc: starting quote block with '> Great, just what I need.. another D in programming. -- Segfault'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_quote_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_quote_verbose.html
 
 /++
 Quote Block:
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d
index 1cda6640629..231364acc96 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables.d
@@ -1,12 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables.html
 
 /++
 # Tables
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d
index d7b3c388e1d..d1aac1cedf8 100644
--- a/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d
+++ b/gcc/testsuite/gdc.test/compilable/ddoc_markdown_tables_verbose.d
@@ -1,13 +1,7 @@
 // PERMUTE_ARGS:
 // REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o- -transition=vmarkdown
-// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
-
-/*
-TEST_OUTPUT:
-----
-compilable/ddoc_markdown_tables_verbose.d(19): Ddoc: formatting table '| this | that |'
-----
-*/
+// TEST_OUTPUT_FILE: extra-files/ddoc_markdown_tables_verbose.html
+// OUTPUT_FILES: ${RESULTS_DIR}/compilable/ddoc_markdown_tables_verbose.html
 
 /++
 Table:
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
index 9b1157d87eb..bcf5558054d 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
@@ -53,6 +53,15 @@ struct S final
         extern "C" void foo();
         void bar();
     };
+    struct
+    {
+        int32_t outerPrivate;
+    };
+    struct
+    {
+        int32_t innerPrivate;
+        int32_t innerBar;
+    };
     S()
     {
     }
@@ -77,6 +86,18 @@ extern (C++) struct S
         extern(C) void foo() {}
         extern(C++) void bar() {}
     }
+
+    // Private not emitted because AnonDeclaration has no protection
+    private struct
+    {
+        int outerPrivate;
+    }
+
+    public struct {
+        // Private cannot be exported to C++
+        private int innerPrivate;
+        int innerBar;
+    }
 }
 
 extern (D)
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d
index 76acfc117cb..483e58f6ae5 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_forwarding.d
@@ -42,7 +42,6 @@ struct _d_dynamicArray final
 struct Child;
 class Struct;
 enum class Enum;
-struct OuterStruct;
 class ExternDClass;
 struct ExternDStruct;
 template <typename T>
@@ -51,12 +50,27 @@ template <typename T>
 class TemplStruct;
 template <typename T>
 class ExternDTemplClass;
+struct OnlyByRef;
 
 struct Parent
 {
     virtual void bar();
 };
 
+struct OuterStruct final
+{
+    struct NestedStruct final
+    {
+        NestedStruct()
+        {
+        }
+    };
+
+    OuterStruct()
+    {
+    }
+};
+
 struct ExternDStructRequired final
 {
     int32_t member;
@@ -104,20 +118,6 @@ enum class Enum
 
 extern OuterStruct::NestedStruct* nestedStrPtr;
 
-struct OuterStruct final
-{
-    struct NestedStruct final
-    {
-        NestedStruct()
-        {
-        }
-    };
-
-    OuterStruct()
-    {
-    }
-};
-
 extern ExternDClass* externDClassPtr;
 
 extern ExternDStruct* externDStrPtr;
@@ -148,6 +148,8 @@ extern ExternDTemplClass<int32_t >* externTemplClass;
 
 extern ExternDTemplStruct<int32_t > externTemplStruct;
 
+extern void foo(OnlyByRef& obr);
+
 ---
 */
 
@@ -255,3 +257,9 @@ extern(D) struct ExternDTemplStruct(T)
 {
     T member;
 }
+
+//******************************************************
+
+extern(D) struct OnlyByRef {}
+
+void foo(ref OnlyByRef obr) {}
diff --git a/gcc/testsuite/gdc.test/compilable/header18364.d b/gcc/testsuite/gdc.test/compilable/header18364.d
index 77df1d0d2ad..c7e1e67c7ae 100644
--- a/gcc/testsuite/gdc.test/compilable/header18364.d
+++ b/gcc/testsuite/gdc.test/compilable/header18364.d
@@ -1,5 +1,21 @@
-// REQUIRED_ARGS: -o- -Hf${RESULTS_DIR}/compilable/header18364.di
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+REQUIRED_ARGS: -o- -Hf${RESULTS_DIR}/compilable/header18364.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/header18364.di
+
+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) 
+{
+	void foo();
+	nothrow pure @nogc @safe package(foo.bar) void foo2();
+}
+---
+*/
+
 module foo.bar.ba;
 @safe pure nothrow @nogc package(foo):
 void foo();
diff --git a/gcc/testsuite/gdc.test/compilable/header18365.d b/gcc/testsuite/gdc.test/compilable/header18365.d
index e01b4cdd8e5..7e51fb26cc7 100644
--- a/gcc/testsuite/gdc.test/compilable/header18365.d
+++ b/gcc/testsuite/gdc.test/compilable/header18365.d
@@ -1,5 +1,26 @@
-// REQUIRED_ARGS: -c -o- -Hf${RESULTS_DIR}/compilable/header18365.di
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+REQUIRED_ARGS: -c -o- -Hf${RESULTS_DIR}/compilable/header18365.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/header18365.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/header18365.di
+// D import file generated from 'compilable/header18365.d'
+struct FullCaseEntry
+{
+	dchar[3] seq;
+	ubyte n;
+	ubyte size;
+	ubyte entry_len;
+	auto const pure nothrow @nogc @property @trusted value() return
+	{
+		return seq[0..entry_len];
+	}
+}
+---
+*/
+
 struct FullCaseEntry
 {
     dchar[3] seq;
diff --git a/gcc/testsuite/gdc.test/compilable/imports/imp22122.d b/gcc/testsuite/gdc.test/compilable/imports/imp22122.d
new file mode 100644
index 00000000000..b29bae0bb6f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/imp22122.d
@@ -0,0 +1,5 @@
+module imports.imp22122;
+
+package struct Imp22122
+{
+}
diff --git a/gcc/testsuite/gdc.test/compilable/interpret3.d b/gcc/testsuite/gdc.test/compilable/interpret3.d
index cd355538eee..ff85856b62e 100644
--- a/gcc/testsuite/gdc.test/compilable/interpret3.d
+++ b/gcc/testsuite/gdc.test/compilable/interpret3.d
@@ -2,8 +2,7 @@
 /*
 TEST_OUTPUT:
 ---
-compilable/interpret3.d(2914): Deprecation: `case` variables have to be `const` or `immutable`
-compilable/interpret3.d(6351): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
+compilable/interpret3.d(6350): Deprecation: identity comparison of static arrays implicitly coerces them to slices, which are compared by reference
 ---
 */
 
@@ -2904,16 +2903,16 @@ static assert(bug4448b() == 3);
 
 /**************************************************/
 // https://issues.dlang.org/show_bug.cgi?id=6985
-// non-constant case
+// Formerly, non-constant case, but switch cases with mutable cases now error
+// Currently: run-time constant variable case
 
 int bug6985(int z)
 {
-    int q = z * 2 - 6;
+    const int q = z * 2 - 6;
     switch(z)
     {
     case q:
-        q = 87;
-        break;
+        return 87;
     default:
     }
     return q;
diff --git a/gcc/testsuite/gdc.test/compilable/test17143.d b/gcc/testsuite/gdc.test/compilable/test17143.d
index 98e31f4c324..4ec029572f4 100644
--- a/gcc/testsuite/gdc.test/compilable/test17143.d
+++ b/gcc/testsuite/gdc.test/compilable/test17143.d
@@ -1,4 +1,16 @@
-import std.typecons : tuple;
+// https://issues.dlang.org/show_bug.cgi?id=17143
+
+struct Tuple(T...)
+{
+    T values;
+    alias expand = values;
+}
+
+Tuple!T tuple(T...)(T args)
+{
+    return Tuple!T(args);
+}
+
 enum foo = tuple(1, 2).expand;
 static assert(typeof(foo).stringof == "(int, int)");
 static assert(foo.stringof == "tuple(1, 2)");
diff --git a/gcc/testsuite/gdc.test/compilable/test20367.d b/gcc/testsuite/gdc.test/compilable/test20367.d
index a6a171f4a42..ebdf9ee5b8d 100644
--- a/gcc/testsuite/gdc.test/compilable/test20367.d
+++ b/gcc/testsuite/gdc.test/compilable/test20367.d
@@ -1,7 +1,5 @@
 // https://issues.dlang.org/show_bug.cgi?id=20367
 
-import std.stdio;
-
 struct A
 {
 	int x;
diff --git a/gcc/testsuite/gdc.test/compilable/test22122.d b/gcc/testsuite/gdc.test/compilable/test22122.d
new file mode 100644
index 00000000000..a06d06c787d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22122.d
@@ -0,0 +1,53 @@
+// EXTRA_FILES: imports/imp22122.d
+module imports.test22122;
+
+struct S22122
+{
+    import imports.imp22122;
+    Variant!(Imp22122)[] array;
+}
+
+void test22122_catch(S22122 s)
+{
+    try
+    {
+        foreach(elem; s.array)
+        {
+            import imports.imp22122;
+            with(elem.get!Imp22122)
+            {
+            }
+        }
+    }
+    catch (Exception)
+    {
+    }
+}
+
+void test22122_finally(S22122 s)
+{
+    try
+    {
+        foreach(elem; s.array)
+        {
+            import imports.imp22122;
+            with(elem.get!Imp22122)
+            {
+            }
+        }
+    }
+    finally
+    {
+    }
+}
+
+private struct Variant(T)
+{
+    union Impl
+    {
+    }
+    auto get(E)()
+    {
+        return Impl();
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/testcstuff1.c b/gcc/testsuite/gdc.test/compilable/testcstuff1.c
deleted file mode 100644
index 271edaeca0d..00000000000
--- a/gcc/testsuite/gdc.test/compilable/testcstuff1.c
+++ /dev/null
@@ -1,499 +0,0 @@
-// check the expression parser
-
-_Static_assert(0 == 0, "ok");
-_Static_assert(0 != 1, "ok");
-_Static_assert(1 + 2 == 3, "ok");
-_Static_assert(1 - 2 == -1, "ok");
-_Static_assert(3 * 4 == 12, "ok");
-_Static_assert(10 / 2 == 5, "ok");
-_Static_assert(10 % 3 == 1, "ok");
-_Static_assert(2 << 3 == 16, "ok");
-_Static_assert(16 >> 3 == 2, "ok");
-_Static_assert((2 | 1) == 3, "ok");
-_Static_assert((3 & 1) == 1, "ok");
-_Static_assert((3 ^ 1) == 2, "ok");
-_Static_assert(-(3 ^ 1) == -+2, "ok");
-_Static_assert(~1 == 0xFFFFFFFE, "ok");
-_Static_assert(!3 == 0, "ok");
-_Static_assert(!0 == 1, "ok");
-_Static_assert(6.0f == 6.0, "in");
-_Static_assert(6.0F == 6.0, "in");
-_Static_assert(6.0l == 6.0, "in");
-_Static_assert(6.0L == 6.0, "in");
-
-_Static_assert(sizeof(char) == 1, "ok");
-_Static_assert(sizeof(char signed) == 1, "ok");
-_Static_assert(sizeof(unsigned char) == 1, "ok");
-
-_Static_assert(sizeof(short) == 2, "ok");
-_Static_assert(sizeof(int short) == 2, "ok");
-_Static_assert(sizeof(signed short) == 2, "ok");
-_Static_assert(sizeof(signed short int) == 2, "ok");
-
-_Static_assert(sizeof(short unsigned) == 2, "ok");
-_Static_assert(sizeof(unsigned short int) == 2, "ok");
-
-_Static_assert(sizeof(int) == 4, "ok");
-_Static_assert(sizeof(signed) == 4, "ok");
-_Static_assert(sizeof(signed int) == 4, "ok");
-
-_Static_assert(sizeof(int unsigned) == 4, "ok");
-_Static_assert(sizeof(unsigned) == 4, "ok");
-
-_Static_assert(sizeof(long) >= 4, "ok");
-_Static_assert(sizeof(signed long) >= 4, "ok");
-_Static_assert(sizeof(int long) <= 8, "ok");
-_Static_assert(sizeof(long signed int) <= 8, "ok");
-
-_Static_assert(sizeof(int unsigned long) >= 4, "ok");
-_Static_assert(sizeof(long unsigned) <= 8, "ok");
-
-_Static_assert(sizeof(long long) == 8, "ok");
-_Static_assert(sizeof(int long long) == 8, "ok");
-_Static_assert(sizeof(long signed long) == 8, "ok");
-_Static_assert(sizeof(long long signed int) == 8, "ok");
-
-_Static_assert(sizeof(unsigned long long) == 8, "ok");
-_Static_assert(sizeof(int long unsigned long) == 8, "ok");
-
-_Static_assert(sizeof(float) == 4, "ok");
-_Static_assert(sizeof(double) == 8, "ok");
-//_Static_assert(sizeof(long double) == 8 || sizeof(long double) == 10 || sizeof(long double) == 16, "ok");
-
-_Static_assert(sizeof(const restrict volatile char volatile restrict const) == 1, "ok");
-
-_Static_assert(sizeof(int*) == 8 || 4 == sizeof(char*), "ok");
-
-_Static_assert(sizeof(int[10][20]) == 20 * (10 * 4), "ok");
-
-/**********************************************/
-
-_Static_assert(07 == 7, "ok");
-_Static_assert(071 == 57, "ok");
-_Static_assert(0 == 0, "ok");
-
-_Static_assert(1u == 1l, "ok");
-_Static_assert(1U == 1L, "ok");
-_Static_assert(1Ul == 1L, "ok");
-
-_Static_assert(1ull == 1LL, "ok");
-_Static_assert(1llu == 1ull, "ok");
-
-_Static_assert(sizeof(1) == 4, "ok");
-_Static_assert(sizeof(0x1) == 4, "ok");
-_Static_assert(sizeof(1u) == 4, "ok");
-_Static_assert(sizeof(0x1u) == 4, "ok");
-_Static_assert(sizeof(1l) == 4  || sizeof(1l) == 8, "ok");
-_Static_assert(sizeof(1ul) == 4 || sizeof(1ul) == 8, "ok");
-_Static_assert(sizeof(0x1l) == 4  || sizeof(0x1L) == 8, "ok");
-_Static_assert(sizeof(0x1ul) == 4 || sizeof(0x1UL) == 8, "ok");
-_Static_assert(sizeof(1ll) == 8, "ok");
-_Static_assert(sizeof(1ull) == 8, "ok");
-_Static_assert(sizeof(0x1ull) == 8, "ok");
-
-_Static_assert(sizeof(0x8000000000000000LL) == 8, "ok");
-_Static_assert(sizeof(0x1LL) == 8, "ok");
-_Static_assert(sizeof(0x8000000000000000) == 8, "ok");
-_Static_assert(sizeof(0x7FFFFFFF00000000) == 8, "ok");
-_Static_assert(sizeof(9223372036854775808) == 8, "ok");
-_Static_assert(sizeof(9223372032559808512) == 8, "ok");
-_Static_assert(sizeof(0xFFFFFFFF00000000U) == 8, "ok");
-
-_Static_assert(sizeof(0x8000000000000000L) == 8, "ok");
-
-/**********************************************/
-
-int f1(i, j)
-int i;
-int j;
-{
-    return i + 3;
-}
-
-_Static_assert(f1(4, 2) == 7, "ok");
-
-/**********************************************/
-
-enum E1 { M1, M2, M3, M4 = 7, M5, };
-enum E2 { M6 };
-
-_Static_assert(M3 == 2, "ok");
-_Static_assert(M5 == 8, "ok");
-
-/**********************************************/
-
-int s1(int i)
-{
-    while (i < 10) ++i;
-    return i;
-}
-
-_Static_assert(s1(3) == 10, "s1(3) == 10");
-
-int s2(int i)
-{
-    for (; i < 10; ++i);
-    return i;
-}
-
-_Static_assert(s2(3) == 10, "s2(3) == 10");
-
-int s3(int i)
-{
-    do
-    {
-        ++i;
-    } while (i < 10);
-    return i;
-}
-
-_Static_assert(s3(3) == 10, "s3(3) == 10");
-
-int s4(int i)
-{
-    switch (i)
-    {
-        case 1: break;
-        case 2+1: i = 10; break;
-        default: i = 11; break;
-    }
-    return i;
-}
-
-_Static_assert(s4(1) ==  1, "s4(1) == 1");
-_Static_assert(s4(3) == 10, "s4(3) == 10");
-_Static_assert(s4(5) == 11, "s4(5) == 11");
-
-int s5(int i)
-{
-    if (i == 3)
-        return 4;
-    else
-        return 5;
-}
-
-_Static_assert(s5(3) == 4, "s5(3) == 4");
-_Static_assert(s5(4) == 5, "s5(4) == 5");
-
-/********************************/
-
-void tokens()
-<%
-    char c = 'c';
-    unsigned short w = L'w';
-    //unsigned short* ws = L"wstring";
-    int LLL1[1];
-    int LLL2<:1:>;
-%>
-
-/********************************/
-
-int testexpinit()
-{
-    int i = 1;
-    int j = { 2 };
-    int k = { 3 , };
-    return i + j + k;
-}
-
-_Static_assert(testexpinit() == 1 + 2 + 3, "ok");
-
-/********************************/
-
-// Character literals
-_Static_assert(sizeof('a') == 4, "ok");
-_Static_assert(sizeof(u'a') == 4, "ok");
-_Static_assert(sizeof(U'a') == 4, "ok");
-_Static_assert('a' == 0x61, "ok");
-_Static_assert('ab' == 0x6162, "ok");
-_Static_assert('abc' == 0x616263, "ok");
-_Static_assert('abcd' == 0x61626364, "ok");
-_Static_assert(u'a' == 0x61, "ok");
-_Static_assert(u'ab' == 0x610062, "ok");
-_Static_assert(U'a' == 0x61, "ok");
-_Static_assert(u'\u1234' == 0x1234, "ok");
-_Static_assert(U'\U00011234' == 0x11234, "ok");
-_Static_assert(L'\u1234' == 0x1234, "ok");
-
-/********************************/
-
-void test__func__()
-{
-    _Static_assert((sizeof __func__) == 13, "ok");
-}
-
-void teststringtype()
-{
-    char* p = "hello";
-    unsigned short* up = u"hello";
-    unsigned int* Up = U"hello";
-}
-
-/********************************/
-
-char s[] = "hello";
-_Static_assert(sizeof(s) == 6, "in");
-
-/********************************/
-
-struct SA { int a, b, *const c, d[50]; };
-
-int test1(int i)
-{
-  L1:
-    ++i;
-  L2:
-    { --i; }
-    return i;
-}
-
-_Static_assert(test1(5) == 5, "ok");
-
-void test2()
-{
-    int;
-    int (*xi);
-    int (*fp)(void);
-    int (* const volatile restrict fp2)(void);
-    void* pv;
-    char c, d;
-    short sh;
-    int j;
-    long l;
-    signed s;
-    unsigned u;
-    //_Complex double co;
-    _Bool b;
-    typedef int TI;
-    //extern int ei;
-    static int si;
-    _Thread_local int tli;
-    auto int ai;
-    register int reg;
-    const int ci;
-    volatile int vi;
-    restrict int ri;
-
-//    _Atomic(int) ai;
-//    _Alignas(c) ac;
-
-    void * const volatile restrict q;
-
-    inline int f();
-    _Noreturn void g();
-
-    _Static_assert(1, "ok");
-}
-
-void test3(int i)
-{
-    for (i = 0; ;)
-    {
-    }
-    for (int j = 0; ;)
-    {
-        continue;
-    }
-    if (i == 3)
-        i = 4;
-    else
-        i = 5;
-    if (i == 4)
-        i = 6;
-    goto L1;
-  L1: ;
-    { L2: }
-}
-
-void test4(int i)
-{
-    i = 4, i = 5;
-    float f = 1.0f + 3;
-    double d = 1.0 + 4;
-    char c = 'c';
-    //char* s = __func__;
-    int* p = &i;
-    i = *p;
-    _Static_assert(sizeof 3 == 4, "ok");
-    _Static_assert(sizeof(3) == 4, "ok");
-    _Static_assert(_Alignof(int) == 4, "ok");
-    _Static_assert((int)3 == 3, "ok");
-    _Static_assert(sizeof p[0] == 4, "ok");
-    _Static_assert(1 && 2, "ok");
-    _Static_assert((1 ? 2 : 3) == 2, "ok");
-    _Static_assert((0 ? 2 : 3) == 3, "ok");
-
-    i += 2;
-    i -= 2;
-    i *= 2;
-    i /= 2;
-    i %= 2;
-    i &= 2;
-    i |= 2;
-    i ^= 2;
-    i <<= 2;
-    i >>= 2;
-    i++;
-    i--;
-    p[0]++;
-    *p = 3;
-    (++i);
-    long long ll = 12L;
-    ll = 12UL;
-    long double ld = 1.0L;
-    const char* s = "hello" "betty";
-}
-
-/********************************/
-
-void parenExp(int a, int b)
-{
-    char* q = (char*)"hello";
-    if (!(a == b))
-        a = b;
-    if ((int)3 == 3);
-        a = b;
-    if ((a) == b)
-        a = b;
-    a = (int) (1 << (b));
-    typedef int t;
-    int* p;
-    a = a + (t)*p;
-}
-
-/********************************/
-
-struct SS { int a; };
-
-int tests1()
-{
-    struct SS s;
-    return s.a;
-}
-
-int tests2()
-{
-    struct T { int a; };
-    struct T t;
-    return t.a;
-}
-
-void* tests3()
-{
-    struct T1 *p;
-    return p;
-}
-
-int tests4()
-{
-    struct S { int b; } a, *p;
-    a.b = 3;
-    p = &a;
-    return p->b;
-}
-
-int test5()
-{
-    struct { int a; };
-    struct S
-    {
-        int a;
-        struct { int b, c; };
-    } s;
-    return s.a + s.b + s.c;
-}
-
-/********************************/
-
-int test16997()
-{
-    /* Exhaustively test all signed and unsigned byte promotions for
-     * - + and ~
-     */
-    for (int i = 0; i < 256; ++i)
-    {
-        unsigned char c = (unsigned char)i;
-
-        int i1 = (int) (~c);
-        int i2 = (int) (~(int) c);
-
-        //printf("%d, %d\n", i1, i2);
-        if (i1 != i2) return 0;
-
-        i1 = (int) (+c);
-        i2 = (int) (+(int) c);
-        if (i1 != i2) return 0;
-
-        i1 = (int) (-c);
-        i2 = (int) (-(int) c);
-        if (i1 != i2) return 0;
-    }
-
-    for (int i = 0; i < 256; ++i)
-    {
-        signed char c = (signed char)i;
-
-        int i1 = (int) (~c);
-        int i2 = (int) (~(int) c);
-
-        //printf("%d, %d\n", i1, i2);
-        if (i1 != i2) return 0;
-
-        i1 = (int) (+c);
-        i2 = (int) (+(int) c);
-        if (i1 != i2) return 0;
-
-        i1 = (int) (-c);
-        i2 = (int) (-(int) c);
-        if (i1 != i2) return 0;
-    }
-    return 1;
-}
-
-_Static_assert(test16997(), "in");
-
-/********************************/
-
-struct SH { int a; };
-int SH;
-int SJ;
-struct SJ { int a; };
-
-void testtags()
-{
-    struct SH h;
-    h.a = SH;
-    struct SJ j;
-    j.a = SJ;
-
-    struct SK { int a; };
-    int SK;
-    struct SK k;
-    k.a = SK;
-
-    int SL;
-    struct SL { int a; };
-    struct SL l;
-    l.a = SL;
-}
-
-/********************************/
-
-int printf(const char*, ...);
-
-int main()
-{
-    printf("hello world\n");
-}
-
-#line 1000
-%:line 1010
-
-# 1020 "cstuff1.c" 1 2 3 4
-# 1030
-struct S21944
-{
-    int var;
-#1040 "cstuff1.c" 3 4
-};
-
diff --git a/gcc/testsuite/gdc.test/compilable/testcstuff2.c b/gcc/testsuite/gdc.test/compilable/testcstuff2.c
deleted file mode 100644
index a500d4f7b88..00000000000
--- a/gcc/testsuite/gdc.test/compilable/testcstuff2.c
+++ /dev/null
@@ -1,313 +0,0 @@
-// check bugs in the expression parser
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21931
-
-typedef long int T21931a;
-typedef T21931a T21931b;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21933
-
-struct S21933 { void *opaque; };
-int test21933(struct S21933 *);
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21934
-
-typedef int T21934 asm("realtype");
-int init21934 asm("realsym") = 1;
-int var21934 asm("realvsym");
-int fun21934() asm("realfun");
-
-void test21934()
-{
-    typedef int asmreg;
-    register asmreg r1 asm("r1");
-    // asm ignored by C compiler, should be disallowed?
-    asmreg r2 asm("r2");
-
-    register asmreg r3 asm("r3") = 3;
-    // asm ignored by C compiler, should be disallowed?
-    asmreg r4 asm("r4") = 4;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21937
-
-__attribute__(()) int test21937a();
-int test21937b() __attribute__(( , nothrow, hot, aligned(2), ));
-int test21937c() __attribute__((nothrow , leaf)) __attribute__((noreturn));
-
-__attribute__((noinline))
-void test21937d()
-{
-    typedef int attr_var_t;
-    attr_var_t attr_local __attribute__((unused));
-}
-
-__attribute__((aligned)) int test21937e;
-int test21937f __attribute__((aligned));
-
-struct __attribute__((packed)) S21937a
-{
-    __attribute__((deprecated("msg"))) char c;
-    int i __attribute__((deprecated));
-};
-
-struct S21937b
-{
-    __attribute__((deprecated("msg"))) char c;
-    int i __attribute__((deprecated));
-} __attribute__((packed));
-
-enum __attribute__((aligned)) E21937a
-{
-    E21937a_A,
-};
-
-enum E21937b
-{
-    E21937b_A,
-} __attribute__((aligned));
-
-typedef int T21937a __attribute__((unused));
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21945
-
-typedef struct {
-    long var;
-} S21945;
-S21945 test21945a;
-
-typedef enum {
-    E21945_member,
-} E21945;
-E21945 test21945b;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21948
-
-void test21948()
-{
-    typedef int myint;
-    typedef struct { int f; } mystruct;
-
-    myint var1;
-    myint var2 = 12;
-    mystruct var3;
-    // Uncomment when bug fixed https://issues.dlang.org/show_bug.cgi?id=21979
-    //mystruct var4 = { 34 };
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21963
-
-union U21963
-{
-    int iv;
-    float fv;
-};
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21965
-
-struct { int var; };
-typedef struct { int var; };
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21967
-
-const int test21967a(void);
-const int *test21967b(void);
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21968
-
-struct S21968
-{
-    struct inner *data[16];
-};
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21970
-
-extern int test21970a;
-extern char *test21970b;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21973
-
-struct S21973
-{
-    int field;
-    struct
-    {
-        int nested;
-    };
-};
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21977
-int test21977a;
-_Thread_local int test21977b;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=21982
-
-struct S21982 { int field; };
-struct S21982 test21982;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22028
-
-struct S22028
-{
-    struct nested
-    {
-        int field;
-    };
-    const int cfield;
-    _Static_assert(1 == 1, "ok");
-};
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22060
-
-struct S22060;
-typedef struct S22060 T22060a;
-struct S22060;
-typedef struct S22060 T22060b;
-struct S22060;
-struct S22060
-{
-    int _flags;
-};
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22061
-
-union S22061
-{
-    int field;
-};
-typedef union S22061 S22061;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22063
-
-typedef struct S22063_t
-{
-    int field;
-} S22063;
-
-void test22063()
-{
-    // BUG: no definition of struct
-    //struct S22063_t v1 = { 0 };
-    // BUG: cannot implicitly cast from integer to pointer.
-    struct S22063_t *v2 = (struct S22063_t *)0;
-    S22063 v3 = { 0 };
-    S22063 *v4 = (S22063 *)0;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22066
-
-void test22066()
-{
-  int var = 0;
-  (var)++;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22067
-
-void test22067()
-{
-    union U {
-        int value;
-        char *ptr;
-        char array[4];
-    } var;
-    union U *pvar = &var;
-    var.value = 0xabcdef;
-    var.array[0]++;
-    (*var.ptr)--;
-    ++(*pvar).value;
-    --(*pvar).array[3];
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22073
-
-struct S22073a { int field; };
-struct S22073b { const char *field; };
-
-_Static_assert((struct S22073a){6789}.field == 6789, "ok");
-_Static_assert((struct S22073b){"zxcv"}.field[2] == 'c', "ok");
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22079
-
-struct S22079
-{
-    int a, b, c;
-};
-
-_Static_assert(sizeof(struct S22079){1,2,3} == sizeof(int)*3, "ok");
-_Static_assert(sizeof(struct S22079){1,2,3}.a == sizeof(int), "ok");
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22080
-
-int F22080(const char *);
-
-int test22080()
-{
-    int (*fun)(const char *) = &F22080;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22086
-typedef union U22086 U22086;
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22088
-
-void test22088()
-{
-    int *p;
-    int i;
-    p = i;
-    i = p;
-
-    void *pv;
-    p = pv;
-    pv = p;
-
-    long long ll;
-    ll = i;
-    i = ll;
-
-    char c;
-    c = i;
-    i = c;
-
-    float f;
-    f = i;
-    i = f;
-
-    double d;
-    d = i;
-    i = d;
-
-    long double ld;
-    ld = i;
-    i = ld;
-    c = ld;
-}
-
-/***************************************************/
-
diff --git a/gcc/testsuite/gdc.test/compilable/testheader1.d b/gcc/testsuite/gdc.test/compilable/testheader1.d
index 9d4cd483cb1..9b14f7b0d34 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader1.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader1.d
@@ -1,12 +1,9 @@
-// EXTRA_SOURCES: extra-files/header1.d
-// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader1.di -ignore
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
 /*
-TEST_OUTPUT:
----
-Hello World
----
+EXTRA_SOURCES: extra-files/header1.d
+REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader1.di -ignore
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader1.di
+TEST_OUTPUT_FILE: extra-files/header1.di
 */
 
 void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567a.d b/gcc/testsuite/gdc.test/compilable/testheader12567a.d
index dcbcd37ca30..3372d871ea6 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader12567a.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader12567a.d
@@ -1,6 +1,16 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567a.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567a.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader12567a.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader12567a.di
+// D import file generated from 'compilable/testheader12567a.d'
+deprecated module header12567a;
+void main();
+---
+*/
 
 deprecated module header12567a;
 
diff --git a/gcc/testsuite/gdc.test/compilable/testheader12567b.d b/gcc/testsuite/gdc.test/compilable/testheader12567b.d
index 873a8fad049..f17a37eeea5 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader12567b.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader12567b.d
@@ -1,6 +1,16 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567b.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader12567b.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader12567b.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader12567b.di
+// D import file generated from 'compilable/testheader12567b.d'
+deprecated("message") module header12567b;
+void main();
+---
+*/
 
 deprecated("message") module header12567b;
 
diff --git a/gcc/testsuite/gdc.test/compilable/testheader1i.d b/gcc/testsuite/gdc.test/compilable/testheader1i.d
index 236d3f82582..f79a1af4027 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader1i.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader1i.d
@@ -1,12 +1,9 @@
-// EXTRA_SOURCES: extra-files/header1.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader1i.di -inline -ignore
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
 /*
-TEST_OUTPUT:
----
-Hello World
----
+EXTRA_SOURCES: extra-files/header1.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader1i.di -inline -ignore
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader1i.di
+TEST_OUTPUT_FILE: extra-files/header1i.di
 */
 
 void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader2.d b/gcc/testsuite/gdc.test/compilable/testheader2.d
index a061530d857..25cc3c933da 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader2.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader2.d
@@ -1,6 +1,9 @@
-// EXTRA_SOURCES: extra-files/header2.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+EXTRA_SOURCES: extra-files/header2.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader2.di
+TEST_OUTPUT_FILE: extra-files/header2.di
+*/
 
 void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader2i.d b/gcc/testsuite/gdc.test/compilable/testheader2i.d
index ec1f3c2c931..517fae41d53 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader2i.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader2i.d
@@ -1,6 +1,9 @@
-// EXTRA_SOURCES: extra-files/header2.d
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2i.di -inline
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+EXTRA_SOURCES: extra-files/header2.d
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheader2i.di -inline
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader2i.di
+TEST_OUTPUT_FILE: extra-files/header2i.di
+*/
 
 void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheader3.d b/gcc/testsuite/gdc.test/compilable/testheader3.d
index 0aac4fbc945..be38d7c76ee 100644
--- a/gcc/testsuite/gdc.test/compilable/testheader3.d
+++ b/gcc/testsuite/gdc.test/compilable/testheader3.d
@@ -1,8 +1,27 @@
-// EXTRA_SOURCES: extra-files/header3.d
-// REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader3.di
-// PERMUTE_ARGS: -d -dw
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
-
-void main() {}
+/*
+EXTRA_SOURCES: extra-files/header3.d
+REQUIRED_ARGS: -o- -unittest -H -Hf${RESULTS_DIR}/compilable/testheader3.di
+PERMUTE_ARGS: -d -dw
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheader3.di
 
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheader3.di
+// D import file generated from 'compilable/extra-files/header3.d'
+auto elseifchain()
+{
+	bool a, b, c;
+	if (a)
+	{
+	}
+	else if (b)
+	{
+	}
+	else if (c)
+	{
+	}
+}
+---
+*/
 
+void main() {}
diff --git a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
index b0d4515f96d..b6b0ed1a278 100644
--- a/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
+++ b/gcc/testsuite/gdc.test/compilable/testheaderudamodule.d
@@ -1,6 +1,22 @@
-// REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/header-postscript.sh
+/*
+REQUIRED_ARGS: -o- -H -Hf${RESULTS_DIR}/compilable/testheaderudamodule.di
+PERMUTE_ARGS:
+OUTPUT_FILES: ${RESULTS_DIR}/compilable/testheaderudamodule.di
+
+TEST_OUTPUT:
+---
+=== ${RESULTS_DIR}/compilable/testheaderudamodule.di
+// D import file generated from 'compilable/testheaderudamodule.d'
+@(1, UDA(2))
+module testheaderudamodule;
+struct UDA
+{
+	int a;
+}
+void main();
+void foo(@(1) int bar, @UDA(2) string bebe);
+---
+*/
 
 @(1, UDA(2))
 module testheaderudamodule;
diff --git a/gcc/testsuite/gdc.test/compilable/vcg-ast.d b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
index bfcaf83d572..61767cc60d6 100644
--- a/gcc/testsuite/gdc.test/compilable/vcg-ast.d
+++ b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
@@ -1,7 +1,11 @@
+/*
+REQUIRED_ARGS: -vcg-ast -o-
+PERMUTE_ARGS:
+OUTPUT_FILES: compilable/vcg-ast.d.cg
+TEST_OUTPUT_FILE: extra-files/vcg-ast.d.cg
+*/
+
 module vcg;
-// REQUIRED_ARGS: -vcg-ast -o-
-// PERMUTE_ARGS:
-// POST_SCRIPT: compilable/extra-files/vcg-ast-postscript.sh
 
 template Seq(A...)
 {
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cconst1.c b/gcc/testsuite/gdc.test/fail_compilation/cconst1.c
deleted file mode 100644
index 50bf17f58bc..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/cconst1.c
+++ /dev/null
@@ -1,21 +0,0 @@
-/* TEST_OUTPUT:
----
-fail_compilation/cconst1.c(104): Error: cannot modify `const` expression `i`
-fail_compilation/cconst1.c(106): Error: cannot modify `const` expression `j`
-fail_compilation/cconst1.c(108): Error: cannot modify `const` expression `p`
----
-*/
-
-#line 100
-
-void test100()
-{
-    const int i;
-    ++i;
-    int const j;
-    ++j;
-    int *const p;
-    ++p;
-    int *const x, y;
-    ++y; // this should pass
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d b/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d
index 93d3e038e46..326d82e0718 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_class_alloc.d
@@ -1,7 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag_class_alloc.d(13): Error: class allocators are obsolete, consider moving the allocation strategy outside of the class
+fail_compilation/diag_class_alloc.d(15): Error: `new` allocator must be annotated with `@disabled`
+fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with non-empty parameter list is deprecated
+fail_compilation/diag_class_alloc.d(16): Deprecation: `new` allocator with function definition is deprecated
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/disable_new.d b/gcc/testsuite/gdc.test/fail_compilation/disable_new.d
index d5f1ecf074e..33ae32c2d8a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/disable_new.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/disable_new.d
@@ -1,8 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/disable_new.d(23): Error: allocator `disable_new.C.new` cannot be used because it is annotated with `@disable`
-fail_compilation/disable_new.d(24): Error: allocator `disable_new.S.new` cannot be used because it is annotated with `@disable`
+fail_compilation/disable_new.d(23): Error: cannot allocate `class C` with `new` because it is annotated with `@disable new()`
+fail_compilation/disable_new.d(24): Error: cannot allocate `struct S` with `new` because it is annotated with `@disable new()`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11038.d b/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
index 8f39ccc51eb..331c3fc5892 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11038.d
@@ -2,16 +2,16 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail11038.d(16): Error: `writeln` is not defined, perhaps `import std.stdio;` is needed?
+fail_compilation/fail11038.d(16): Error: `printf` is not defined, perhaps `import core.stdc.stdio;` is needed?
 ---
 */
 
 static
 {
-    import std.stdio;
+    import core.stdc.stdio;
 }
 
 void main()
 {
-    writeln("foo");  // compiles
+    printf("foo");  // compiles
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20033.d b/gcc/testsuite/gdc.test/fail_compilation/fail20033.d
index 8d8dbd5cec0..f641469c3dc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20033.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20033.d
@@ -2,17 +2,22 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail20033.d(36): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
-fail_compilation/fail20033.d(37): Deprecation: `alias byKeyValue this` is deprecated
-fail_compilation/fail20033.d(39): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
-fail_compilation/fail20033.d(40): Deprecation: `alias byKeyValue this` is deprecated
+fail_compilation/fail20033.d(38): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
+fail_compilation/fail20033.d(39): Deprecation: `alias byKeyValue this` is deprecated
+fail_compilation/fail20033.d(41): Deprecation: `alias byKeyValue this` is deprecated - This was a bad idea
+fail_compilation/fail20033.d(42): Deprecation: `alias byKeyValue this` is deprecated
 ---
 */
 #line 1
-struct Test {
-    import std.typecons : Tuple;
-    alias KVT = Tuple!(string, "key", string, "value");
+struct Tuple(T...)
+{
+    T values;
+    alias values this;
+}
 
+alias KVT = Tuple!(string, string);
+
+struct Test {
     struct Range {
         bool empty () { return false; }
         KVT front() { return KVT.init; }
@@ -26,9 +31,6 @@ struct Test {
 }
 
 struct Test2 {
-    import std.typecons : Tuple;
-    alias KVT = Tuple!(string, "key", string, "value");
-
     struct Range {
         bool empty () { return false; }
         KVT front() { return KVT.init; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d
new file mode 100644
index 00000000000..6f34029db10
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21868b.d
@@ -0,0 +1,22 @@
+/* REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail21868b.d(19): Error: returning `&s.x` escapes a reference to parameter `s`
+fail_compilation/fail21868b.d(19):        perhaps remove `scope` parameter annotation so `return` applies to `ref`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21868
+
+struct S
+{
+    int x;
+    int* y;
+}
+
+int* test(ref return scope S s)
+{
+    return &s.x;
+}
+
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22054.d b/gcc/testsuite/gdc.test/fail_compilation/fail22054.d
new file mode 100644
index 00000000000..c172f089d9c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22054.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=22054
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22054.d(21): Error: no property `what` for type `fail22054.exception`
+fail_compilation/fail22054.d(16):        `class fail22054.exception` is opaque and has no members.
+fail_compilation/fail22054.d(22): Error: no property `what` for type `fail22054.exception2`
+fail_compilation/fail22054.d(17):        `struct fail22054.exception2` is opaque and has no members.
+---
+*/
+
+
+
+
+class exception;
+struct exception2;
+
+void main ()
+{
+    assert(exception.what() == "Hello");
+    assert(exception2.what() == "Hello");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22075.d b/gcc/testsuite/gdc.test/fail_compilation/fail22075.d
new file mode 100644
index 00000000000..9b857c2f1d5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22075.d
@@ -0,0 +1,30 @@
+// https://issues.dlang.org/show_bug.cgi?id=22075
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22075.d(25): Error: AA key type `S` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+fail_compilation/fail22075.d(26): Error: AA key type `S` should have `extern (D) size_t toHash() const nothrow @safe` if `opEquals` defined
+---
+*/
+
+struct HasAliasThis { int a; alias a this; }
+
+struct LacksAliasThis { int a; }
+
+struct S(T)
+{
+    private T a;
+
+    bool opEquals(const S rhs) const @nogc nothrow @safe
+    {
+        return rhs is this;
+    }
+}
+
+int[S!HasAliasThis] aa1; // Compiles but should not.
+int[S!LacksAliasThis] aa2; // Correctly fails to compile with "Error: AA key
+     // type `S` should have `extern (D) size_t toHash() const nothrow @safe`
+     // if `opEquals` defined"".
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22121.d b/gcc/testsuite/gdc.test/fail_compilation/fail22121.d
new file mode 100644
index 00000000000..f45cf12e061
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22121.d
@@ -0,0 +1,11 @@
+// https://issues.dlang.org/show_bug.cgi?id=22121
+// EXTRA_FILES: fail22121/imports/test22121/package.d
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22121/imports/test22121/package.d(1): Error: package name 'fail22121' conflicts with usage as a module name in file fail_compilation/fail22121.d
+---
+*/
+
+module fail22121;
+import fail22121.imports.test22121;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d b/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d
new file mode 100644
index 00000000000..9277fabd0c5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22121/imports/test22121/package.d
@@ -0,0 +1 @@
+module fail22121.imports.test22121;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4517.d b/gcc/testsuite/gdc.test/fail_compilation/fail4517.d
deleted file mode 100644
index f3fe031a147..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4517.d
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail4517.d(16): Error: `enum` member `B` not represented in `final switch`
----
-*/
-
-enum E : ushort
-{
-    A, B
-}
-
-void main()
-{
-    E e;
-    final switch(e)
-    {
-        case E.A:
-            break;
-    }
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4923.d b/gcc/testsuite/gdc.test/fail_compilation/fail4923.d
index fd1e8af2d45..3239cff0cf0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4923.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4923.d
@@ -1,8 +1,7 @@
 /*
-REQUIRED_ARGS: -de
 TEST_OUTPUT:
 ---
-fail_compilation/fail4923.d(4): Deprecation: initialization of `immutable` variable from `static this` is deprecated.
+fail_compilation/fail4923.d(4): Error: immutable variable `bar` initialization is not allowed in `static this`
 fail_compilation/fail4923.d(4):        Use `shared static this` instead.
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9368.d b/gcc/testsuite/gdc.test/fail_compilation/fail9368.d
deleted file mode 100644
index f575a86ab0c..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9368.d
+++ /dev/null
@@ -1,48 +0,0 @@
-// REQUIRED_ARGS: -d
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail9368.d(19): Error: `enum` member `b` not represented in `final switch`
----
-*/
-
-enum E
-{
-    a,
-    b
-}
-
-void main()
-{
-    alias E F;
-    F f;
-    final switch (f)
-    {
-        case F.a:
-    }
-}
-
-/*
-TEST_OUTPUT:
----
-fail_compilation/fail9368.d(40): Error: `enum` member `B` not represented in `final switch`
----
-*/
-
-enum G
-{
-    A,B,C
-}
-
-void test286()
-{
-    G e;
-    final switch (e)
-    {
-        case G.A:
-//      case G.B:
-        case G.C:
-            {}
-    }
-}
-
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failcstuff1.c b/gcc/testsuite/gdc.test/fail_compilation/failcstuff1.c
deleted file mode 100644
index e57a7148021..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/failcstuff1.c
+++ /dev/null
@@ -1,103 +0,0 @@
-// check the expression parser
-/* TEST_OUTPUT
----
-fail_compilation/failcstuff1.c(51): Error: attributes should be specified before the function definition
-fail_compilation/failcstuff1.c(100): Error: no members for `enum E21962`
-fail_compilation/failcstuff1.c(101): Error: no members for anonymous enum
-fail_compilation/failcstuff1.c(152): Error: `;` or `,` expected
-fail_compilation/failcstuff1.c(153): Error: `void` has no value
-fail_compilation/failcstuff1.c(153): Error: missing comma
-fail_compilation/failcstuff1.c(153): Error: `;` or `,` expected
-fail_compilation/failcstuff1.c(154): Error: empty struct-declaration-list for `struct Anonymous`
-fail_compilation/failcstuff1.c(157): Error: identifier not allowed in abstract-declarator
-fail_compilation/failcstuff1.c(203): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(204): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(205): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(206): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(207): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(208): Error: storage class not allowed in specifier-qualified-list
-fail_compilation/failcstuff1.c(251): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(252): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(253): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(258): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(259): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(260): Error: identifier or `(` expected
-fail_compilation/failcstuff1.c(301): Error: illegal type combination
-fail_compilation/failcstuff1.c(352): Error: found `2` when expecting `:`
-fail_compilation/failcstuff1.c(352): Error: found `:` instead of statement
-fail_compilation/failcstuff1.c(400): Error: `enum ENUM` has no members
----
-*/
-
-/********************************/
-// https://issues.dlang.org/show_bug.cgi?id=21937
-#line 50
-void test21962() __attribute__((noinline))
-{
-}
-
-/********************************/
-// https://issues.dlang.org/show_bug.cgi?id=21962
-#line 100
-enum E21962 { };
-enum { };
-
-/********************************/
-// https://issues.dlang.org/show_bug.cgi?id=22028
-#line 150
-struct S22028
-{
-    int init = 1;
-    void vfield nocomma;
-    struct { };
-};
-
-int test22028 = sizeof(struct S22028 ident);
-
-/********************************/
-// https://issues.dlang.org/show_bug.cgi?id=22029
-#line 200
-struct S22029
-{
-    int field;
-    typedef int tfield;
-    extern int efield;
-    static int sfield;
-    _Thread_local int lfield;
-    auto int afield;
-    register int rfield;
-};
-
-// https://issues.dlang.org/show_bug.cgi?id=22030
-#line 250
-int;
-int *;
-int &;
-int , int;
-
-struct S22030
-{
-    int;
-    int *;
-    int &;
-    int, int;
-    int _;
-};
-
-void test22030(struct S22030, struct S22030*, struct S22030[4]);
-
-// https://issues.dlang.org/show_bug.cgi?id=22032
-#line 300
-struct S22032 { int field; }
-int test22032;
-
-// https://issues.dlang.org/show_bug.cgi?id=22035
-#line 350
-void test22035()
-{
-    case 1 2:
-}
-
-// https://issues.dlang.org/show_bug.cgi?id=21932
-#line 400
-enum ENUM;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failcstuff2.c b/gcc/testsuite/gdc.test/fail_compilation/failcstuff2.c
deleted file mode 100644
index 385b5bce47a..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/failcstuff2.c
+++ /dev/null
@@ -1,86 +0,0 @@
-// check semantic analysis of C files
-/* TEST_OUTPUT:
----
-fail_compilation/failcstuff2.c(54): Error: `& var` has no effect
-fail_compilation/failcstuff2.c(55): Error: `*ptr` has no effect
-fail_compilation/failcstuff2.c(56): Error: `var` has no effect
-fail_compilation/failcstuff2.c(57): Error: `-var` has no effect
-fail_compilation/failcstuff2.c(58): Error: `~var` has no effect
-fail_compilation/failcstuff2.c(59): Error: `!var` has no effect
-fail_compilation/failcstuff2.c(113): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(114): Error: cannot modify constant `var.sizeof`
-fail_compilation/failcstuff2.c(115): Error: `cast(short)3` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(116): Error: cannot modify constant `4`
-fail_compilation/failcstuff2.c(117): Error: cannot modify constant `5`
-fail_compilation/failcstuff2.c(118): Error: cannot modify constant `6`
-fail_compilation/failcstuff2.c(119): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(120): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(121): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(122): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(123): Error: `cast(int)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(124): Error: `makeS22067().field` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(125): Error: `makeS22067().field` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(126): Error: `makeS22067().field` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(127): Error: `makeS22067().field` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(153): Error: `cast(short)var` is not an lvalue and cannot be modified
-fail_compilation/failcstuff2.c(154): Error: `cast(long)var` is not an lvalue and cannot be modified
----
-*/
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22069
-#line 50
-void test22069()
-{
-    int var;
-    int *ptr;
-    &var;
-    *ptr;
-    +var;
-    -var;
-    ~var;
-    !var;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22067
-#line 100
-struct S22067
-{
-    int field;
-};
-
-struct S22067 makeS22067()
-{
-    return (struct S22067) { 42 };
-}
-
-void test22067()
-{
-    int var;
-    (int) var = 1;
-    sizeof(var) = 2;
-    ++(short)3;
-    --4;
-    (5)++;
-    (&6);
-    ((int)var)++;
-    ((int)var)--;
-    ++(int)var;
-    --(int)var;
-    &(int)var;
-    &makeS22067().field;
-    makeS22067().field = 1;
-    makeS22067().field++;
-    --makeS22067().field;
-}
-
-/***************************************************/
-// https://issues.dlang.org/show_bug.cgi?id=22068
-#line 150
-void test22068()
-{
-    int var;
-    ++(short) var;
-    --(long long) var;
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice17831.d b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
index 4312d5b1ddf..41abbf77a82 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice17831.d
@@ -1,12 +1,16 @@
-// REQUIRED_ARGS: -d
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice17831.d(19): Error: `case` variable `i` declared at fail_compilation/ice17831.d(17) cannot be declared in `switch` body
-fail_compilation/ice17831.d(33): Error: `case` variable `i` declared at fail_compilation/ice17831.d(31) cannot be declared in `switch` body
-fail_compilation/ice17831.d(48): Error: `case` variable `i` declared at fail_compilation/ice17831.d(45) cannot be declared in `switch` body
-fail_compilation/ice17831.d(61): Error: `case` variable `i` declared at fail_compilation/ice17831.d(60) cannot be declared in `switch` body
-fail_compilation/ice17831.d(73): Error: `case` variable `i` declared at fail_compilation/ice17831.d(72) cannot be declared in `switch` body
+fail_compilation/ice17831.d(23): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(23): Error: `case` variable `i` declared at fail_compilation/ice17831.d(21) cannot be declared in `switch` body
+fail_compilation/ice17831.d(37): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(37): Error: `case` variable `i` declared at fail_compilation/ice17831.d(35) cannot be declared in `switch` body
+fail_compilation/ice17831.d(52): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(52): Error: `case` variable `i` declared at fail_compilation/ice17831.d(49) cannot be declared in `switch` body
+fail_compilation/ice17831.d(65): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(65): Error: `case` variable `i` declared at fail_compilation/ice17831.d(64) cannot be declared in `switch` body
+fail_compilation/ice17831.d(77): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/ice17831.d(77): Error: `case` variable `i` declared at fail_compilation/ice17831.d(76) cannot be declared in `switch` body
 ---
  */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16523.d b/gcc/testsuite/gdc.test/fail_compilation/test16523.d
index 61d17ed2b85..78563c92525 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16523.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16523.d
@@ -1,8 +1,7 @@
-// REQUIRED_ARGS: -de
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test16523.d(13): Deprecation: `case` variables have to be `const` or `immutable`
+fail_compilation/test16523.d(12): Error: `case` variables have to be `const` or `immutable`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
index 8d5d480174e..c5d0579f4a0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
@@ -2,14 +2,14 @@
 TEST_OUTPUT:
 ---
 fail_compilation/trait_loc_err.d(13): Error: can only get the location of a symbol, not `trait_loc_err`
-fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `std`
+fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `stdc`
 ---
 */
 module trait_loc_err;
-import std.stdio;
+import core.stdc.stdio;
 
 void main()
 {
     __traits(getLocation, __traits(parent, main));
-    __traits(getLocation, __traits(parent, std.stdio));
+    __traits(getLocation, __traits(parent, core.stdc.stdio));
 }
diff --git a/gcc/testsuite/gdc.test/runnable/builtin.d b/gcc/testsuite/gdc.test/runnable/builtin.d
index cc3c8c1ee93..39ab12a3386 100644
--- a/gcc/testsuite/gdc.test/runnable/builtin.d
+++ b/gcc/testsuite/gdc.test/runnable/builtin.d
@@ -1,6 +1,4 @@
 // RUNNABLE_PHOBOS_TEST
-
-import std.stdio;
 import std.math;
 import core.bitop;
 
@@ -16,21 +14,15 @@ version (DigitalMars)
 
 void test1()
 {
-    writefln("%a", sin(6.8L));
     auto f = 6.8L;
-    writefln("%a", sin(f));
     assert(sin(f) == sin(6.8L));
     static assert(isClose(sin(6.8L), 0x1.f9f8d9aea10fdf1cp-2));
 
-    writefln("%a", cos(6.8L));
     f = 6.8L;
-    writefln("%a", cos(f));
     assert(cos(f) == cos(6.8L));
     static assert(isClose(cos(6.8L), 0x1.bd21aaf88dcfa13ap-1));
 
-    writefln("%a", tan(6.8L));
     f = 6.8L;
-    writefln("%a", tan(f));
     version (Win64)
     { }
     else
@@ -113,7 +105,5 @@ int main()
     test1();
     test2();
     test3();
-
-    printf("Success\n");
     return 0;
 }
diff --git a/gcc/testsuite/gdc.test/runnable/cstuff2.c b/gcc/testsuite/gdc.test/runnable/cstuff2.c
deleted file mode 100644
index 3c28348e63f..00000000000
--- a/gcc/testsuite/gdc.test/runnable/cstuff2.c
+++ /dev/null
@@ -1,254 +0,0 @@
-
-int printf(const char *, ...);
-void exit(int);
-
-/*********************************/
-
-void test1()
-{
-    static int a[3] = {1, 2, 3};
-    if (a[0] != 1 ||
-        a[1] != 2 ||
-        a[2] != 3)
-    {
-        printf("error 1\n");
-        exit(1);
-    }
-}
-
-/*********************************/
-
-void test2()
-{
-    static int a[4] = {1, 2, 3};
-    if (a[0] != 1 ||
-        a[1] != 2 ||
-        a[2] != 3 ||
-        a[3] != 0)
-    {
-        printf("error 2\n");
-        exit(1);
-    }
-}
-
-/*********************************/
-
-void test3()
-{
-    static int a[] = {1, 2, 3};
-    if (sizeof(a) != 3 * sizeof(int) ||
-        a[0] != 1 ||
-        a[1] != 2 ||
-        a[2] != 3)
-    {
-        printf("error 3\n");
-        exit(1);
-    }
-}
-
-/*********************************/
-
-void test4()
-{
-    static int a[3] = {1, 2, 3};
-    int i;
-    for (i = 0; i < 3; ++i)
-    {
-        if (a[i] != i + 1)
-        {
-            printf("error 4\n");
-            exit(1);
-        }
-    }
-}
-
-/*********************************/
-
-void test5()
-{
-    static int b[3][2] = { 1,2,3,4,5,6 };
-    int i;
-    for (i = 0; i < 3; ++i)
-    {
-        int j;
-        for (j = 0; j < 2; ++j)
-        {
-            if (b[i][j] != i * 2 + j + 1)
-            {
-                printf("error 5\n");
-                exit(1);
-            }
-        }
-    }
-}
-
-/*********************************/
-
-void test6()
-{
-    static int c[3][2] = { {1,2},{3,4},{5,6} };
-    int i;
-    for (i = 0; i < 3; ++i)
-    {
-        int j;
-        for (j = 0; j < 2; ++j)
-        {
-            if (c[i][j] != i * 2 + j + 1)
-            {
-                printf("error 6\n");
-                exit(1);
-            }
-        }
-    }
-}
-
-/*********************************/
-
-void test7()
-{
-    static int d[3][2] = { {1,2},3,4,{5,6} };
-    int i;
-    for (i = 0; i < 3; ++i)
-    {
-        int j;
-        for (j = 0; j < 2; ++j)
-        {
-            if (d[i][j] != i * 2 + j + 1)
-            {
-                printf("error 7\n");
-                exit(1);
-            }
-        }
-    }
-}
-
-/*********************************/
-
-void test8()
-{
-    static int d[3][2] = { {1,2} };
-    int i;
-    for (i = 0; i < 3; ++i)
-    {
-        int j;
-        for (j = 0; j < 2; ++j)
-        {
-            if (i == 0)
-            {
-                if (d[i][j] != j + 1)
-                {
-                    printf("error 8a\n");
-                    exit(1);
-                }
-            }
-            else if (d[i][j] != 0)
-            {
-                printf("error 8b\n");
-                exit(1);
-            }
-        }
-    }
-}
-
-/*********************************/
-
-void test8a()
-{
-    int i;
-    static int a[3] = { 1,2,3 };
-    // Casting to an array type is not allowed by C11, but
-    // CompoundLiterals are not there yet to test this
-    // grammar
-    i = ((int[3])a)[2];
-    if (i != 3) { printf("test8a\n"); exit(1); }
-}
-
-/*********************************/
-
-void test8b()
-{
-    struct S { int a, b; };
-    static struct S ax[3] = { 0x11,0x22,0x33,0 };
-    //printf("%x %x %x %x\n", ax[0].a, ax[0].b, ax[1].a, ax[1].b);
-    if (ax[0].a != 0x11 ||
-        ax[0].b != 0x22 ||
-        ax[1].a != 0x33 ||
-        ax[1].b != 0) { printf("test8b\n"); exit(1); }
-}
-
-/*********************************/
-
-void test9()
-{
-    int i = 1;            if (i != 1) { printf("error 9i\n"); exit(1); }
-    int j = { 2 };        if (j != 2) { printf("error 9j\n"); exit(1); }
-    int k = { 3,};        if (k != 3) { printf("error 9k\n"); exit(1); }
-
-    static int l = 4;     if (l != 4) { printf("error 9l\n"); exit(1); }
-    static int m = { 5 }; if (m != 5) { printf("error 9m\n"); exit(1); }
-    static int n = { 6,}; if (n != 6) { printf("error 9n\n"); exit(1); }
-}
-
-/*********************************/
-
-void test10()
-{
-    char s[6] = { "s" }; if (s[0] != 's')                     { printf("error 10s\n"); exit(1); }
-    char t[7] = { "t" }; if (t[0] != 't' && t[1] != 0)        { printf("error 10t\n"); exit(1); }
-    static char u[6] = { "u" }; if (u[0] != 'u')              { printf("error 10u\n"); exit(1); }
-    static char v[7] = { "v" }; if (v[0] != 'v' && v[1] != 0) { printf("error 10v\n"); exit(1); }
-}
-
-/*********************************/
-
-void test11()
-{
-    struct S { int a, b; };
-    struct S s = { 1, 2 };
-    if (s.a != 1 || s.b != 2) { printf("xx\n"); exit(1); }
-    static struct S s2 = { 1, };
-    if (s2.a != 1 || s2.b != 0) { printf("xx\n"); exit(1); }
-
-    struct T { int a; struct { int b, c; }; };
-    struct T t = { 1, 2, 3 };
-    if (t.a != 1 || t.b != 2 || t.c != 3) { printf("xx\n"); exit(1); }
-
-    struct U { int a; union { int b, c; }; int d; };
-    struct U u = { 1, 2, 3 };
-    if (u.a != 1 ||
-        u.b != 2 ||
-        u.c != 2 ||
-        u.d != 3) { printf("%d %d %d %d\n", u.a, u.b, u.c, u.d); exit(1); }
-}
-
-/*********************************/
-
-void test12()
-{
-    int i;
-    i = (int) { 3 };
-    if (i != 3) { printf("test12\n"); exit(1); }
-}
-
-/*********************************/
-
-int main()
-{
-    test1();
-    test2();
-    test3();
-    test4();
-    test5();
-    test6();
-    test7();
-    test8();
-    test8a();
-    test8b();
-    test9();
-    test10();
-    test11();
-    test12();
-
-    return 0;
-}
-
diff --git a/gcc/testsuite/gdc.test/runnable/fix22115.d b/gcc/testsuite/gdc.test/runnable/fix22115.d
new file mode 100644
index 00000000000..2344bcc1a0c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/fix22115.d
@@ -0,0 +1,70 @@
+/* PERMUTE_ARGS: -O -inline
+ */
+// https://issues.dlang.org/show_bug.cgi?id=22115
+
+
+int sx;
+void sss() {  ++sx; }
+
+static if (1)
+{
+    struct S { int a; }
+
+    void test1(S* s)
+    {
+        if (s.a == 3 ? s : null)
+            sss();
+    }
+}
+
+static if (1)
+{
+    extern (C++) class Exp
+    {
+        int a;
+
+        void func() { }
+        final inout(AddExp) isAddExp() inout { return a == 3 ? cast(typeof(return))this : null; }
+    }
+
+    extern (C++) class AddExp : Exp
+    {
+    }
+
+    void test2(Exp e)
+    {
+        if (e.isAddExp())
+            sss();
+    }
+}
+
+
+int main()
+{
+    static if (1)
+    {
+        S s;
+        s.a = 3;
+        test1(&s);
+        assert(sx == 1);
+        s.a = 2;
+        test1(&s);
+        assert(sx == 1);
+    }
+    sx = 1;
+
+    static if (1)
+    {
+        auto c = new AddExp();
+        c.a = 3;
+        test2(c);
+        assert(sx == 2);
+        auto ae = c.isAddExp();
+        assert(ae && ae.a == 3);
+        c.a = 2;
+        test2(c);
+        assert(sx == 2);
+    }
+
+    return 0;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/ice21727.d b/gcc/testsuite/gdc.test/runnable/ice21727.d
new file mode 100644
index 00000000000..5b5745f9df0
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/ice21727.d
@@ -0,0 +1,46 @@
+// REQUIRED_ARGS: -m64 -O -inline
+// DISABLED: win32 linux32 freebsd32 osx32 netbsd32 dragonflybsd32
+// https://issues.dlang.org/show_bug.cgi?id=21727
+
+import core.simd;
+
+@nogc nothrow pure @safe:
+
+struct Float4
+{
+    float4 mVector;
+
+    pragma(inline, false) ref typeof(this) doubleInPlace() return
+    @nogc nothrow pure @safe
+    {
+        mVector = mVector + mVector;
+        return this;
+    }
+}
+
+pragma(inline, false) Float4 identity(Float4 a)
+{
+    return a;
+}
+
+pragma(inline, true) Float4 twoTimes(const ref Float4 a)
+{
+    version (D_SIMD)
+        return Float4(cast(float4) __simd(XMM.ADDPS, a.mVector, a.mVector));
+    else // Allow non-DMD compilers to compile this test.
+        return Float4(a.mVector + a.mVector);
+}
+
+pragma(inline, false) Float4 fourTimes(const Float4 a)
+{
+    auto x = identity(a);
+    auto y = x.doubleInPlace(); // This crashed in dmd.backend.cgxmm.xmmload.
+    auto z = twoTimes(y);
+    return z;
+}
+
+void main()
+{
+    const c = fourTimes(Float4([5,7,11,13]));
+    assert(c.mVector.array == [20, 28, 44, 52]);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test15.d b/gcc/testsuite/gdc.test/runnable/test15.d
index ad888a5fb25..222742c4080 100644
--- a/gcc/testsuite/gdc.test/runnable/test15.d
+++ b/gcc/testsuite/gdc.test/runnable/test15.d
@@ -1,14 +1,10 @@
-// RUNNABLE_PHOBOS_TEST
 /*
-REQUIRED_ARGS:
+REQUIRED_ARGS: -Jrunnable/extra-files
 EXTRA_FILES: extra-files/test15.txt
 */
 
-import std.array;
 import core.math;
 import core.vararg;
-import std.string;
-import std.stdio : File;
 
 extern (C)
 {
@@ -281,10 +277,47 @@ void test20()
 
 void test21()
 {
+    // Minimalistic byLine implementation
+    static struct Lines
+    {
+        private string text, line;
+        this(string text)
+        {
+            this.text = text;
+            popFront();
+        }
+
+        bool empty() const { return text == ""; }
+
+        string front() const
+        {
+            assert(!empty);
+            return line;
+        }
+
+        void popFront()
+        {
+            assert(!empty);
+            foreach (const idx; 0 .. text.length)
+            {
+                if (text[idx] == '\n')
+                {
+                    line = text[0..idx];
+                    text = text[idx + 1..$];
+                    return;
+                }
+            }
+
+            line = text;
+            text = null;
+        }
+    }
+
+    static immutable string file = import(`test15.txt`);
+
     int[string] esdom;
-    auto f = File("runnable/extra-files/test15.txt", "r");
 
-    foreach(it; f.byLine())
+    foreach(it; Lines(file))
         esdom[it.idup] = 0;
 
     esdom.rehash;
@@ -363,11 +396,11 @@ void test25()
 
 void test26()
 {
-    string[] instructions = std.array.split("a;b;c", ";");
+    string[] instructions =[ "a", "b", "c" ];
 
     foreach(ref string instr; instructions)
     {
-        std.string.strip(instr);
+        instr = instr[];
     }
 
     foreach(string instr; instructions)
@@ -1117,16 +1150,13 @@ void test60()
 
 class StdString
 {
-     alias std.string.format toString;
+     alias nearest =  core.math.rint;
 }
 
 void test61()
 {
-    int i = 123;
     StdString g = new StdString();
-    string s = g.toString("%s", i);
-    printf("%.*s\n", cast(int)s.length, s.ptr);
-    assert(s == "123");
+    assert(g.nearest(123.1) == 123);
 }
 
 
diff --git a/gcc/testsuite/gdc.test/runnable/ufcs.d b/gcc/testsuite/gdc.test/runnable/ufcs.d
index fb9039b8df2..2d9bf155983 100644
--- a/gcc/testsuite/gdc.test/runnable/ufcs.d
+++ b/gcc/testsuite/gdc.test/runnable/ufcs.d
@@ -1,4 +1,3 @@
-// RUNNABLE_PHOBOS_TEST
 // EXTRA_SOURCES: imports/ufcs5a.d imports/ufcs5b.d imports/ufcs5c.d imports/ufcs5d.d imports/ufcs5e.d
 
 module ufcs;
@@ -422,8 +421,6 @@ class C5 : B5
 /*******************************************/
 // https://issues.dlang.org/show_bug.cgi?id=662
 
-import std.string, std.conv;
-
 enum Etest
 {
     a,b,c,d
@@ -448,6 +445,10 @@ int test(Etest test)
 //{
 //  return cast(int)i;
 //}
+string to(T)(int i) {
+    assert(i == 22);
+    return "22";
+}
 
 void test682()
 {
@@ -465,13 +466,54 @@ void test682()
 /*******************************************/
 // https://issues.dlang.org/show_bug.cgi?id=3382
 
-import std.range, std.algorithm;
-
 @property T twice(T)(T x){ return x * x; }
 char toupper(char c){ return ('a'<=c && c<='z') ? cast(char)(c - 'a' + 'A') : c; }
 
 @property ref T setter(T)(ref T x, T v){ x = v; return x; }
 
+auto iota(T)(T min, T max)
+{
+    static struct Result
+    {
+        T cur, end;
+
+        T front() { return cur; }
+        bool empty() { return front == end; }
+        void popFront() { cur++; }
+    }
+    return Result(min, max);
+}
+
+auto map(string s, R)(R range)
+{
+    static struct Result
+    {
+        R source;
+        auto front() { auto a = source.front; return mixin(s); }
+        alias source this;
+    }
+    return Result(range);
+}
+
+auto filter(string s, R)(R range)
+{
+    static struct Result
+    {
+        R source;
+        alias source this;
+        void popFront()
+        {
+            while (true)
+            {
+                auto a = source.front;
+                if (mixin(s)) break;
+                source.popFront();
+            }
+        }
+    }
+    return Result(range);
+}
+
 void test3382()
 {
     auto r = iota(0, 10).map!"a*3"().filter!"a%2 != 0"();
@@ -486,10 +528,23 @@ void test3382()
 /*******************************************/
 // https://issues.dlang.org/show_bug.cgi?id=6185
 
-void test6185()
+ref T front(T)(T[] array) { return array[0]; }
+bool empty(T)(T[] array) { return array.length == 0; }
+void popFront(T)(ref T[] array) { array = array[1..$]; }
+
+bool equal(T, U)(T t, U u)
 {
-    import std.algorithm;
+    while (true)
+    {
+        if (t.empty) return u.empty;
+        if (u.empty || t.front != u.front) return false;
+        t.popFront();
+        u.popFront();
+    }
+}
 
+void test6185()
+{
     auto r1 = [1,2,3].map!"a*2";
     assert(equal(r1, [2,4,6]));
 
diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d
index 252e33da8b0..734fbcf9bae 100644
--- a/libphobos/libdruntime/core/exception.d
+++ b/libphobos/libdruntime/core/exception.d
@@ -51,6 +51,11 @@ class RangeError : Error
     {
         super( "Range violation", file, line, next );
     }
+
+    protected this( string msg, string file, size_t line, Throwable next = null ) @nogc nothrow pure @safe
+    {
+        super( msg, file, line, next );
+    }
 }
 
 unittest
@@ -72,6 +77,142 @@ unittest
     }
 }
 
+/**
+ * Thrown when an out of bounds array index is accessed.
+ */
+class ArrayIndexError : RangeError
+{
+    /// Index into array
+    const size_t index;
+    /// Length of indexed array
+    const size_t length;
+
+    // Buffer to avoid GC allocations
+    private immutable char[100] msgBuf = '\0';
+
+    this(size_t index, size_t length, string file = __FILE__,
+         size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
+    {
+        this.index  = index;
+        this.length = length;
+
+        // Constructing the message is a bit clumsy:
+        // It's essentially `printf("index [%zu] exceeds array of length [%zu]", index, length)`,
+        // but even `snprintf` isn't `pure`.
+        // Also string concatenation isn't `@nogc`, and casting to/from immutable isn't `@safe`
+        import core.internal.string : unsignedToTempString;
+        char[msgBuf.length] buf = void;
+        char[20] tmpBuf = void;
+        char[] sink = buf[];
+        sink.rangeMsgPut("index [");
+        sink.rangeMsgPut(unsignedToTempString!10(index, tmpBuf));
+        sink.rangeMsgPut("]");
+        sink.rangeMsgPut(" exceeds array of length ");
+        sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
+        this.msgBuf = buf;
+        super(msgBuf[0..$-sink.length], file, line, next);
+    }
+}
+
+@safe pure unittest
+{
+    assert(new ArrayIndexError(900, 700).msg == "index [900] exceeds array of length 700");
+    // Ensure msg buffer doesn't overflow on large numbers
+    assert(new ArrayIndexError(size_t.max, size_t.max-1).msg);
+}
+
+unittest
+{
+    try
+    {
+        _d_arraybounds_indexp("test", 400, 9, 3);
+        assert(0, "no ArrayIndexError thrown");
+    }
+    catch (ArrayIndexError re)
+    {
+        assert(re.file   == "test");
+        assert(re.line   == 400);
+        assert(re.index  == 9);
+        assert(re.length == 3);
+    }
+}
+
+/**
+ * Thrown when an out of bounds array slice is created
+ */
+class ArraySliceError : RangeError
+{
+    /// Lower/upper bound passed to slice: `array[lower .. upper]`
+    const size_t lower, upper;
+    /// Length of sliced array
+    const size_t length;
+
+    private immutable char[120] msgBuf = '\0';
+
+    this(size_t lower, size_t upper, size_t length, string file = __FILE__,
+         size_t line = __LINE__, Throwable next = null) @nogc nothrow pure @safe
+    {
+        this.lower  = lower;
+        this.upper  = upper;
+        this.length = length;
+
+        // Constructing the message is a bit clumsy for the same reasons as ArrayIndexError
+        import core.internal.string : unsignedToTempString;
+        char[msgBuf.length] buf = void;
+        char[20] tmpBuf = void;
+        char[] sink = buf;
+        sink.rangeMsgPut("slice [");
+        sink.rangeMsgPut(unsignedToTempString!10(lower, tmpBuf));
+        sink.rangeMsgPut(" .. ");
+        sink.rangeMsgPut(unsignedToTempString!10(upper, tmpBuf));
+        sink.rangeMsgPut("] ");
+        if (lower > upper)
+        {
+            sink.rangeMsgPut("has a larger lower index than upper index");
+        }
+        else
+        {
+            sink.rangeMsgPut("extends past source array of length ");
+            sink.rangeMsgPut(unsignedToTempString!10(length, tmpBuf));
+        }
+
+        this.msgBuf = buf;
+        super(msgBuf[0..$-sink.length], file, line, next);
+    }
+}
+
+@safe pure unittest
+{
+    assert(new ArraySliceError(40, 80, 20).msg == "slice [40 .. 80] extends past source array of length 20");
+    assert(new ArraySliceError(90, 70, 20).msg == "slice [90 .. 70] has a larger lower index than upper index");
+    // Ensure msg buffer doesn't overflow on large numbers
+    assert(new ArraySliceError(size_t.max, size_t.max, size_t.max-1).msg);
+}
+
+unittest
+{
+    try
+    {
+        _d_arraybounds_slicep("test", 400, 1, 7, 3);
+        assert(0, "no ArraySliceError thrown");
+    }
+    catch (ArraySliceError re)
+    {
+        assert(re.file   == "test");
+        assert(re.line   == 400);
+        assert(re.lower  == 1);
+        assert(re.upper  == 7);
+        assert(re.length == 3);
+    }
+}
+
+/// Mini `std.range.primitives: put` for constructor of ArraySliceError / ArrayIndexError
+private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure @safe
+{
+    assert(r.length >= e.length); // don't throw ArraySliceError inside ArrayIndexError ctor
+    r[0 .. e.length] = e[];
+    r = r[e.length .. $];
+}
 
 /**
  * Thrown on an assert error.
@@ -470,7 +611,7 @@ extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothr
 ///////////////////////////////////////////////////////////////////////////////
 
 /**
- * A callback for array bounds errors in D.  A $(LREF RangeError) will be thrown.
+ * A callback for general array bounds errors in D. A $(LREF RangeError) will be thrown.
  *
  * Params:
  *  file = The name of the file that signaled this error.
@@ -481,9 +622,45 @@ extern (C) void onUnittestErrorMsg( string file, size_t line, string msg ) nothr
  */
 extern (C) void onRangeError( string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
 {
-    throw staticError!RangeError( file, line, null );
+    throw staticError!RangeError(file, line, null);
 }
 
+/**
+ * A callback for array slice out of bounds errors in D.
+ *
+ * Params:
+ *  lower  = the lower bound of the index passed of a slice
+ *  upper  = the upper bound of the index passed of a slice or the index if not a slice
+ *  length = length of the array
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ *
+ * Throws:
+ *  $(LREF ArraySliceError).
+ */
+extern (C) void onArraySliceError( size_t lower = 0, size_t upper = 0, size_t length = 0,
+                              string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
+{
+    throw staticError!ArraySliceError(lower, upper, length, file, line, null);
+}
+
+/**
+ * A callback for array index out of bounds errors in D.
+ *
+ * Params:
+ *  index  = index in the array
+ *  length = length of the array
+ *  file = The name of the file that signaled this error.
+ *  line = The line number on which this error occurred.
+ *
+ * Throws:
+ *  $(LREF ArrayIndexError).
+ */
+extern (C) void onArrayIndexError( size_t index = 0, size_t length = 0,
+                              string file = __FILE__, size_t line = __LINE__ ) @trusted pure nothrow @nogc
+{
+    throw staticError!ArrayIndexError(index, length, file, line, null);
+}
 
 /**
  * A callback for finalize errors in D.  A $(LREF FinalizeError) will be thrown.
@@ -613,22 +790,36 @@ extern (C)
         _d_unittest_msg("unittest failure", file, line);
     }
 
-    /* Called when an array index is out of bounds
-     */
+    /// Called when an invalid array index/slice or associative array key is accessed
     void _d_arrayboundsp(immutable(char*) file, uint line)
     {
         import core.stdc.string : strlen;
         onRangeError(file[0 .. strlen(file)], line);
     }
 
+    /// ditto
     void _d_arraybounds(string file, uint line)
     {
         onRangeError(file, line);
     }
+
+    /// Called when an out of range slice of an array is created
+    void _d_arraybounds_slicep(immutable(char*) file, uint line, size_t lower, size_t upper, size_t length)
+    {
+        import core.stdc.string : strlen;
+        onArraySliceError(lower, upper, length, file[0 .. strlen(file)], line);
+    }
+
+    /// Called when an out of range array index is accessed
+    void _d_arraybounds_indexp(immutable(char*) file, uint line, size_t index, size_t length)
+    {
+        import core.stdc.string : strlen;
+        onArrayIndexError(index, length, file[0 .. strlen(file)], line);
+    }
 }
 
 // TLS storage shared for all errors, chaining might create circular reference
-private align(2 * size_t.sizeof) void[128] _store;
+private align(2 * size_t.sizeof) void[256] _store;
 
 // only Errors for now as those are rarely chained
 private T staticError(T, Args...)(auto ref Args args)
diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d
index 0d9f903b100..3036ea72d15 100644
--- a/libphobos/libdruntime/core/internal/atomic.d
+++ b/libphobos/libdruntime/core/internal/atomic.d
@@ -10,7 +10,7 @@
 
 module core.internal.atomic;
 
-import core.atomic : MemoryOrder;
+import core.atomic : MemoryOrder, has128BitCAS;
 
 version (DigitalMars)
 {
@@ -1065,8 +1065,9 @@ enum CanCAS(T) = is(T : ulong) ||
                  is(T : U[], U) ||
                  is(T : R delegate(A), R, A...) ||
                  (is(T == struct) && __traits(isPOD, T) &&
-                  T.sizeof <= size_t.sizeof*2 && // no more than 2 words
-                  (T.sizeof & (T.sizeof - 1)) == 0 // is power of 2
+                  (T.sizeof <= size_t.sizeof*2 ||       // no more than 2 words
+                   (T.sizeof == 16 && has128BitCAS)) && // or supports 128-bit CAS
+                  (T.sizeof & (T.sizeof - 1)) == 0      // is power of 2
                  );
 
 template IntOrLong(T)
diff --git a/libphobos/libdruntime/core/internal/backtrace/dwarf.d b/libphobos/libdruntime/core/internal/backtrace/dwarf.d
index 9e1b39d167a..f17658b1cf9 100644
--- a/libphobos/libdruntime/core/internal/backtrace/dwarf.d
+++ b/libphobos/libdruntime/core/internal/backtrace/dwarf.d
@@ -317,7 +317,9 @@ void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations,
                     // Can be called with either `locInfo` or `lastLoc`
                     void update(const ref LocationInfo match)
                     {
-                        const sourceFile = lp.sourceFiles[match.file - 1];
+                        // File indices are 1-based for DWARF < 5
+                        const fileIndex = match.file - (lp.dwarfVersion < 5 ? 1 : 0);
+                        const sourceFile = lp.sourceFiles[fileIndex];
                         debug (DwarfDebugMachine)
                         {
                             printf("-- found for [%p]:\n", loc.address);
@@ -325,7 +327,7 @@ void resolveAddresses(const(ubyte)[] debugLineSectionData, Location[] locations,
                                    cast(int) sourceFile.file.length, sourceFile.file.ptr);
                             printf("--   line: %d\n", match.line);
                         }
-                        // DMD emits entries with FQN, but other implmentations
+                        // DMD emits entries with FQN, but other implementations
                         // (e.g. LDC) make use of directories
                         // See https://github.com/dlang/druntime/pull/2945
                         if (sourceFile.dirIndex != 0)
@@ -592,76 +594,13 @@ T read(T)(ref const(ubyte)[] buffer) @nogc nothrow
     return result;
 }
 
-/**
- * Reads an ULEB128 length and then reads the followings bytes specified by the
- * length.
- *
- * Params:
- *      buffer = buffer where the data is read from
- * Returns:
- *      Value contained in the block.
- */
-ulong readBlock(ref const(ubyte)[] buffer) @nogc nothrow
+// Reads a null-terminated string from `buffer`.
+const(char)[] readStringz(ref const(ubyte)[] buffer) @nogc nothrow
 {
-    ulong length = buffer.readULEB128();
-    assert(length <= ulong.sizeof);
-
-    ulong block;
-    foreach (i; 0 .. length)
-    {
-        ubyte b = buffer.read!ubyte;
-        block <<= 8 * i;
-        block |= b;
-    }
-
-    return block;
-}
-
-/**
- * Reads a MD5 hash from the `buffer`.
- *
- * Params:
- *      buffer = buffer where the data is read from
- * Returns:
- *      A MD5 hash
- */
-char[16] readMD5(ref const(ubyte)[] buffer) @nogc nothrow
-{
-    assert(buffer.length >= 16);
-
-    ubyte[16] bytes;
-    foreach (h; 0 .. 16)
-        bytes[h] = buffer.read!ubyte;
-
-    return cast(char[16])bytes;
-}
-
-/**
- * Reads a null-terminated string from `buffer`.
- * The string is not removed from buffer and doesn't contain the last null byte.
- *
- * Params:
- *      buffer = buffer where the data is read from
- *
- * Returns:
- *      A string
- */
-const(char)[] readString(ref const(ubyte)[] buffer) @nogc nothrow
-{
-    import core.sys.posix.string : strnlen;
-
-    return cast(const(char)[])buffer[0 .. strnlen(cast(char*)buffer.ptr, buffer.length)];
-}
-
-unittest
-{
-    const(ubyte)[] data = [0x48, 0x61, 0x76, 0x65, 0x20, 0x61, 0x20, 0x67, 0x6f,
-        0x6f, 0x64, 0x20, 0x64, 0x61, 0x79, 0x20, 0x21, 0x00];
-    const(char)[] result = data.readString();
-    assert(result == "Have a good day !");
-
-    data = [0x00];
-    assert(data.readString == null);
+    const p = cast(char*) buffer.ptr;
+    const str = p[0 .. strlen(p)];
+    buffer = buffer[str.length+1 .. $];
+    return str;
 }
 
 ulong readULEB128(ref const(ubyte)[] buffer) @nogc nothrow
@@ -710,102 +649,18 @@ long readSLEB128(ref const(ubyte)[] buffer) @nogc nothrow
     return val;
 }
 
-Array!EntryFormatData readEntryFormat(ref const(ubyte)[] buffer, ref Array!ulong entryFormat) @nogc nothrow
+enum DW_LNCT : ushort
 {
-    // The count needs to be pair, as the specification says
-    assert(entryFormat.length % 2 == 0);
-    Array!EntryFormatData result;
-
-    for (uint i = 0; i < entryFormat.length; i += 2)
-    {
-        EntryFormatData efdata;
-        ulong form = entryFormat[i + 1];
-
-        switch (entryFormat[i])
-        {
-            case StandardContentDescription.path:
-                if (form == FormEncoding._string)
-                    efdata.path = buffer.readString();
-                else
-                {
-                    size_t offset = buffer.read!size_t;
-
-                    // TODO: set filename.path to the string at offset
-                    static if (0)
-                    {
-                        if (form == FormEncoding.line_strp) // Offset in debug_line_str
-                        {
-
-                        }
-                        else if (form == FormEncoding.strp) // Offset in debug_str
-                        {
-
-                        }
-                        else if (form == FormEncoding.strp_sup) // Offset of debug_str in debug_info
-                        {
-
-                        }
-                        else
-                            assert(0);
-                    }
-                    else
-                        assert(0);
-                }
-                break;
-
-            case StandardContentDescription.directoryIndex:
-                if (form == FormEncoding.data1)
-                    efdata.directoryIndex = cast(ulong)buffer.read!ubyte;
-                else if (form == FormEncoding.data2)
-                    efdata.directoryIndex = cast(ulong)buffer.read!ushort;
-                else if (form == FormEncoding.udata)
-                    efdata.directoryIndex = buffer.readULEB128();
-                else
-                    assert(0);
-                break;
-
-            case StandardContentDescription.timeStamp:
-                if (form == FormEncoding.udata)
-                    efdata.timeStamp = buffer.readULEB128();
-                else if (form == FormEncoding.data4)
-                    efdata.timeStamp = cast(ulong)buffer.read!uint;
-                else if (form == FormEncoding.data8)
-                    efdata.timeStamp = buffer.read!ulong;
-                else if (form == FormEncoding.block)
-                    efdata.timeStamp = buffer.readBlock();
-                else
-                    assert(0);
-                break;
-
-            case StandardContentDescription.size:
-                if (form == FormEncoding.data1)
-                    efdata.size = cast(ulong)buffer.read!ubyte;
-                else if (form == FormEncoding.data2)
-                    efdata.size = cast(ulong)buffer.read!ushort;
-                else if (form == FormEncoding.data4)
-                    efdata.size = cast(ulong)buffer.read!uint;
-                else if (form == FormEncoding.data8)
-                    efdata.size = buffer.read!ulong;
-                else
-                    assert(0);
-                break;
-
-            case StandardContentDescription.md5:
-                if (form == FormEncoding.data16)
-                    efdata.md5 = buffer.readMD5();
-                else
-                    assert(0);
-                break;
-
-            default:
-                assert(0);
-        }
-        result.insertBack(efdata);
-    }
-    return result;
+    path = 1,
+    directoryIndex = 2,
+    timestamp = 3,
+    size = 4,
+    md5 = 5,
+    loUser = 0x2000,
+    hiUser = 0x3fff,
 }
 
-enum FormEncoding : ubyte
+enum DW_FORM : ubyte
 {
     addr = 1,
     block2 = 3,
@@ -813,7 +668,7 @@ enum FormEncoding : ubyte
     data2 = 5,
     data4 = 6,
     data8 = 7,
-    _string = 8,
+    string_ = 8,
     block = 9,
     block1 = 10,
     data1 = 11,
@@ -852,6 +707,36 @@ enum FormEncoding : ubyte
     addrx4 = 44,
 }
 
+struct EntryFormatPair
+{
+    DW_LNCT type;
+    DW_FORM form;
+}
+
+/// Reads a DWARF v5 directory/file name entry format.
+Array!EntryFormatPair readEntryFormat(ref const(ubyte)[] buffer) @nogc nothrow
+{
+    const numPairs = buffer.read!ubyte();
+
+    Array!EntryFormatPair pairs;
+    pairs.length = numPairs;
+
+    foreach (ref pair; pairs)
+    {
+        pair.type = cast(DW_LNCT) buffer.readULEB128();
+        pair.form = cast(DW_FORM) buffer.readULEB128();
+    }
+
+    debug (DwarfDebugMachine)
+    {
+        printf("entryFormat: (%d)\n", cast(int) pairs.length);
+        foreach (ref pair; pairs)
+            printf("\t- type: %d, form: %d\n", cast(int) pair.type, cast(int) pair.form);
+    }
+
+    return pairs;
+}
+
 enum StandardOpcode : ubyte
 {
     extendedOp = 0,
@@ -877,24 +762,6 @@ enum ExtendedOpcode : ubyte
     setDiscriminator = 4,
 }
 
-enum StandardContentDescription : ubyte
-{
-    path = 1,
-    directoryIndex = 2,
-    timeStamp = 3,
-    size = 4,
-    md5 = 5,
-}
-
-struct EntryFormatData
-{
-    const(char)[] path;
-    ulong directoryIndex;
-    ulong timeStamp;
-    ulong size;
-    char[16] md5;
-}
-
 struct StateMachine
 {
     const(void)* address;
@@ -931,17 +798,6 @@ struct LineNumberProgram
     ubyte lineRange;
     ubyte opcodeBase;
     const(ubyte)[] standardOpcodeLengths;
-
-    ubyte directoryEntryFormatCount;
-    Array!ulong directoryEntryFormat;
-    ulong directoriesCount;
-    Array!EntryFormatData directories;
-
-    ubyte fileNameEntryFormatCount;
-    Array!ulong fileNameEntryFormat;
-    ulong fileNamesCount;
-    Array!EntryFormatData fileNames;
-
     Array!(const(char)[]) includeDirectories;
     Array!SourceFile sourceFiles;
     const(ubyte)[] program;
@@ -950,7 +806,7 @@ struct LineNumberProgram
 struct SourceFile
 {
     const(char)[] file;
-    size_t dirIndex;
+    size_t dirIndex; // 1-based
 }
 
 LineNumberProgram readLineNumberProgram(ref const(ubyte)[] data) @nogc nothrow
@@ -993,78 +849,135 @@ LineNumberProgram readLineNumberProgram(ref const(ubyte)[] data) @nogc nothrow
 
     if (lp.dwarfVersion >= 5)
     {
-        lp.directoryEntryFormatCount = data.read!ubyte();
-        foreach (c; 0 .. lp.directoryEntryFormatCount)
-            lp.directoryEntryFormat.insertBack(data.readULEB128());
-
-        lp.directoriesCount = data.readULEB128();
-        lp.directories = data.readEntryFormat(lp.directoryEntryFormat);
-
-
-        lp.fileNameEntryFormatCount = data.read!ubyte;
-        foreach (c; 0 .. lp.fileNameEntryFormatCount)
-            lp.fileNameEntryFormat.insertBack(data.readULEB128());
-
-        lp.fileNamesCount = data.readULEB128();
-        lp.fileNames = data.readEntryFormat(lp.fileNameEntryFormat);
-    }
-
-    // A sequence ends with a null-byte.
-    static auto readSequence(alias ReadEntry)(ref const(ubyte)[] data)
-    {
-        alias ResultType = typeof(ReadEntry(data));
-
-        static size_t count(const(ubyte)[] data)
+        static void consumeGenericForm(ref const(ubyte)[] data, DW_FORM form, bool is64bitDwarf)
         {
-            size_t count = 0;
-            while (data.length && data[0] != 0)
+            with (DW_FORM) switch (form)
             {
-                ReadEntry(data);
-                ++count;
+                case strp, strp_sup, line_strp:
+                    data = data[is64bitDwarf ? 8 : 4 .. $]; break;
+                case data1, strx1:
+                    data = data[1 .. $]; break;
+                case data2, strx2:
+                    data = data[2 .. $]; break;
+                case strx3:
+                    data = data[3 .. $]; break;
+                case data4, strx4:
+                    data = data[4 .. $]; break;
+                case data8:
+                    data = data[8 .. $]; break;
+                case data16:
+                    data = data[16 .. $]; break;
+                case udata, strx:
+                    data.readULEB128(); break;
+                case block:
+                    const length = cast(size_t) data.readULEB128();
+                    data = data[length .. $];
+                    break;
+                default:
+                    assert(0); // TODO: support other forms for vendor extensions
             }
-            return count;
         }
 
-        const numEntries = count(data);
+        const dirFormat = data.readEntryFormat();
+        lp.includeDirectories.length = cast(size_t) data.readULEB128();
+        foreach (ref dir; lp.includeDirectories)
+        {
+            dir = "<unknown dir>"; // fallback
+            foreach (ref pair; dirFormat)
+            {
+                if (pair.type == DW_LNCT.path &&
+                    // TODO: support other forms too (offsets in other sections)
+                    pair.form == DW_FORM.string_)
+                {
+                    dir = data.readStringz();
+                }
+                else // uninteresting type
+                    consumeGenericForm(data, pair.form, is64bitDwarf);
+            }
+        }
 
-        Array!ResultType result;
-        result.length = numEntries;
+        const fileFormat = data.readEntryFormat();
+        lp.sourceFiles.length = cast(size_t) data.readULEB128();
+        foreach (ref sf; lp.sourceFiles)
+        {
+            sf.file = "<unknown file>"; // fallback
+            foreach (ref pair; fileFormat)
+            {
+                if (pair.type == DW_LNCT.path &&
+                    // TODO: support other forms too (offsets in other sections)
+                    pair.form == DW_FORM.string_)
+                {
+                    sf.file = data.readStringz();
+                }
+                else if (pair.type == DW_LNCT.directoryIndex)
+                {
+                    if (pair.form == DW_FORM.data1)
+                        sf.dirIndex = data.read!ubyte();
+                    else if (pair.form == DW_FORM.data2)
+                        sf.dirIndex = data.read!ushort();
+                    else if (pair.form == DW_FORM.udata)
+                        sf.dirIndex = cast(size_t) data.readULEB128();
+                    else
+                        assert(0); // not allowed by DWARF 5 spec
+                    sf.dirIndex++; // DWARF v5 indices are 0-based
+                }
+                else // uninteresting type
+                    consumeGenericForm(data, pair.form, is64bitDwarf);
+            }
+        }
+    }
+    else
+    {
+        // A sequence ends with a null-byte.
+        static auto readSequence(alias ReadEntry)(ref const(ubyte)[] data)
+        {
+            alias ResultType = typeof(ReadEntry(data));
 
-        foreach (i; 0 .. numEntries)
-            result[i] = ReadEntry(data);
+            static size_t count(const(ubyte)[] data)
+            {
+                size_t count = 0;
+                while (data.length && data[0] != 0)
+                {
+                    ReadEntry(data);
+                    ++count;
+                }
+                return count;
+            }
 
-        data = data[1 .. $]; // skip over sequence-terminating null
+            const numEntries = count(data);
 
-        return result;
-    }
+            Array!ResultType result;
+            result.length = numEntries;
 
-    /// Directories are simply a sequence of NUL-terminated strings
-    static const(char)[] readIncludeDirectoryEntry(ref const(ubyte)[] data)
-    {
-        const ptr = cast(const(char)*) data.ptr;
-        const dir = ptr[0 .. strlen(ptr)];
-        data = data[dir.length + "\0".length .. $];
-        return dir;
-    }
-    lp.includeDirectories = readSequence!readIncludeDirectoryEntry(data);
+            foreach (i; 0 .. numEntries)
+                result[i] = ReadEntry(data);
 
-    static SourceFile readFileNameEntry(ref const(ubyte)[] data)
-    {
-        const ptr = cast(const(char)*) data.ptr;
-        const file = ptr[0 .. strlen(ptr)];
-        data = data[file.length + "\0".length .. $];
+            data = data[1 .. $]; // skip over sequence-terminating null
 
-        auto dirIndex = cast(size_t) data.readULEB128();
+            return result;
+        }
 
-        data.readULEB128(); // last mod
-        data.readULEB128(); // file len
+        /// Directories are simply a sequence of NUL-terminated strings
+        static const(char)[] readIncludeDirectoryEntry(ref const(ubyte)[] data)
+        {
+            return data.readStringz();
+        }
+        lp.includeDirectories = readSequence!readIncludeDirectoryEntry(data);
 
-        return SourceFile(
-            file,
-            dirIndex,
-        );
+        static SourceFile readFileNameEntry(ref const(ubyte)[] data)
+        {
+            const file = data.readStringz();
+            const dirIndex = cast(size_t) data.readULEB128();
+            data.readULEB128(); // last mod
+            data.readULEB128(); // file len
+
+            return SourceFile(
+                file,
+                dirIndex,
+            );
+        }
+        lp.sourceFiles = readSequence!readFileNameEntry(data);
     }
-    lp.sourceFiles = readSequence!readFileNameEntry(data);
 
     debug (DwarfDebugMachine)
     {
diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d
index c2701fa7af6..6aaef53f066 100644
--- a/libphobos/libdruntime/core/internal/dassert.d
+++ b/libphobos/libdruntime/core/internal/dassert.d
@@ -37,6 +37,10 @@ module core.internal.dassert;
  */
 string _d_assert_fail(A)(const scope string op, auto ref const scope A a)
 {
+    // Prevent InvalidMemoryOperationError when triggered from a finalizer
+    if (inFinalizer())
+        return "Assertion failed (rich formatting is disabled in finalizers)";
+
     string[2] vals = [ miniFormatFakeAttributes(a), "true" ];
     immutable token = op == "!" ? "==" : "!=";
     return combine(vals[0 .. 1], token, vals[1 .. $]);
@@ -62,6 +66,10 @@ template _d_assert_fail(A...)
         const scope string comp, auto ref const scope A a, auto ref const scope B b)
     if (B.length != 0 || A.length != 1) // Resolve ambiguity with unary overload
     {
+        // Prevent InvalidMemoryOperationError when triggered from a finalizer
+        if (inFinalizer())
+            return "Assertion failed (rich formatting is disabled in finalizers)";
+
         string[A.length + B.length] vals;
         static foreach (idx; 0 .. A.length)
             vals[idx] = miniFormatFakeAttributes(a[idx]);
@@ -401,22 +409,53 @@ private string miniFormat(V)(const scope ref V v)
 private string formatMembers(V)(const scope ref V v)
 {
     enum ctxPtr = __traits(isNested, V);
+    enum isOverlapped = calcFieldOverlap([ v.tupleof.offsetof ]);
+
     string msg = V.stringof ~ "(";
     foreach (i, ref field; v.tupleof)
     {
         if (i > 0)
             msg ~= ", ";
 
-        // Mark context pointer
-        static if (ctxPtr && i == v.tupleof.length - 1)
-            msg ~= "<context>: ";
+        static if (isOverlapped[i])
+        {
+            msg ~= "<overlapped field>";
+        }
+        else
+        {
+            // Mark context pointer
+            static if (ctxPtr && i == v.tupleof.length - 1)
+                msg ~= "<context>: ";
 
-        msg ~= miniFormat(field);
+            msg ~= miniFormat(field);
+        }
     }
     msg ~= ")";
     return msg;
 }
 
+/**
+ * Calculates whether fields are overlapped based on the passed offsets.
+ *
+ * Params:
+ *   offsets = offsets of all fields matching the order of `.tupleof`
+ *
+ * Returns: an array such that arr[n] = true indicates that the n'th field
+ *          overlaps with an adjacent field
+ **/
+private bool[] calcFieldOverlap(const scope size_t[] offsets)
+{
+    bool[] overlaps = new bool[](offsets.length);
+
+    foreach (const idx; 1 .. overlaps.length)
+    {
+        if (offsets[idx - 1] == offsets[idx])
+            overlaps[idx - 1] = overlaps[idx] = true;
+    }
+
+    return overlaps;
+}
+
 // This should be a local import in miniFormat but fails with a cyclic dependency error
 // core.thread.osthread -> core.time -> object -> core.internal.array.capacity
 // -> core.atomic -> core.thread -> core.thread.osthread
@@ -476,6 +515,14 @@ private auto pureAlloc(size_t t)
     return assumeFakeAttributes(&alloc)(t);
 }
 
+/// Wrapper for GC.inFinalizer that fakes purity
+private bool inFinalizer()() pure nothrow @nogc @safe
+{
+    // CTFE doesn't trigger InvalidMemoryErrors
+    import core.memory : GC;
+    return !__ctfe && assumeFakeAttributes(&GC.inFinalizer)();
+}
+
 // https://issues.dlang.org/show_bug.cgi?id=21544
 unittest
 {
diff --git a/libphobos/libdruntime/core/internal/hash.d b/libphobos/libdruntime/core/internal/hash.d
index 668fc4d8e28..e999f0cada9 100644
--- a/libphobos/libdruntime/core/internal/hash.d
+++ b/libphobos/libdruntime/core/internal/hash.d
@@ -130,16 +130,10 @@ private template canBitwiseHash(T)
 
 //enum hash. CTFE depends on base type
 size_t hashOf(T)(auto ref T val, size_t seed = 0)
-if (is(T EType == enum) && (!__traits(isScalar, T) || is(T == __vector)))
+if (is(T == enum) && !__traits(isScalar, T))
 {
-    static if (is(T EType == enum)) //for EType
-    {
-        return hashOf(cast(EType) val, seed);
-    }
-    else
-    {
-        static assert(0);
-    }
+    static if (is(T EType == enum)) {} //for EType
+    return hashOf(cast(EType) val, seed);
 }
 
 //CTFE ready (depends on base type).
@@ -261,6 +255,11 @@ size_t hashOf(T)(scope const T val) if (__traits(isScalar, T) && !is(T == __vect
         size_t result = cast(size_t) val;
         return result ^ (result >> 4);
     }
+    else static if (is(T EType == enum) && is(typeof(val[0])))
+    {
+        // Enum type whose base type is vector.
+        return hashOf(cast(EType) val);
+    }
     else static if (__traits(isIntegral, T))
     {
         static if (T.sizeof <= size_t.sizeof)
@@ -301,6 +300,11 @@ size_t hashOf(T)(scope const T val, size_t seed) if (__traits(isScalar, T) && !i
         }
         return hashOf(cast(size_t) val, seed);
     }
+    else static if (is(T EType == enum) && is(typeof(val[0])))
+    {
+        // Enum type whose base type is vector.
+        return hashOf(cast(EType) val, seed);
+    }
     else static if (__traits(isIntegral, val) && T.sizeof <= size_t.sizeof)
     {
         static if (size_t.sizeof < ulong.sizeof)
@@ -357,8 +361,8 @@ size_t hashOf(T)(scope const T val, size_t seed) if (__traits(isScalar, T) && !i
     }
 }
 
-size_t hashOf(T)(scope const auto ref T val, size_t seed = 0) @safe @nogc nothrow pure
-if (is(T == __vector) && !is(T == enum))
+size_t hashOf(T)(scope const T val, size_t seed = 0) @safe @nogc nothrow pure
+if (is(T == __vector)) // excludes enum types
 {
     static if (__traits(isFloating, T) && (floatCoalesceZeroes || floatCoalesceNaNs))
     {
@@ -400,10 +404,21 @@ q{
     static if (!isChained) enum size_t seed = 0;
     static if (hasCallableToHash!(typeof(val))) //CTFE depends on toHash()
     {
-        static if (isChained)
-            return hashOf(cast(size_t) val.toHash(), seed);
+        static if (!__traits(isSame, typeof(val), __traits(parent, val.toHash))
+            && is(typeof(val is null)))
+        {
+            static if (isChained)
+                return hashOf(__traits(getMember, val, __traits(getAliasThis, typeof(val))), seed);
+            else
+                return hashOf(__traits(getMember, val, __traits(getAliasThis, typeof(val))));
+        }
         else
-            return val.toHash();
+        {
+            static if (isChained)
+                return hashOf(cast(size_t) val.toHash(), seed);
+            else
+                return val.toHash();
+        }
     }
     else
     {
@@ -452,10 +467,21 @@ q{
                 {
                     static if (hasCallableToHash!F)
                     {
-                        static if (i == 0 && !isChained)
-                            size_t h = val.tupleof[i].toHash();
+                        static if (!__traits(isSame, F, __traits(parent, val.tupleof[i].toHash))
+                            && is(typeof(val.tupleof[i] is null)))
+                        {
+                            static if (i == 0 && !isChained)
+                                size_t h = hashOf(__traits(getMember, val.tupleof[i], __traits(getAliasThis, F)));
+                            else
+                                h = hashOf(__traits(getMember, val.tupleof[i], __traits(getAliasThis, F)), h);
+                        }
                         else
-                            h = hashOf(cast(size_t) val.tupleof[i].toHash(), h);
+                        {
+                            static if (i == 0 && !isChained)
+                                size_t h = val.tupleof[i].toHash();
+                            else
+                                h = hashOf(cast(size_t) val.tupleof[i].toHash(), h);
+                        }
                     }
                     else static if (F.tupleof.length == 1)
                     {
@@ -580,7 +606,13 @@ if (!is(T == enum) && (is(T == interface) || is(T == class))
     && !canBitwiseHash!T)
 {
     static if (__traits(compiles, {size_t h = val.toHash();}))
-        return val ? val.toHash() : 0;
+    {
+        static if (is(__traits(parent, val.toHash) P) && !is(immutable T* : immutable P*)
+                && is(typeof((ref P p) => p is null)))
+            return val ? hashOf(__traits(getMember, val, __traits(getAliasThis, T))) : 0;
+        else
+            return val ? val.toHash() : 0;
+    }
     else
         return val ? (cast(Object)val).toHash() : 0;
 }
@@ -591,7 +623,14 @@ if (!is(T == enum) && (is(T == interface) || is(T == class))
     && !canBitwiseHash!T)
 {
     static if (__traits(compiles, {size_t h = val.toHash();}))
-        return hashOf(val ? cast(size_t) val.toHash() : size_t(0), seed);
+    {
+        static if (is(__traits(parent, val.toHash) P) && !is(immutable T* : immutable P*)
+                && is(typeof((ref P p) => p is null)))
+            return hashOf(val ? hashOf(__traits(getMember, val, __traits(getAliasThis, T)))
+                              : size_t(0), seed);
+        else
+            return hashOf(val ? cast(size_t) val.toHash() : size_t(0), seed);
+    }
     else
         return hashOf(val ? (cast(Object)val).toHash() : 0, seed);
 }
diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d
index 7836812e16b..fc47b1d9394 100644
--- a/libphobos/libdruntime/core/lifetime.d
+++ b/libphobos/libdruntime/core/lifetime.d
@@ -1915,7 +1915,7 @@ pure nothrow @safe @nogc unittest
     static assert(is(typeof({ S s; move(s, s); }) == T));
 }
 
-private void moveImpl(T)(scope ref T target, return ref T source)
+private void moveImpl(T)(scope ref T target, return scope ref T source)
 {
     import core.internal.traits : hasElaborateDestructor;
 
@@ -1930,7 +1930,7 @@ private void moveImpl(T)(scope ref T target, return ref T source)
     moveEmplaceImpl(target, source);
 }
 
-private T moveImpl(T)(ref T source)
+private T moveImpl(T)(return scope ref T source)
 {
     // Properly infer safety from moveEmplaceImpl as the implementation below
     // might void-initialize pointers in result and hence needs to be @trusted
@@ -1939,7 +1939,7 @@ private T moveImpl(T)(ref T source)
     return trustedMoveImpl(source);
 }
 
-private T trustedMoveImpl(T)(ref T source) @trusted
+private T trustedMoveImpl(T)(return scope ref T source) @trusted
 {
     T result = void;
     moveEmplaceImpl(result, source);
diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d
index 7669c20645d..bfb72e07b05 100644
--- a/libphobos/libdruntime/core/runtime.d
+++ b/libphobos/libdruntime/core/runtime.d
@@ -785,7 +785,7 @@ version (DRuntime_Use_Libunwind)
     alias DefaultTraceInfo = LibunwindHandler;
 }
 /// Default implementation for most POSIX systems
-static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInfo
+else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInfo
 {
     import core.demangle;
     import core.stdc.stdlib : free;
diff --git a/libphobos/libdruntime/core/sys/posix/fcntl.d b/libphobos/libdruntime/core/sys/posix/fcntl.d
index 59df921ba41..6d9eb7846d6 100644
--- a/libphobos/libdruntime/core/sys/posix/fcntl.d
+++ b/libphobos/libdruntime/core/sys/posix/fcntl.d
@@ -895,10 +895,10 @@ else version (CRuntime_Musl)
         O_SEARCH        = O_PATH,
         O_EXEC          = O_PATH,
 
-        O_ACCMODE       = (03|O_SEARCH),
-        O_RDONLY        = 00,
-        O_WRONLY        = 01,
-        O_RDWR          = 02,
+        O_ACCMODE       = (3|O_SEARCH),
+        O_RDONLY        = 0,
+        O_WRONLY        = 1,
+        O_RDWR          = 2,
     }
     enum
     {
diff --git a/libphobos/libdruntime/core/sys/windows/sqlext.d b/libphobos/libdruntime/core/sys/windows/sqlext.d
index 3acfc5aa70c..1f891056a82 100644
--- a/libphobos/libdruntime/core/sys/windows/sqlext.d
+++ b/libphobos/libdruntime/core/sys/windows/sqlext.d
@@ -535,7 +535,7 @@ enum SQL_U_UNION_ALL = 2;
 
 enum SQL_UB_OFF = 0UL;
 enum SQL_UB_DEFAULT = SQL_UB_OFF;
-enum SQL_UB_ON = 01UL;
+enum SQL_UB_ON = 1UL;
 
 enum SQL_UNION = 96;
 enum SQL_UNSEARCHABLE = 0;
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index cec2ef561f4..a8dd832eeed 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -2194,7 +2194,7 @@ const:
      * Returns:
      *  array of pointers to the ModuleInfo's of modules imported by this one
      */
-    @property immutable(ModuleInfo*)[] importedModules() nothrow pure @nogc
+    @property immutable(ModuleInfo*)[] importedModules() return nothrow pure @nogc
     {
         if (flags & MIimportedModules)
         {
@@ -2208,7 +2208,7 @@ const:
      * Returns:
      *  array of TypeInfo_Class references for classes defined in this module
      */
-    @property TypeInfo_Class[] localClasses() nothrow pure @nogc
+    @property TypeInfo_Class[] localClasses() return nothrow pure @nogc
     {
         if (flags & MIlocalClasses)
         {
@@ -2222,7 +2222,7 @@ const:
      * Returns:
      *  name of module, `null` if no name
      */
-    @property string name() nothrow pure @nogc
+    @property string name() return nothrow pure @nogc
     {
         import core.stdc.string : strlen;
 
@@ -3505,7 +3505,7 @@ private U[] _dup(T, U)(scope T[] a) pure nothrow @trusted if (__traits(isPOD, T)
     return *cast(U[]*) &arr;
 }
 
-private U[] _dupCtfe(T, U)(T[] a)
+private U[] _dupCtfe(T, U)(scope T[] a)
 {
     static if (is(T : void))
         assert(0, "Cannot dup a void[] array at compile time.");
@@ -3546,6 +3546,21 @@ private U[] _dup(T, U)(T[] a) if (!__traits(isPOD, T))
     return res;
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22107
+@safe unittest
+{
+    static int i;
+    @safe struct S
+    {
+        this(this) { i++; }
+    }
+
+    void fun(scope S[] values...) @safe
+    {
+        values.dup;
+    }
+}
+
 // HACK:  This is a lie.  `_d_arraysetcapacity` is neither `nothrow` nor `pure`, but this lie is
 // necessary for now to prevent breaking code.
 private extern (C) size_t _d_arraysetcapacity(const TypeInfo ti, size_t newcapacity, void[]* arrptr) pure nothrow;
@@ -3820,7 +3835,7 @@ private void _doPostblit(T)(T[] arr)
 
     [].dup!Sunpure;
     [].dup!Sthrow;
-    [].dup!Sunsafe;
+    cast(void) [].dup!Sunsafe;
     static assert(!__traits(compiles, () pure    { [].dup!Sunpure; }));
     static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
     static assert(!__traits(compiles, () @safe   { [].dup!Sunsafe; }));
@@ -3871,7 +3886,7 @@ private void _doPostblit(T)(T[] arr)
     static struct Sunsafe { this(ref const typeof(this)) @system pure nothrow {} }
     [].dup!Sunpure;
     [].dup!Sthrow;
-    [].dup!Sunsafe;
+    cast(void) [].dup!Sunsafe;
     static assert(!__traits(compiles, () pure    { [].dup!Sunpure; }));
     static assert(!__traits(compiles, () nothrow { [].dup!Sthrow; }));
     static assert(!__traits(compiles, () @safe   { [].dup!Sunsafe; }));
diff --git a/libphobos/src/std/algorithm/comparison.d b/libphobos/src/std/algorithm/comparison.d
index dd42bff7e9c..c9525445ceb 100644
--- a/libphobos/src/std/algorithm/comparison.d
+++ b/libphobos/src/std/algorithm/comparison.d
@@ -1516,7 +1516,7 @@ Iterates the passed arguments and returns the maximum value.
 
 Params:
     args = The values to select the maximum from. At least two arguments must
-    be passed, and they must be comparable with `>`.
+    be passed, and they must be comparable with `<`.
 
 Returns:
     The maximum of the passed-in values. The type of the returned value is
@@ -1564,6 +1564,16 @@ if (T.length >= 2 && !is(CommonType!T == void))
     return cast(Result) (chooseB ? b : a);
 }
 
+/// ditto
+T max(T, U)(T a, U b)
+if (is(T == U) && is(typeof(a < b)))
+{
+   /* Handle the common case without all the template expansions
+    * of the general case
+    */
+    return a < b ? b : a;
+}
+
 ///
 @safe @betterC @nogc unittest
 {
@@ -1664,6 +1674,17 @@ if (T.length >= 2 && !is(CommonType!T == void))
     return cast(Result) (chooseB ? b : a);
 }
 
+/// ditto
+T min(T, U)(T a, U b)
+if (is(T == U) && is(typeof(a < b)))
+{
+   /* Handle the common case without all the template expansions
+    * of the general case
+    */
+    return b < a ? b : a;
+}
+
+
 ///
 @safe @nogc @betterC unittest
 {
diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d
index 6d1e2313bb6..88191bbf3f7 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -1074,7 +1074,7 @@ Params:
 */
 void move(T)(ref T source, ref T target)
 {
-    moveImpl(source, target);
+    moveImpl(target, source);
 }
 
 /// For non-struct types, `move` just performs `target = source`:
@@ -1244,7 +1244,7 @@ pure nothrow @safe @nogc unittest
     static assert(is(typeof({ S s; move(s, s); }) == T));
 }
 
-private void moveImpl(T)(ref T source, ref T target)
+private void moveImpl(T)(ref scope T target, ref return scope T source)
 {
     import std.traits : hasElaborateDestructor;
 
@@ -1257,10 +1257,10 @@ private void moveImpl(T)(ref T source, ref T target)
         static if (hasElaborateDestructor!T) target.__xdtor();
     }
     // move and emplace source into target
-    moveEmplaceImpl(source, target);
+    moveEmplaceImpl(target, source);
 }
 
-private T moveImpl(T)(ref T source)
+private T moveImpl(T)(ref return scope T source)
 {
     // Properly infer safety from moveEmplaceImpl as the implementation below
     // might void-initialize pointers in result and hence needs to be @trusted
@@ -1269,10 +1269,10 @@ private T moveImpl(T)(ref T source)
     return trustedMoveImpl(source);
 }
 
-private T trustedMoveImpl(T)(ref T source) @trusted
+private T trustedMoveImpl(T)(ref return scope T source) @trusted
 {
     T result = void;
-    moveEmplaceImpl(source, result);
+    moveEmplaceImpl(result, source);
     return result;
 }
 
@@ -1415,7 +1415,7 @@ private T trustedMoveImpl(T)(ref T source) @trusted
     move(x, x);
 }
 
-private void moveEmplaceImpl(T)(ref T source, ref T target)
+private void moveEmplaceImpl(T)(ref scope T target, ref return scope T source)
 {
     import core.stdc.string : memcpy, memset;
     import std.traits : hasAliasing, hasElaborateAssign,
@@ -1486,7 +1486,7 @@ private void moveEmplaceImpl(T)(ref T source, ref T target)
  */
 void moveEmplace(T)(ref T source, ref T target) pure @system
 {
-    moveEmplaceImpl(source, target);
+    moveEmplaceImpl(target, source);
 }
 
 ///
@@ -2388,7 +2388,7 @@ Range remove(alias pred, SwapStrategy s = SwapStrategy.stable, Range)(Range rang
 @nogc @safe unittest
 {
     // @nogc test
-    int[10] arr = [0,1,2,3,4,5,6,7,8,9];
+    static int[] arr = [0,1,2,3,4,5,6,7,8,9];
     alias pred = e => e < 5;
 
     auto r = arr[].remove!(SwapStrategy.unstable)(0);
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index bca137dbf58..0466c08ce7a 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -1953,7 +1953,7 @@ private enum bool hasCheapIteration(R) = isArray!R;
    See_Also:
         For a lazy version, see $(REF joiner, std,algorithm,iteration)
   +/
-ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, scope R sep)
+ElementEncodingType!(ElementType!RoR)[] join(RoR, R)(RoR ror, R sep)
 if (isInputRange!RoR &&
     isInputRange!(Unqual!(ElementType!RoR)) &&
     isInputRange!R &&
@@ -3265,7 +3265,7 @@ if (isDynamicArray!A)
     {
         size_t capacity;
         Unqual!T[] arr;
-        bool canExtend = false;
+        bool tryExtendBlock = false;
     }
 
     private Data* _data;
@@ -3276,7 +3276,7 @@ if (isDynamicArray!A)
      * it will be used by the appender.  After initializing an appender on an array,
      * appending to the original array will reallocate.
      */
-    this(A arr) @trusted pure nothrow
+    this(A arr) @trusted
     {
         // initialize to a given array.
         _data = new Data;
@@ -3325,7 +3325,7 @@ if (isDynamicArray!A)
      * managed array can accommodate before triggering a reallocation). If any
      * appending will reallocate, `0` will be returned.
      */
-    @property size_t capacity() const @safe pure nothrow
+    @property size_t capacity() const
     {
         return _data ? _data.capacity : 0;
     }
@@ -3334,7 +3334,7 @@ if (isDynamicArray!A)
      * Use opSlice() from now on.
      * Returns: The managed array.
      */
-    @property inout(ElementEncodingType!A)[] data() inout @trusted pure nothrow
+    @property inout(T)[] data() inout @trusted
     {
         return this[];
     }
@@ -3342,7 +3342,7 @@ if (isDynamicArray!A)
     /**
      * Returns: The managed array.
      */
-    @property inout(ElementEncodingType!A)[] opSlice() inout @trusted pure nothrow
+    @property inout(T)[] opSlice() inout @trusted
     {
         /* @trusted operation:
          * casting Unqual!T[] to inout(T)[]
@@ -3385,7 +3385,7 @@ if (isDynamicArray!A)
             // have better access to the capacity field.
             auto newlen = appenderNewCapacity!(T.sizeof)(_data.capacity, reqlen);
             // first, try extending the current block
-            if (_data.canExtend)
+            if (_data.tryExtendBlock)
             {
                 immutable u = (() @trusted => GC.extend(_data.arr.ptr, nelems * T.sizeof, (newlen - len) * T.sizeof))();
                 if (u)
@@ -3410,7 +3410,7 @@ if (isDynamicArray!A)
             if (len)
                 () @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
             _data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
-            _data.canExtend = true;
+            _data.tryExtendBlock = true;
             // leave the old data, for safety reasons
         }
     }
@@ -3653,7 +3653,7 @@ if (isDynamicArray!A)
 }
 
 ///
-@safe unittest
+@safe pure nothrow unittest
 {
     auto app = appender!string();
     string b = "abcdefg";
@@ -3691,7 +3691,7 @@ if (isDynamicArray!A)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=17251
-@safe unittest
+@safe pure nothrow unittest
 {
     static struct R
     {
@@ -3707,7 +3707,7 @@ if (isDynamicArray!A)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=13300
-@safe unittest
+@safe pure nothrow unittest
 {
     static test(bool isPurePostblit)()
     {
@@ -3743,7 +3743,7 @@ if (isDynamicArray!A)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=19572
-@system unittest
+@safe pure nothrow unittest
 {
     static struct Struct
     {
@@ -3763,7 +3763,7 @@ if (isDynamicArray!A)
     assert(result.value != 23);
 }
 
-@safe unittest
+@safe pure unittest
 {
     import std.conv : to;
     import std.utf : byCodeUnit;
@@ -3774,7 +3774,7 @@ if (isDynamicArray!A)
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=21256
-@safe unittest
+@safe pure unittest
 {
     Appender!string app1;
     app1.toString();
@@ -3788,7 +3788,7 @@ if (isDynamicArray!A)
 //arg curLen: The current length
 //arg reqLen: The length as requested by the user
 //ret sugLen: A suggested growth.
-private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen) @safe pure nothrow
+private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen)
 {
     import core.bitop : bsr;
     import std.algorithm.comparison : max;
@@ -3816,6 +3816,8 @@ private size_t appenderNewCapacity(size_t TSizeOf)(size_t curLen, size_t reqLen)
 struct RefAppender(A)
 if (isDynamicArray!A)
 {
+    private alias T = ElementEncodingType!A;
+
     private
     {
         Appender!A impl;
@@ -3878,7 +3880,7 @@ if (isDynamicArray!A)
     /* Use opSlice() instead.
      * Returns: the managed array.
      */
-    @property inout(ElementEncodingType!A)[] data() inout
+    @property inout(T)[] data() inout
     {
         return impl[];
     }
@@ -3893,7 +3895,7 @@ if (isDynamicArray!A)
 }
 
 ///
-@system pure nothrow
+@safe pure nothrow
 unittest
 {
     int[] a = [1, 2];
@@ -3929,63 +3931,48 @@ Appender!(E[]) appender(A : E[], E)(auto ref A array)
 
 @safe pure nothrow unittest
 {
-    import std.exception;
-    {
-        auto app = appender!(char[])();
-        string b = "abcdefg";
-        foreach (char c; b) app.put(c);
-        assert(app[] == "abcdefg");
-    }
-    {
-        auto app = appender!(char[])();
-        string b = "abcdefg";
-        foreach (char c; b) app ~= c;
-        assert(app[] == "abcdefg");
-    }
-    {
-        int[] a = [ 1, 2 ];
-        auto app2 = appender(a);
-        assert(app2[] == [ 1, 2 ]);
-        app2.put(3);
-        app2.put([ 4, 5, 6 ][]);
-        assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
-        app2.put([ 7 ]);
-        assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
-    }
+    auto app = appender!(char[])();
+    string b = "abcdefg";
+    foreach (char c; b) app.put(c);
+    assert(app[] == "abcdefg");
+}
 
+@safe pure nothrow unittest
+{
+    auto app = appender!(char[])();
+    string b = "abcdefg";
+    foreach (char c; b) app ~= c;
+    assert(app[] == "abcdefg");
+}
+
+@safe pure nothrow unittest
+{
     int[] a = [ 1, 2 ];
     auto app2 = appender(a);
     assert(app2[] == [ 1, 2 ]);
-    app2 ~= 3;
-    app2 ~= [ 4, 5, 6 ][];
+    app2.put(3);
+    app2.put([ 4, 5, 6 ][]);
     assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
-    app2 ~= [ 7 ];
+    app2.put([ 7 ]);
     assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
+}
 
-    app2.reserve(5);
-    assert(app2.capacity >= 5);
-
-    try // shrinkTo may throw
-    {
-        app2.shrinkTo(3);
-    }
-    catch (Exception) assert(0);
-    assert(app2[] == [ 1, 2, 3 ]);
-    assertThrown(app2.shrinkTo(5));
-
-    const app3 = app2;
-    assert(app3.capacity >= 3);
-    assert(app3[] == [1, 2, 3]);
-
+@safe pure nothrow unittest
+{
     auto app4 = appender([]);
     try // shrinkTo may throw
     {
         app4.shrinkTo(0);
     }
     catch (Exception) assert(0);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=5663
+// https://issues.dlang.org/show_bug.cgi?id=9725
+@safe pure nothrow unittest
+{
+    import std.exception : assertNotThrown;
 
-    // https://issues.dlang.org/show_bug.cgi?id=5663
-    // https://issues.dlang.org/show_bug.cgi?id=9725
     static foreach (S; AliasSeq!(char[], const(char)[], string))
     {
         {
@@ -4016,6 +4003,12 @@ Appender!(E[]) appender(A : E[], E)(auto ref A array)
             assert(app5663m[] == "\xE3");
         }
     }
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=10122
+@safe pure nothrow unittest
+{
+    import std.exception : assertCTFEable;
 
     static struct S10122
     {
@@ -4032,6 +4025,35 @@ Appender!(E[]) appender(A : E[], E)(auto ref A array)
     });
 }
 
+@safe pure nothrow unittest
+{
+    import std.exception : assertThrown;
+
+    int[] a = [ 1, 2 ];
+    auto app2 = appender(a);
+    assert(app2[] == [ 1, 2 ]);
+    app2 ~= 3;
+    app2 ~= [ 4, 5, 6 ][];
+    assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
+    app2 ~= [ 7 ];
+    assert(app2[] == [ 1, 2, 3, 4, 5, 6, 7 ]);
+
+    app2.reserve(5);
+    assert(app2.capacity >= 5);
+
+    try // shrinkTo may throw
+    {
+        app2.shrinkTo(3);
+    }
+    catch (Exception) assert(0);
+    assert(app2[] == [ 1, 2, 3 ]);
+    assertThrown(app2.shrinkTo(5));
+
+    const app3 = app2;
+    assert(app3.capacity >= 3);
+    assert(app3[] == [1, 2, 3]);
+}
+
 ///
 @safe pure nothrow
 unittest
@@ -4053,63 +4075,63 @@ unittest
 
 @safe pure nothrow unittest
 {
+    auto w = appender!string();
+    w.reserve(4);
+    cast(void) w.capacity;
+    cast(void) w[];
+    try
     {
-        auto w = appender!string();
-        w.reserve(4);
-        cast(void) w.capacity;
-        cast(void) w[];
-        try
-        {
-            wchar wc = 'a';
-            dchar dc = 'a';
-            w.put(wc);    // decoding may throw
-            w.put(dc);    // decoding may throw
-        }
-        catch (Exception) assert(0);
+        wchar wc = 'a';
+        dchar dc = 'a';
+        w.put(wc);    // decoding may throw
+        w.put(dc);    // decoding may throw
     }
+    catch (Exception) assert(0);
+}
+
+@safe pure nothrow unittest
+{
+    auto w = appender!(int[])();
+    w.reserve(4);
+    cast(void) w.capacity;
+    cast(void) w[];
+    w.put(10);
+    w.put([10]);
+    w.clear();
+    try
     {
-        auto w = appender!(int[])();
-        w.reserve(4);
-        cast(void) w.capacity;
-        cast(void) w[];
-        w.put(10);
-        w.put([10]);
-        w.clear();
-        try
-        {
-            w.shrinkTo(0);
-        }
-        catch (Exception) assert(0);
+        w.shrinkTo(0);
+    }
+    catch (Exception) assert(0);
 
-        struct N
-        {
-            int payload;
-            alias payload this;
-        }
-        w.put(N(1));
-        w.put([N(2)]);
+    struct N
+    {
+        int payload;
+        alias payload this;
+    }
+    w.put(N(1));
+    w.put([N(2)]);
 
-        struct S(T)
-        {
-            @property bool empty() { return true; }
-            @property T front() { return T.init; }
-            void popFront() {}
-        }
-        S!int r;
-        w.put(r);
+    struct S(T)
+    {
+        @property bool empty() { return true; }
+        @property T front() { return T.init; }
+        void popFront() {}
     }
+    S!int r;
+    w.put(r);
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=10690
-@safe unittest
+@safe pure nothrow unittest
 {
-    import std.algorithm;
-    import std.typecons;
+    import std.algorithm.iteration : filter;
+    import std.typecons : tuple;
     [tuple(1)].filter!(t => true).array; // No error
     [tuple("A")].filter!(t => true).array; // error
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     import std.range;
     //Coverage for put(Range)
@@ -4129,7 +4151,7 @@ unittest
     au1.put(sc1.repeat().take(10));
 }
 
-@system unittest
+@system pure unittest
 {
     import std.range;
     struct S2
@@ -4141,7 +4163,7 @@ unittest
     au2.put(sc2.repeat().take(10));
 }
 
-@system unittest
+@system pure nothrow unittest
 {
     struct S
     {
@@ -4175,7 +4197,7 @@ unittest
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=9528
-@safe unittest
+@safe pure nothrow unittest
 {
     const(E)[] fastCopy(E)(E[] src) {
             auto app = appender!(const(E)[])();
@@ -4193,7 +4215,7 @@ unittest
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=10753
-@safe unittest
+@safe pure unittest
 {
     import std.algorithm.iteration : map;
     struct Foo {
@@ -4206,7 +4228,7 @@ unittest
     [1, 2].map!Bar.array;
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     import std.algorithm.comparison : equal;
 
@@ -4255,7 +4277,7 @@ unittest
     assert(app8[] == null);
 }
 
-@safe unittest //Test large allocations (for GC.extend)
+@safe pure nothrow unittest //Test large allocations (for GC.extend)
 {
     import std.algorithm.comparison : equal;
     import std.range;
@@ -4266,7 +4288,7 @@ unittest
     assert(equal(app[], 'a'.repeat(100_000)));
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     auto reference = new ubyte[](2048 + 1); //a number big enough to have a full page (EG: the GC extends)
     auto arr = reference.dup;
@@ -4276,7 +4298,7 @@ unittest
     assert(reference[] == arr[]);
 }
 
-@safe unittest // clear method is supported only for mutable element types
+@safe pure nothrow unittest // clear method is supported only for mutable element types
 {
     Appender!string app;
     app.put("foo");
@@ -4284,7 +4306,7 @@ unittest
     assert(app[] == "foo");
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     static struct D//dynamic
     {
@@ -4343,7 +4365,7 @@ RefAppender!(E[]) appender(P : E[]*, E)(P arrayPtr)
 }
 
 ///
-@system pure nothrow
+@safe pure nothrow
 unittest
 {
     int[] a = [1, 2];
@@ -4359,35 +4381,41 @@ unittest
     assert(app2.capacity >= 5);
 }
 
-@system unittest
+@safe pure nothrow unittest
 {
-    import std.exception;
-    {
-        auto arr = new char[0];
-        auto app = appender(&arr);
-        string b = "abcdefg";
-        foreach (char c; b) app.put(c);
-        assert(app[] == "abcdefg");
-        assert(arr == "abcdefg");
-    }
-    {
-        auto arr = new char[0];
-        auto app = appender(&arr);
-        string b = "abcdefg";
-        foreach (char c; b) app ~= c;
-        assert(app[] == "abcdefg");
-        assert(arr == "abcdefg");
-    }
-    {
-        int[] a = [ 1, 2 ];
-        auto app2 = appender(&a);
-        assert(app2[] == [ 1, 2 ]);
-        assert(a == [ 1, 2 ]);
-        app2.put(3);
-        app2.put([ 4, 5, 6 ][]);
-        assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
-        assert(a == [ 1, 2, 3, 4, 5, 6 ]);
-    }
+    auto arr = new char[0];
+    auto app = appender(&arr);
+    string b = "abcdefg";
+    foreach (char c; b) app.put(c);
+    assert(app[] == "abcdefg");
+    assert(arr == "abcdefg");
+}
+
+@safe pure nothrow unittest
+{
+    auto arr = new char[0];
+    auto app = appender(&arr);
+    string b = "abcdefg";
+    foreach (char c; b) app ~= c;
+    assert(app[] == "abcdefg");
+    assert(arr == "abcdefg");
+}
+
+@safe pure nothrow unittest
+{
+    int[] a = [ 1, 2 ];
+    auto app2 = appender(&a);
+    assert(app2[] == [ 1, 2 ]);
+    assert(a == [ 1, 2 ]);
+    app2.put(3);
+    app2.put([ 4, 5, 6 ][]);
+    assert(app2[] == [ 1, 2, 3, 4, 5, 6 ]);
+    assert(a == [ 1, 2, 3, 4, 5, 6 ]);
+}
+
+@safe pure nothrow unittest
+{
+    import std.exception : assertThrown;
 
     int[] a = [ 1, 2 ];
     auto app2 = appender(&a);
@@ -4415,13 +4443,13 @@ unittest
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=14605
-@safe unittest
+@safe pure nothrow unittest
 {
     static assert(isOutputRange!(Appender!(int[]), int));
     static assert(isOutputRange!(RefAppender!(int[]), int));
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     Appender!(int[]) app;
     short[] range = [1, 2, 3];
@@ -4429,7 +4457,7 @@ unittest
     assert(app[] == [1, 2, 3]);
 }
 
-@safe unittest
+@safe pure nothrow unittest
 {
     string s = "hello".idup;
     char[] a = "hello".dup;
@@ -4471,7 +4499,7 @@ pragma(inline, true) T[n] staticArray(T, size_t n)(auto ref T[n] a)
 }
 
 /// static array from array literal
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     auto a = [0, 1].staticArray;
     static assert(is(typeof(a) == int[2]));
@@ -4485,14 +4513,14 @@ if (!is(T == U) && is(T : U))
 }
 
 /// static array from array with implicit casting of elements
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     auto b = [0, 1].staticArray!long;
     static assert(is(typeof(b) == long[2]));
     assert(b == [0, 1]);
 }
 
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     int val = 3;
     static immutable gold = [1, 2, 3];
@@ -4589,7 +4617,7 @@ if (isInputRange!T && is(ElementType!T : U))
 }
 
 /// static array from range + size
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     import std.range : iota;
 
@@ -4605,8 +4633,7 @@ nothrow pure @safe unittest
 // Tests that code compiles when there is an elaborate destructor and exceptions
 // are thrown. Unfortunately can't test that memory is initialized
 // before having a destructor called on it.
-// @system required because of https://issues.dlang.org/show_bug.cgi?id=18872.
-@system nothrow unittest
+@safe nothrow unittest
 {
     // exists only to allow doing something in the destructor. Not tested
     // at the end because value appears to depend on implementation of the.
@@ -4644,7 +4671,7 @@ nothrow pure @safe unittest
 }
 
 
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     auto a = [1, 2].staticArray;
     assert(is(typeof(a) == int[2]) && a == [1, 2]);
@@ -4656,7 +4683,7 @@ nothrow pure @safe unittest
     2.iota.staticArray!(long[2]).checkStaticArray!long([0, 1]);
 }
 
-nothrow pure @system unittest
+nothrow pure @safe @nogc unittest
 {
     import std.range : iota;
     size_t copiedAmount;
@@ -4681,7 +4708,7 @@ if (isInputRange!(typeof(a)))
 }
 
 /// static array from CT range
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     import std.range : iota;
 
@@ -4694,7 +4721,7 @@ nothrow pure @safe unittest
     assert(b == [0, 1]);
 }
 
-nothrow pure @safe unittest
+nothrow pure @safe @nogc unittest
 {
     import std.range : iota;
 
diff --git a/libphobos/src/std/container/array.d b/libphobos/src/std/container/array.d
index 780b985e587..89ca4b24534 100644
--- a/libphobos/src/std/container/array.d
+++ b/libphobos/src/std/container/array.d
@@ -544,6 +544,17 @@ if (!is(immutable T == immutable bool))
         return _data.refCountedStore.isInitialized ? _data._capacity : 0;
     }
 
+    /**
+     * Returns: the internal representation of the array.
+     *
+     * Complexity: $(BIGOH 1).
+     */
+
+    T[] data() @system
+    {
+        return _data._payload;
+    }
+
     /**
      * Ensures sufficient capacity to accommodate `e` _elements.
      * If `e < capacity`, this method does nothing.
@@ -1559,7 +1570,7 @@ if (!is(immutable T == immutable bool))
     ai.insertBack(arr);
 }
 
-/**
+/*
  * typeof may give wrong result in case of classes defining `opCall` operator
  * https://issues.dlang.org/show_bug.cgi?id=20589
  *
@@ -2601,3 +2612,12 @@ if (is(immutable T == immutable bool))
     GC.collect();
     arr[1].func();
 }
+
+@system unittest
+{
+    Array!int arr = [1, 2, 4, 5];
+    int[] data = arr.data();
+
+    data[0] = 0;
+    assert(arr[0] == 0);
+}
diff --git a/libphobos/src/std/datetime/date.d b/libphobos/src/std/datetime/date.d
index fa78abe197d..ebdaba42a9d 100644
--- a/libphobos/src/std/datetime/date.d
+++ b/libphobos/src/std/datetime/date.d
@@ -3216,7 +3216,7 @@ public:
         assertThrown!DateTimeException(DateTime.fromISOString("2010-12-22T172201"));
         assertThrown!DateTimeException(DateTime.fromISOString("2010-Dec-22 17:22:01"));
 
-        assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+        assert(DateTime.fromISOString("20101222T172201") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1)));
         assert(DateTime.fromISOString("19990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
         assert(DateTime.fromISOString("-19990706T123033") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
         assert(DateTime.fromISOString("+019990706T123033") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
@@ -3316,7 +3316,7 @@ public:
         assertThrown!DateTimeException(DateTime.fromISOExtString("20101222T172201"));
         assertThrown!DateTimeException(DateTime.fromISOExtString("2010-Dec-22 17:22:01"));
 
-        assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+        assert(DateTime.fromISOExtString("2010-12-22T17:22:01") == DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1)));
         assert(DateTime.fromISOExtString("1999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
         assert(DateTime.fromISOExtString("-1999-07-06T12:30:33") == DateTime(Date(-1999, 7, 6), TimeOfDay(12, 30, 33)));
         assert(DateTime.fromISOExtString("+01999-07-06T12:30:33") == DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
@@ -3414,7 +3414,7 @@ public:
         assertThrown!DateTimeException(DateTime.fromSimpleString("2010-12-22T172201"));
 
         assert(DateTime.fromSimpleString("2010-Dec-22 17:22:01") ==
-               DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 01)));
+               DateTime(Date(2010, 12, 22), TimeOfDay(17, 22, 1)));
         assert(DateTime.fromSimpleString("1999-Jul-06 12:30:33") ==
                DateTime(Date(1999, 7, 6), TimeOfDay(12, 30, 33)));
         assert(DateTime.fromSimpleString("-1999-Jul-06 12:30:33") ==
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index 1e2d120fe03..9c051b452f7 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -8901,7 +8901,7 @@ public:
                 throw new AssertError("unittest failure", __FILE__, line);
         }
 
-        test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+        test("20101222T172201", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
         test("19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test("-19990706T123033", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
         test("+019990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
@@ -8909,16 +8909,16 @@ public:
         test(" 19990706T123033", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test(" 19990706T123033 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
 
-        test("19070707T121212.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("19070707T121212.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("19070707T121212.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
-        test("20100704T000000.00000000", SysTime(Date(2010, 07, 04)));
-        test("20100704T000000.00000009", SysTime(Date(2010, 07, 04)));
-        test("20100704T000000.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
-        test("19070707T121212.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("19070707T121212.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("19070707T121212.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
-        test("19070707T121212.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
+        test("19070707T121212.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("19070707T121212.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("19070707T121212.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
+        test("20100704T000000.00000000", SysTime(Date(2010, 7, 4)));
+        test("20100704T000000.00000009", SysTime(Date(2010, 7, 4)));
+        test("20100704T000000.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
+        test("19070707T121212.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("19070707T121212.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("19070707T121212.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
+        test("19070707T121212.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
 
         auto west60 = new immutable SimpleTimeZone(hours(-1));
         auto west90 = new immutable SimpleTimeZone(minutes(-90));
@@ -8927,32 +8927,32 @@ public:
         auto east90 = new immutable SimpleTimeZone(minutes(90));
         auto east480 = new immutable SimpleTimeZone(hours(8));
 
-        test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
-        test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
-        test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
-        test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
+        test("20101222T172201Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
+        test("20101222T172201-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("20101222T172201-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("20101222T172201-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
+        test("20101222T172201-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
+        test("20101222T172201+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("20101222T172201+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("20101222T172201+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("20101222T172201+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
 
         test("20101103T065106.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
-        test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
-        test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
-        test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
-        test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
-        test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
-        test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
-        test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
+        test("20101222T172201.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
+        test("20101222T172201.23112-0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
+        test("20101222T172201.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
+        test("20101222T172201.1-0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
+        test("20101222T172201.55-0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
+        test("20101222T172201.1234567+0100", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
+        test("20101222T172201.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("20101222T172201.0000000+0130", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("20101222T172201.45+0800", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
 
         // for dstring coverage
         assert(SysTime.fromISOString("20101222T172201.23112-0100"d) == SysTime(
-            DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
+            DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
         assert(SysTime.fromISOString("19070707T121212.0010000"d) == SysTime(
-            DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
+            DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
 
         // @@@DEPRECATED_2019-07@@@
         // This isn't deprecated per se, but that text will make it so that it
@@ -8964,19 +8964,19 @@ public:
         // These tests will then start failing will need to be updated accordingly.
         // Also, the notes about this issue in toISOString and fromISOString's
         // documentation will need to be removed.
-        test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
-        test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
-        test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
-
-        test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
-        test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
-        test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
-        test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
-        test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
+        test("20101222T172201-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("20101222T172201-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
+        test("20101222T172201-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
+        test("20101222T172201+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("20101222T172201+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("20101222T172201+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
+
+        test("20101222T172201.23112-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
+        test("20101222T172201.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
+        test("20101222T172201.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
+        test("20101222T172201.1234567+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
+        test("20101222T172201.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("20101222T172201.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
 
         static void testScope(scope ref string str) @safe
         {
@@ -9177,7 +9177,7 @@ public:
                 throw new AssertError("unittest failure", __FILE__, line);
         }
 
-        test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+        test("2010-12-22T17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
         test("1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test("-1999-07-06T12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
         test("+01999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
@@ -9185,16 +9185,16 @@ public:
         test(" 1999-07-06T12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test(" 1999-07-06T12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
 
-        test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
-        test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 07, 04)));
-        test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 07, 04)));
-        test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
-        test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
-        test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
+        test("1907-07-07T12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("1907-07-07T12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("1907-07-07T12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
+        test("2010-07-04T00:00:00.00000000", SysTime(Date(2010, 7, 4)));
+        test("2010-07-04T00:00:00.00000009", SysTime(Date(2010, 7, 4)));
+        test("2010-07-04T00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
+        test("1907-07-07T12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("1907-07-07T12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("1907-07-07T12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
+        test("1907-07-07T12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
 
         auto west60 = new immutable SimpleTimeZone(hours(-1));
         auto west90 = new immutable SimpleTimeZone(minutes(-90));
@@ -9203,28 +9203,28 @@ public:
         auto east90 = new immutable SimpleTimeZone(minutes(90));
         auto east480 = new immutable SimpleTimeZone(hours(8));
 
-        test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
-        test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
-        test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
-        test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
+        test("2010-12-22T17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
+        test("2010-12-22T17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("2010-12-22T17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("2010-12-22T17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
+        test("2010-12-22T17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
+        test("2010-12-22T17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-12-22T17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-12-22T17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("2010-12-22T17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
 
         test("2010-11-03T06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
-        test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
+        test("2010-12-22T17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
         test("2010-12-22T17:22:01.23112-01:00",
-             SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
-        test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
-        test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
-        test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
+             SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
+        test("2010-12-22T17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
+        test("2010-12-22T17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
+        test("2010-12-22T17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
         test("2010-12-22T17:22:01.1234567+01:00",
-             SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
-        test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
+             SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
+        test("2010-12-22T17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-12-22T17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("2010-12-22T17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
 
         static void testScope(scope ref string str) @safe
         {
@@ -9429,7 +9429,7 @@ public:
                 throw new AssertError("unittest failure", __FILE__, line);
         }
 
-        test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 01)));
+        test("2010-Dec-22 17:22:01", SysTime(DateTime(2010, 12, 22, 17, 22, 1)));
         test("1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test("-1999-Jul-06 12:30:33", SysTime(DateTime(-1999, 7, 6, 12, 30, 33)));
         test("+01999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
@@ -9437,16 +9437,16 @@ public:
         test(" 1999-Jul-06 12:30:33", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
         test(" 1999-Jul-06 12:30:33 ", SysTime(DateTime(1999, 7, 6, 12, 30, 33)));
 
-        test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 07, 07, 12, 12, 12)));
-        test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 07, 04)));
-        test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 07, 04)));
-        test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 07, 04), hnsecs(1)));
-        test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), hnsecs(1)));
-        test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 07, 07, 12, 12, 12), usecs(1)));
-        test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
-        test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 07, 07, 12, 12, 12), msecs(1)));
+        test("1907-Jul-07 12:12:12.0", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("1907-Jul-07 12:12:12.0000000", SysTime(DateTime(1907, 7, 7, 12, 12, 12)));
+        test("2010-Jul-04 00:00:00.00000000", SysTime(Date(2010, 7, 4)));
+        test("2010-Jul-04 00:00:00.00000009", SysTime(Date(2010, 7, 4)));
+        test("2010-Jul-04 00:00:00.00000019", SysTime(DateTime(2010, 7, 4), hnsecs(1)));
+        test("1907-Jul-07 12:12:12.0000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), hnsecs(1)));
+        test("1907-Jul-07 12:12:12.000001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("1907-Jul-07 12:12:12.0000010", SysTime(DateTime(1907, 7, 7, 12, 12, 12), usecs(1)));
+        test("1907-Jul-07 12:12:12.001", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
+        test("1907-Jul-07 12:12:12.0010000", SysTime(DateTime(1907, 7, 7, 12, 12, 12), msecs(1)));
 
         auto west60 = new immutable SimpleTimeZone(hours(-1));
         auto west90 = new immutable SimpleTimeZone(minutes(-90));
@@ -9455,28 +9455,28 @@ public:
         auto east90 = new immutable SimpleTimeZone(minutes(90));
         auto east480 = new immutable SimpleTimeZone(hours(8));
 
-        test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), UTC()));
-        test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west60));
-        test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west90));
-        test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), west480));
-        test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east480));
+        test("2010-Dec-22 17:22:01Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), UTC()));
+        test("2010-Dec-22 17:22:01-01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("2010-Dec-22 17:22:01-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west60));
+        test("2010-Dec-22 17:22:01-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west90));
+        test("2010-Dec-22 17:22:01-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), west480));
+        test("2010-Dec-22 17:22:01+01:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-Dec-22 17:22:01+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-Dec-22 17:22:01+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("2010-Dec-22 17:22:01+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east480));
 
         test("2010-Nov-03 06:51:06.57159Z", SysTime(DateTime(2010, 11, 3, 6, 51, 6), hnsecs(5715900), UTC()));
-        test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_341_200), UTC()));
+        test("2010-Dec-22 17:22:01.23412Z", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_341_200), UTC()));
         test("2010-Dec-22 17:22:01.23112-01:00",
-             SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(2_311_200), west60));
-        test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), west60));
-        test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_000_000), west90));
-        test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(5_500_000), west480));
+             SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(2_311_200), west60));
+        test("2010-Dec-22 17:22:01.45-01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), west60));
+        test("2010-Dec-22 17:22:01.1-01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_000_000), west90));
+        test("2010-Dec-22 17:22:01.55-08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(5_500_000), west480));
         test("2010-Dec-22 17:22:01.1234567+01:00",
-             SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(1_234_567), east60));
-        test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east60));
-        test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 01), east90));
-        test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 01), hnsecs(4_500_000), east480));
+             SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(1_234_567), east60));
+        test("2010-Dec-22 17:22:01.0+01", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east60));
+        test("2010-Dec-22 17:22:01.0000000+01:30", SysTime(DateTime(2010, 12, 22, 17, 22, 1), east90));
+        test("2010-Dec-22 17:22:01.45+08:00", SysTime(DateTime(2010, 12, 22, 17, 22, 1), hnsecs(4_500_000), east480));
 
         static void testScope(scope ref string str) @safe
         {
@@ -9688,7 +9688,7 @@ long unixTimeToStdTime(long unixTime) @safe pure nothrow @nogc
 
     assert(unixTimeToStdTime(int.max) == 642_830_804_470_000_000L);
     assert(SysTime(unixTimeToStdTime(int.max)) ==
-           SysTime(DateTime(2038, 1, 19, 3, 14, 07), UTC()));
+           SysTime(DateTime(2038, 1, 19, 3, 14, 7), UTC()));
 
     assert(unixTimeToStdTime(-127_127) == 621_354_696_730_000_000L);
     assert(SysTime(unixTimeToStdTime(-127_127)) ==
@@ -10934,7 +10934,7 @@ version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t
 
         // test time zones
         {
-            auto dt = DateTime(1982, 05, 03, 12, 22, 04);
+            auto dt = DateTime(1982, 5, 3, 12, 22, 4);
             test("Wed, 03 May 1982 12:22:04 UT", SysTime(dt, UTC()));
             test("Wed, 03 May 1982 12:22:04 GMT", SysTime(dt, UTC()));
             test("Wed, 03 May 1982 12:22:04 EST", SysTime(dt, new immutable SimpleTimeZone(dur!"hours"(-5))));
@@ -10995,13 +10995,13 @@ version (StdUnittest) private void testBadParse822(alias cr)(string str, size_t
 
         // test that the checks for minimum length work correctly and avoid
         // any RangeErrors.
-        test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
+        test("7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
                                      new immutable SimpleTimeZone(Duration.zero)));
-        test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
+        test("Fri,7Dec1200:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
                                          new immutable SimpleTimeZone(Duration.zero)));
-        test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
+        test("7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
                                         new immutable SimpleTimeZone(Duration.zero)));
-        test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 00, 00, 00),
+        test("Fri,7Dec1200:00:00A", SysTime(DateTime(2012, 12, 7, 0, 0, 0),
                                             new immutable SimpleTimeZone(Duration.zero)));
 
         auto tooShortMsg = collectExceptionMsg!DateTimeException(parseRFC822DateTime(""));
diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d
index 108360a33ff..5df42e728c3 100644
--- a/libphobos/src/std/datetime/timezone.d
+++ b/libphobos/src/std/datetime/timezone.d
@@ -1702,7 +1702,7 @@ package:
         Params:
             isoExtString = A string which represents a time zone in the ISO format.
       +/
-    static immutable(SimpleTimeZone) fromISOExtString(S)(S isoExtString) @safe pure
+    static immutable(SimpleTimeZone) fromISOExtString(S)(scope S isoExtString) @safe pure
         if (isSomeString!S)
     {
         import std.algorithm.searching : startsWith;
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 9f26ebb53d1..6bcb231d717 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -1846,7 +1846,7 @@ else version (Posix)
         stat_t statbuf;
         // check that both lvalues and rvalues work
         timeLastAccessed(statbuf);
-        timeLastAccessed(stat_t.init);
+        cast(void) timeLastAccessed(stat_t.init);
     }
 }
 
diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d
index 486be66e5a9..59d784265c1 100644
--- a/libphobos/src/std/internal/math/biguintcore.d
+++ b/libphobos/src/std/internal/math/biguintcore.d
@@ -761,7 +761,7 @@ public:
 
     // If wantSub is false, return x + y, leaving sign unchanged
     // If wantSub is true, return abs(x - y), negating sign if x < y
-    static BigUint addOrSubInt(Tulong)(const BigUint x, Tulong y,
+    static BigUint addOrSubInt(Tulong)(const scope BigUint x, Tulong y,
             bool wantSub, ref bool sign) pure nothrow @safe if (is(Tulong == ulong))
     {
         BigUint r;
@@ -1380,7 +1380,7 @@ pure nothrow @safe
 }
 
 // Encode BigInt as BigDigit array (sign and 2's complement)
-BigDigit[] includeSign(const(BigDigit) [] x, size_t minSize, bool sign)
+BigDigit[] includeSign(scope const(BigDigit) [] x, size_t minSize, bool sign)
 pure nothrow @safe
 {
     size_t length = (x.length > minSize) ? x.length : minSize;
diff --git a/libphobos/src/std/math/operations.d b/libphobos/src/std/math/operations.d
index ec8966d4951..dfb1aeea587 100644
--- a/libphobos/src/std/math/operations.d
+++ b/libphobos/src/std/math/operations.d
@@ -1717,7 +1717,7 @@ if (isFloatingPoint!T)
     bool negative;
 }
 
-FloatingPointBitpattern!T extractBitpattern(T)(T val)
+FloatingPointBitpattern!T extractBitpattern(T)(T val) @trusted
 if (isFloatingPoint!T)
 {
     import std.math : floatTraits, RealFormat;
@@ -1729,9 +1729,9 @@ if (isFloatingPoint!T)
     {
         if (__ctfe)
         {
-            import core.math : fabs;
+            import core.math : fabs, ldexp;
             import std.math.rounding : floor;
-            import std.math.traits : isInfinity, isNaN;
+            import std.math.traits : isInfinity, isNaN, signbit;
             import std.math.exponential : log2;
 
             if (isNaN(val) || isInfinity(val))
@@ -1750,19 +1750,9 @@ if (isFloatingPoint!T)
             }
             else
             {
-                if (ret.exponent > 16382 + 64) // bias + bits of ulong
-                    val /= 2.0L ^^ (ret.exponent - (16382 + 64));
-                else
-                {
-                    auto delta = 16382 + 64 - (ret.exponent == 0 ? 1 : ret.exponent); // -1 in case of subnormals
-                    if (delta > 16383)
-                    {
-                        // need two steps to avoid overflow
-                        val *= 2.0L ^^ 16383;
-                        delta -= 16383;
-                    }
-                    val *= 2.0L ^^ delta;
-                }
+                auto delta = 16382 + 64 // bias + bits of ulong
+                             - (ret.exponent == 0 ? 1 : ret.exponent); // -1 in case of subnormals
+                val = ldexp(val, delta); // val *= 2^^delta
 
                 ulong tmp = cast(ulong) fabs(val);
                 if (ret.exponent != 32767 && ret.exponent > 0 && tmp <= ulong.max / 2)
@@ -1773,30 +1763,28 @@ if (isFloatingPoint!T)
                     tmp = cast(ulong) fabs(val);
                 }
 
-                ret.mantissa = tmp & ((1L << 63) - 1);
+                ret.mantissa = tmp & long.max;
             }
 
-            double d = cast(double) val;
-            ulong ival = () @trusted { return *cast(ulong*) &d; }();
-            if ((ival >> 63) & 1) ret.negative = true;
+            ret.negative = (signbit(val) == 1);
         }
         else
         {
-            ulong[2] ival = () @trusted { return *cast(ulong[2]*) &val; }();
-            ret.mantissa = ival[0] & ((1L << 63) - 1);
-            ret.exponent = ival[1] & 32767;
-            if ((ival[1] >> 15) & 1) ret.negative = true;
+            ushort* vs = cast(ushort*) &val;
+            ret.mantissa = (cast(ulong*) vs)[0] & long.max;
+            ret.exponent = vs[4] & short.max;
+            ret.negative = (vs[4] >> 15) & 1;
         }
     }
     else
     {
         static if (F.realFormat == RealFormat.ieeeSingle)
         {
-            ulong ival = () @trusted { return *cast(uint*) &val; }();
+            ulong ival = *cast(uint*) &val;
         }
         else static if (F.realFormat == RealFormat.ieeeDouble)
         {
-            ulong ival = () @trusted { return *cast(ulong*) &val; }();
+            ulong ival = *cast(ulong*) &val;
         }
         else
         {
@@ -2003,8 +1991,8 @@ if (isFloatingPoint!T)
 
         enum r7 = nextDown(0x1p+16383L);
         enum bp7 = extractBitpattern(r7);
-        static assert(bp2.mantissa == 0xffff_ffff_ffff_ffffL);
-        static assert(bp2.exponent == 16383);
-        static assert(bp2.negative == false);
+        static assert(bp7.mantissa == 0xffff_ffff_ffff_ffffL);
+        static assert(bp7.exponent == 16382);
+        static assert(bp7.negative == false);
     }
 }
diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d
index 78679bb400f..e862e654a0e 100644
--- a/libphobos/src/std/path.d
+++ b/libphobos/src/std/path.d
@@ -558,14 +558,14 @@ if (isRandomAccessRange!R && hasSlicing!R && isSomeChar!(ElementType!R) || isNar
     the POSIX requirements for the 'dirname' shell utility)
     (with suitable adaptations for Windows paths).
 */
-auto dirName(R)(R path)
+auto dirName(R)(return scope R path)
 if (isRandomAccessRange!R && hasSlicing!R && hasLength!R && isSomeChar!(ElementType!R) && !isSomeString!R)
 {
     return _dirName(path);
 }
 
 /// ditto
-auto dirName(C)(C[] path)
+auto dirName(C)(return scope C[] path)
 if (isSomeChar!C)
 {
     return _dirName(path);
@@ -662,7 +662,7 @@ if (isSomeChar!C)
     //static assert(dirName("dir/file".byChar).array == "dir");
 }
 
-private auto _dirName(R)(R path)
+private auto _dirName(R)(return scope R path)
 {
     static auto result(bool dot, typeof(path[0 .. 1]) p)
     {
@@ -1448,7 +1448,7 @@ private auto _withDefaultExtension(R, C)(R path, C[] ext)
     Returns: The assembled path.
 */
 immutable(ElementEncodingType!(ElementType!Range))[]
-    buildPath(Range)(Range segments)
+    buildPath(Range)(scope Range segments)
     if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))
 {
     if (segments.empty) return null;
@@ -2747,7 +2747,7 @@ else version (Posix)
     See_Also:
         $(LREF asAbsolutePath) which does not allocate
 */
-string absolutePath(return scope string path, lazy string base = getcwd())
+string absolutePath(string path, lazy string base = getcwd())
     @safe pure
 {
     import std.array : array;
@@ -2893,7 +2893,7 @@ if (isConvertibleToString!R)
     `Exception` if the specified _base directory is not absolute.
 */
 string relativePath(CaseSensitive cs = CaseSensitive.osDefault)
-    (scope return string path, lazy string base = getcwd())
+    (string path, lazy string base = getcwd())
 {
     if (!isAbsolute(path))
         return path;
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index f3d294ed460..68cc65cfa46 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -276,7 +276,7 @@ static:
     multi-threaded programs. See e.g.
     $(LINK2 https://www.gnu.org/software/libc/manual/html_node/Environment-Access.html#Environment-Access, glibc).
     */
-    inout(char)[] opIndexAssign(inout char[] value, scope const(char)[] name) @trusted
+    inout(char)[] opIndexAssign(return inout char[] value, scope const(char)[] name) @trusted
     {
         version (Posix)
         {
@@ -2138,9 +2138,20 @@ struct Config
     enum Config inheritFDs = Config(Flags.inheritFDs); /// ditto
     enum Config detached = Config(Flags.detached); /// ditto
     enum Config stderrPassThrough = Config(Flags.stderrPassThrough); /// ditto
-    Config opBinary(string op : "|")(Config other)
+    Config opUnary(string op)()
+    if (is(typeof(mixin(op ~ q{flags}))))
     {
-        return Config(flags | other.flags);
+        return Config(mixin(op ~ q{flags}));
+    } /// ditto
+    Config opBinary(string op)(Config other)
+    if (is(typeof(mixin(q{flags} ~ op ~ q{other.flags}))))
+    {
+        return Config(mixin(q{flags} ~ op ~ q{other.flags}));
+    } /// ditto
+    Config opOpAssign(string op)(Config other)
+    if (is(typeof(mixin(q{flags} ~ op ~ q{=other.flags}))))
+    {
+        return Config(mixin(q{flags} ~ op ~ q{=other.flags}));
     } /// ditto
 
     version (StdDdoc)
@@ -2158,6 +2169,16 @@ struct Config
     }
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22125
+@safe unittest
+{
+    Config c = Config.retainStdin;
+    c |= Config.retainStdout;
+    c |= Config.retainStderr;
+    c &= ~Config.retainStderr;
+    assert(c == (Config.retainStdin | Config.retainStdout));
+}
+
 /// A handle that corresponds to a spawned process.
 final class Pid
 {
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index 887fc66c4f6..f91eb0df6bb 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -3362,8 +3362,8 @@ if (isRandomAccessRange!Range)
     // Optionally @nogc std.random.randomCover
     // https://issues.dlang.org/show_bug.cgi?id=14001
     auto rng = Xorshift(123_456_789);
-    int[5] sa = [1, 2, 3, 4, 5];
-    auto r = randomCover(sa[], rng);
+    static immutable int[] sa = [1, 2, 3, 4, 5];
+    auto r = randomCover(sa, rng);
     assert(!r.empty);
     const x = r.front;
     r.popFront();
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 4161b4f89e3..86bd4a1dd19 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -7708,7 +7708,7 @@ if (isForwardRange!RangeOfRanges &&
 @safe unittest
 {
     import std.algorithm.comparison : equal;
-    ulong[1] t0 = [ 123 ];
+    ulong[] t0 = [ 123 ];
 
     assert(!hasAssignableElements!(typeof(t0[].chunks(1))));
     assert(!is(typeof(transposed(t0[].chunks(1)))));
@@ -10850,7 +10850,7 @@ if (isInputRange!Range && !isInstanceOf!(SortedRange, Range))
     into a `SortedRange`, it extracts the original range back out of the `SortedRange`
     using $(REF, move, std,algorithm,mutation).
 */
-    auto release()
+    auto release() return scope
     {
         import std.algorithm.mutation : move;
         return move(_input);
diff --git a/libphobos/src/std/regex/internal/ir.d b/libphobos/src/std/regex/internal/ir.d
index 4d1b6006564..ec0cb66631e 100644
--- a/libphobos/src/std/regex/internal/ir.d
+++ b/libphobos/src/std/regex/internal/ir.d
@@ -629,7 +629,9 @@ struct Regex(Char)
 
 
     @safe @property bool empty() const nothrow {  return ir is null; }
-
+    /++
+    `namedCaptures` returns a range of all named captures in a given regular expression.
+    +/
     @safe @property auto namedCaptures()
     {
         static struct NamedGroupRange
diff --git a/libphobos/src/std/signals.d b/libphobos/src/std/signals.d
index 23639eb7692..e5dc67eb83d 100644
--- a/libphobos/src/std/signals.d
+++ b/libphobos/src/std/signals.d
@@ -37,10 +37,10 @@
  *      $(LINK2 http://www.digitalmars.com/d/archives/16368.html, signals and slots)$(BR)
  *
  * Bugs:
- *      $(RED Slots can only be delegates formed from class objects or
- *      interfaces to class objects. If a delegate to something else
+ *      $(RED Slots can only be delegates referring directly to
+ *      class or interface member functions. If a delegate to something else
  *      is passed to connect(), such as a struct member function,
- *      a nested function, a COM interface or a closure, undefined behavior
+ *      a nested function, a COM interface, a closure, undefined behavior
  *      will result.)
  *
  *      Not safe for multiple threads operating on the same signals
@@ -93,7 +93,8 @@ mixin template Signal(T1...)
      * The delegate must be to an instance of a class or an interface
      * to a class instance.
      * Delegates to struct instances or nested functions must not be
-     * used as slots.
+     * used as slots. This applies even if the nested function does not access
+     * it's parent function variables.
      */
     alias slot_t = void delegate(T1);
 
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index a2597b658ad..6e903fcf6ef 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -2121,6 +2121,9 @@ is recommended if you want to process a complete file.
      * When passed as a compile-time argument, the string will be statically checked
      * against the argument types passed.
      * data = Items to be read.
+     * Returns:
+     *      Same as `formattedRead`: The number of variables filled. If the input range `r` ends early,
+     *      this number will be less than the number of variables provided.
      * Example:
 ----
 // test.d
@@ -3150,7 +3153,7 @@ is empty, throws an `Exception`. In case of an I/O error throws
 
         /// Range primitive implementations.
         void put(A)(scope A writeme)
-            if ((isSomeChar!(Unqual!(ElementType!A)) ||
+            if ((isSomeChar!(ElementType!A) ||
                   is(ElementType!A : const(ubyte))) &&
                 isInputRange!A &&
                 !isInfinite!A)
@@ -4488,6 +4491,9 @@ void writefln(Char, A...)(in Char[] fmt, A args)
  * When passed as a compile-time argument, the string will be statically checked
  * against the argument types passed.
  * args = Items to be read.
+ * Returns:
+ *      Same as `formattedRead`: The number of variables filled. If the input range `r` ends early,
+ *      this number will be less than the number of variables provided.
  * Example:
 ----
 // test.d
diff --git a/libphobos/src/std/string.d b/libphobos/src/std/string.d
index 5abcc4c26ed..420b68abe6a 100644
--- a/libphobos/src/std/string.d
+++ b/libphobos/src/std/string.d
@@ -154,7 +154,7 @@ private:
         string _s;
     }
 
-    bool testAliasedString(alias func, Args...)(scope string s, scope Args args)
+    bool testAliasedString(alias func, Args...)(string s, Args args)
     {
         import std.algorithm.comparison : equal;
         auto a = func(TestAliasedString(s), args);
@@ -240,6 +240,17 @@ if (isSomeChar!Char)
     return cString ? cString[0 .. cstrlen(cString)] : null;
 }
 
+/// ditto
+inout(Char)[] fromStringz(Char)(return scope inout(Char)[] cString) @nogc @safe pure nothrow
+if (isSomeChar!Char)
+{
+    foreach (i; 0 .. cString.length)
+        if (cString[i] == '\0')
+            return cString[0 .. i];
+
+    return cString;
+}
+
 ///
 @system pure unittest
 {
@@ -252,6 +263,44 @@ if (isSomeChar!Char)
     assert(fromStringz("福\0"d.ptr) == "福"d);
 }
 
+///
+@nogc @safe pure nothrow unittest
+{
+    struct C
+    {
+        char[32] name;
+    }
+    assert(C("foo\0"c).name.fromStringz() == "foo"c);
+
+    struct W
+    {
+        wchar[32] name;
+    }
+    assert(W("foo\0"w).name.fromStringz() == "foo"w);
+
+    struct D
+    {
+        dchar[32] name;
+    }
+    assert(D("foo\0"d).name.fromStringz() == "foo"d);
+}
+
+@nogc @safe pure nothrow unittest
+{
+    assert( string.init.fromStringz() == ""c);
+    assert(wstring.init.fromStringz() == ""w);
+    assert(dstring.init.fromStringz() == ""d);
+
+    immutable  char[3] a = "foo"c;
+    assert(a.fromStringz() == "foo"c);
+
+    immutable wchar[3] b = "foo"w;
+    assert(b.fromStringz() == "foo"w);
+
+    immutable dchar[3] c = "foo"d;
+    assert(c.fromStringz() == "foo"d);
+}
+
 @system pure unittest
 {
     char* a = null;
@@ -2632,8 +2681,12 @@ if (isSomeChar!C)
 
     enum S : string { a = "hello\nworld" }
     assert(S.a.splitLines() == ["hello", "world"]);
+}
 
-    char[S.a.length] sa = S.a[];
+@system pure nothrow unittest
+{
+    // dip1000 cannot express an array of scope arrays, so this is not @safe
+    char[11] sa = "hello\nworld";
     assert(sa.splitLines() == ["hello", "world"]);
 }
 
@@ -6654,7 +6707,7 @@ string[string] abbrev(string[] values) @safe pure
  */
 
 size_t column(Range)(Range str, in size_t tabsize = 8)
-if ((isInputRange!Range && isSomeChar!(Unqual!(ElementEncodingType!Range)) ||
+if ((isInputRange!Range && isSomeChar!(ElementEncodingType!Range) ||
     isNarrowString!Range) &&
     !isConvertibleToString!Range)
 {
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index c94896e4c95..278647ecb83 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -993,6 +993,7 @@ version (D_BetterC) {} else
 }
 
 // const SumTypes
+version (D_BetterC) {} else // not @nogc, https://issues.dlang.org/show_bug.cgi?id=22117
 @safe unittest
 {
     auto _ = const(SumType!(int[]))([1, 2, 3]);
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 59be04c85b2..0a04ac5d945 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -6348,7 +6348,7 @@ template isIntegral(T)
 /**
  * Detect whether `T` is a built-in floating point type.
  */
-enum bool isFloatingPoint(T) = __traits(isFloating, T) && !is(T : ireal) && !is(T : creal);
+enum bool isFloatingPoint(T) = __traits(isFloating, T) && is(T : real);
 
 ///
 @safe unittest
@@ -6392,16 +6392,28 @@ enum bool isFloatingPoint(T) = __traits(isFloating, T) && !is(T : ireal) && !is(
             static assert(!isFloatingPoint!(Q!T));
         }
     }
+    static if (is(__vector(float[4])))
+    {
+        static assert(!isFloatingPoint!(__vector(float[4])));
+    }
 }
 
 /**
  * Detect whether `T` is a built-in numeric type (integral or floating
  * point).
  */
-enum bool isNumeric(T) = __traits(isArithmetic, T) && !(is(immutable T == immutable bool) ||
-                                                        is(immutable T == immutable char) ||
-                                                        is(immutable T == immutable wchar) ||
-                                                        is(immutable T == immutable dchar));
+template isNumeric(T)
+{
+    static if (!__traits(isArithmetic, T))
+        enum isNumeric = false;
+    else static if (__traits(isFloating, T))
+        enum isNumeric = is(T : real); // Not __vector, imaginary, or complex.
+    else static if (is(T U == enum))
+        enum isNumeric = isNumeric!U;
+    else
+        enum isNumeric = __traits(isZeroInit, T) // Not char, wchar, or dchar.
+            && !is(immutable T == immutable bool) && !is(T == __vector);
+}
 
 ///
 @safe unittest
@@ -6453,6 +6465,21 @@ enum bool isNumeric(T) = __traits(isArithmetic, T) && !(is(immutable T == immuta
         alias t this;
     }
     static assert(!isNumeric!(S!int));
+
+    enum EChar : char { a = 0, }
+    static assert(!isNumeric!EChar);
+
+    static if (is(__vector(float[4])))
+    {
+        static assert(!isNumeric!(__vector(float[4])));
+    }
+    static if (is(__vector(int[4])))
+    {
+        static assert(!isNumeric!(__vector(int[4])));
+    }
+
+    static assert(!isNumeric!ifloat);
+    static assert(!isNumeric!cfloat);
 }
 
 /**
@@ -6514,10 +6541,16 @@ enum bool isBasicType(T) = isScalarType!T || is(immutable T == immutable void);
 /**
  * Detect whether `T` is a built-in unsigned numeric type.
  */
-enum bool isUnsigned(T) = __traits(isUnsigned, T) && !(is(immutable T == immutable char) ||
-                                                       is(immutable T == immutable wchar) ||
-                                                       is(immutable T == immutable dchar) ||
-                                                       is(immutable T == immutable bool));
+template isUnsigned(T)
+{
+    static if (!__traits(isUnsigned, T))
+        enum isUnsigned = false;
+    else static if (is(T U == enum))
+        enum isUnsigned = isUnsigned!U;
+    else
+        enum isUnsigned = __traits(isZeroInit, T) // Not char, wchar, or dchar.
+            && !is(immutable T == immutable bool) && !is(T == __vector);
+}
 
 ///
 @safe unittest
@@ -6554,12 +6587,21 @@ enum bool isUnsigned(T) = __traits(isUnsigned, T) && !(is(immutable T == immutab
         alias t this;
     }
     static assert(!isUnsigned!(S!uint));
+
+    enum EChar : char { a = 0, }
+    static assert(!isUnsigned!EChar);
+
+    static if (is(__vector(uint[4])))
+    {
+        static assert(!isUnsigned!(__vector(uint[4])));
+    }
 }
 
 /**
  * Detect whether `T` is a built-in signed numeric type.
  */
-enum bool isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, T);
+enum bool isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, T)
+                                                  && is(T : real);
 
 ///
 @safe unittest
@@ -6598,6 +6640,14 @@ enum bool isSigned(T) = __traits(isArithmetic, T) && !__traits(isUnsigned, T);
         alias t this;
     }
     static assert(!isSigned!(S!uint));
+
+    static if (is(__vector(int[4])))
+    {
+        static assert(!isSigned!(__vector(int[4])));
+    }
+
+    static assert(!isSigned!ifloat);
+    static assert(!isSigned!cfloat);
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=17196
@@ -7563,6 +7613,11 @@ template isCallable(alias callable)
     else static if (is(typeof(&callable.opCall) V : V*) && is(V == function))
         // T is a type which has a static member function opCall().
         enum bool isCallable = true;
+    else static if (is(typeof(&callable.opCall!())))
+    {
+        alias TemplateInstanceType = typeof(&callable.opCall!());
+        enum bool isCallable = isCallable!TemplateInstanceType;
+    }
     else static if (is(typeof(&callable!())))
     {
         alias TemplateInstanceType = typeof(&callable!());
@@ -7602,9 +7657,13 @@ template isCallable(alias callable)
 {
     void f()() { }
     T g(T = int)(T x) { return x; }
+    struct S1 { static void opCall()() { } }
+    struct S2 { static T opCall(T = int)(T x) {return x; } }
 
     static assert( isCallable!f);
     static assert( isCallable!g);
+    static assert( isCallable!S1);
+    static assert( isCallable!S2);
 }
 
 /// Overloaded functions and function templates.
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index e54622d8c30..b49b989ef65 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3010,7 +3010,7 @@ struct Nullable(T)
      * Params:
      *     value = A value of type `T` to assign to this `Nullable`.
      */
-    void opAssign()(T value)
+    Nullable opAssign()(T value)
     {
         import std.algorithm.mutation : moveEmplace, move;
 
@@ -3028,6 +3028,7 @@ struct Nullable(T)
             move(copy.payload, _value.payload);
         }
         _isNull = false;
+        return this;
     }
 
     /**
@@ -3038,12 +3039,13 @@ struct Nullable(T)
      * Params:
      *     value = A value of type `Nullable!T` to assign to this `Nullable`.
      */
-    void opAssign()(Nullable!T value)
+    Nullable opAssign()(Nullable!T value)
     {
         if (value._isNull)
             nullify();
         else
             opAssign(value.get());
+        return this;
     }
 
     /**
@@ -3088,13 +3090,13 @@ struct Nullable(T)
     }
 
     /// ditto
-    @property inout(T) get()(inout(T) fallback) inout @safe pure nothrow
+    @property inout(T) get()(inout(T) fallback) inout
     {
         return isNull ? fallback : _value.payload;
     }
 
     /// ditto
-    @property auto get(U)(inout(U) fallback) inout @safe pure nothrow
+    @property auto get(U)(inout(U) fallback) inout
     {
         return isNull ? fallback : _value.payload;
     }
@@ -3605,6 +3607,28 @@ auto nullable(T)(T t)
     assert(test1 == test2);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22101
+@safe unittest
+{
+    static int impure;
+
+    struct S
+    {
+        ~this() { impure++; }
+    }
+
+    Nullable!S s;
+    s.get(S());
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=22100
+@safe unittest
+{
+    Nullable!int a, b, c;
+    a = b = c = 5;
+    a = b = c = nullable(5);
+}
+
 /**
 Just like `Nullable!T`, except that the null state is defined as a
 particular value. For example, $(D Nullable!(uint, uint.max)) is an
@@ -6635,7 +6659,16 @@ assert(refCountedStore.isInitialized)).
         string toString(this This)()
         {
             import std.conv : to;
-            return to!string(refCountedPayload);
+
+            static if (autoInit)
+                return to!string(refCountedPayload);
+            else
+            {
+                if (!_refCounted.isInitialized)
+                    return This.stringof ~ "(RefCountedStore(null))";
+                else
+                    return to!string(_refCounted._store._payload);
+            }
         }
     }
 }
@@ -6773,16 +6806,23 @@ pure @system unittest
     import std.conv : to;
     // Check that string conversion is transparent for refcounted
     // structs that do not have either toString or alias this.
-    struct A { Object a; }
+    static struct A { Object a; }
     auto a  = A(new Object());
     auto r = refCounted(a);
     assert(to!string(r) == to!string(a));
     assert(to!string(cast(const) r) == to!string(cast(const) a));
     // Check that string conversion is still transparent for refcounted
     // structs that have alias this.
-    struct B { int b; alias b this; }
-    struct C { B b; alias b this; }
+    static struct B { int b; alias b this; }
+    static struct C { B b; alias b this; }
     assert(to!string(refCounted(C(B(123)))) == to!string(C(B(123))));
+    // https://issues.dlang.org/show_bug.cgi?id=22093
+    // Check that uninitialized refcounted structs that previously could be
+    // converted to strings still can be.
+    alias R = typeof(r);
+    R r2;
+    cast(void) (((const ref R a) => to!string(a))(r2));
+    cast(void) to!string(RefCounted!(A, RefCountedAutoInitialize.no).init);
 }
 
 /**
@@ -8211,7 +8251,7 @@ if (alignment > 0 && !((alignment - 1) & alignment))
         void test(size_t size)
         {
             import core.stdc.stdlib;
-            alloca(size);
+            cast(void) alloca(size);
             alignmentTest();
         }
         foreach (i; 0 .. 10)
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index 7059e8215e7..41f5a09a9cf 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -41,6 +41,7 @@ $(TR $(TD Index) $(TD
 ))
 $(TR $(TD Validation) $(TD
     $(LREF isValidDchar)
+    $(LREF isValidCodepoint)
     $(LREF validate)
 ))
 $(TR $(TD Miscellaneous) $(TD
@@ -306,6 +307,54 @@ pure nothrow @safe @nogc unittest
     });
 }
 
+/**
+Checks if a single character forms a valid code point.
+
+When standing alone, some characters are invalid code points. For
+example the `wchar` `0xD800` is a so called high surrogate, which can
+only be interpreted together with a low surrogate following it. As a
+standalone character it is considered invalid.
+
+See $(LINK2 http://www.unicode.org/versions/Unicode13.0.0/,
+Unicode Standard, D90, D91 and D92) for more details.
+
+Params:
+    c = character to test
+    Char = character type of `c`
+
+Returns:
+    `true`, if `c` forms a valid code point.
+ */
+bool isValidCodepoint(Char)(Char c)
+if (isSomeChar!Char)
+{
+    alias UChar = Unqual!Char;
+    static if (is(UChar == char))
+    {
+        return c <= 0x7F;
+    }
+    else static if (is(UChar == wchar))
+    {
+        return c <= 0xD7FF || c >= 0xE000;
+    }
+    else static if (is(UChar == dchar))
+    {
+        return isValidDchar(c);
+    }
+    else
+        static assert(false, "unknown character type: `" ~ Char.stringof ~ "`");
+}
+
+///
+@safe pure nothrow unittest
+{
+    assert( isValidCodepoint(cast(char) 0x40));
+    assert(!isValidCodepoint(cast(char) 0x80));
+    assert( isValidCodepoint(cast(wchar) 0x1234));
+    assert(!isValidCodepoint(cast(wchar) 0xD800));
+    assert( isValidCodepoint(cast(dchar) 0x0010FFFF));
+    assert(!isValidCodepoint(cast(dchar) 0x12345678));
+}
 
 /++
     Calculate the length of the UTF sequence starting at `index`
diff --git a/libphobos/src/std/uuid.d b/libphobos/src/std/uuid.d
index 1347bca5c25..dec2a1c276d 100644
--- a/libphobos/src/std/uuid.d
+++ b/libphobos/src/std/uuid.d
@@ -331,7 +331,7 @@ public struct UUID
          *
          * For a less strict parser, see $(LREF parseUUID)
          */
-        this(T)(in T[] uuid) if (isSomeChar!(Unqual!T))
+        this(T)(in T[] uuid) if (isSomeChar!T)
         {
             import std.conv : to, parse;
             if (uuid.length < 36)
diff --git a/libphobos/testsuite/libphobos.exceptions/assert_fail.d b/libphobos/testsuite/libphobos.exceptions/assert_fail.d
index d5b41508bab..79b3cb8139e 100644
--- a/libphobos/testsuite/libphobos.exceptions/assert_fail.d
+++ b/libphobos/testsuite/libphobos.exceptions/assert_fail.d
@@ -444,6 +444,82 @@ void testException()
     test(MayThrow(0), MayThrow(1), `Some message != <toString() failed: "Error", called on MayThrow(1)>`);
 }
 
+void testOverlappingFields()
+{
+    static struct S
+    {
+        union
+        {
+            double num;
+            immutable(char)[] name;
+        }
+    }
+
+    test(S(1.0), S(2.0), "S(<overlapped field>, <overlapped field>) != S(<overlapped field>, <overlapped field>)");
+
+    static struct S2
+    {
+        int valid;
+        union
+        {
+            double num;
+            immutable(char)[] name;
+        }
+    }
+
+    test(S2(4, 1.0), S2(5, 2.0), "S2(4, <overlapped field>, <overlapped field>) != S2(5, <overlapped field>, <overlapped field>)");
+
+    static struct S3
+    {
+        union
+        {
+            double num;
+            immutable(char)[] name;
+        }
+        int valid;
+    }
+    S3 a = {
+        num: 1.0,
+        valid: 8
+    };
+
+    S3 b = {
+        num: 1.0,
+        valid: 8
+    };
+    test(a, b, "S3(<overlapped field>, <overlapped field>, 8) != S3(<overlapped field>, <overlapped field>, 8)");
+}
+
+void testDestruction()
+{
+    static class Test
+    {
+        __gshared string unary, binary;
+        __gshared bool run;
+
+        ~this()
+        {
+            run = true;
+            unary = _d_assert_fail!int("", 1);
+            binary = _d_assert_fail!int("==", 1, 2);
+        }
+    }
+
+    static void createGarbage()
+    {
+        new Test();
+        new long[100];
+    }
+
+    import core.memory : GC;
+    createGarbage();
+    GC.collect();
+
+    assert(Test.run);
+    assert(Test.unary == "Assertion failed (rich formatting is disabled in finalizers)");
+    assert(Test.binary == "Assertion failed (rich formatting is disabled in finalizers)");
+}
+
 int main()
 {
     testIntegers();
@@ -476,6 +552,9 @@ int main()
     testExternClasses();
     testShared();
     testException();
+    testOverlappingFields();
+    if (!__ctfe)
+        testDestruction();
 
     if (!__ctfe)
         fprintf(stderr, "success.\n");
diff --git a/libphobos/testsuite/libphobos.hash/test_hash.d b/libphobos/testsuite/libphobos.hash/test_hash.d
index c6ef3ed668e..d0a8e5fb809 100644
--- a/libphobos/testsuite/libphobos.hash/test_hash.d
+++ b/libphobos/testsuite/libphobos.hash/test_hash.d
@@ -16,6 +16,8 @@ void main()
     issue19582();
     issue20034();
     issue21642();
+    issue22024();
+    issue22076();
     testTypeInfoArrayGetHash1();
     testTypeInfoArrayGetHash2();
     pr2243();
@@ -247,6 +249,71 @@ void issue21642() @safe nothrow pure
     assert(toUbyte(c) == [ubyte(1)]);
 }
 
+/// Accept enum type whose ultimate base type is a SIMD vector.
+void issue22024() @nogc nothrow pure @safe
+{
+    static if (is(__vector(float[2])))
+    {
+        enum E2 : __vector(float[2]) { a = __vector(float[2]).init, }
+        enum F2 : E2 { a = E2.init, }
+        assert(hashOf(E2.init) == hashOf(F2.init));
+        assert(hashOf(E2.init, 1) == hashOf(F2.init, 1));
+    }
+    static if (is(__vector(float[4])))
+    {
+        enum E4 : __vector(float[4]) { a = __vector(float[4]).init, }
+        enum F4 : E4 { a = E4.init, }
+        assert(hashOf(E4.init) == hashOf(F4.init));
+        assert(hashOf(E4.init, 1) == hashOf(F4.init, 1));
+    }
+}
+
+/// hashOf(S) can segfault if S.toHash is forwarded via `alias this` to a
+/// receiver which may be null.
+void issue22076()
+{
+    static struct S0 { Object a; alias a this; }
+
+    static struct S1
+    {
+        S0 a;
+        inout(S0)* b() inout nothrow { return &a; }
+        alias b this;
+    }
+
+    static struct S2
+    {
+        S0 a;
+        S1 b;
+    }
+
+    extern(C++) static class C0
+    {
+        int foo() { return 0; } // Need at least one function in vtable.
+        S0 a; alias a this;
+    }
+
+    extern(C++) static class C1
+    {
+        S1 a;
+        inout(S1)* b() inout nothrow { return &a; }
+        alias b this;
+    }
+
+    cast(void) hashOf(S0.init);
+    cast(void) hashOf(S0.init, 0);
+    cast(void) hashOf(S1.init);
+    cast(void) hashOf(S1.init, 0);
+    cast(void) hashOf(S2.init);
+    cast(void) hashOf(S2.init, 0);
+    auto c0 = new C0();
+    cast(void) hashOf(c0);
+    cast(void) hashOf(c0, 0);
+    auto c1 = new C1();
+    cast(void) hashOf(c1);
+    cast(void) hashOf(c1, 0);
+}
+
 /// Tests ensure TypeInfo_Array.getHash uses element hash functions instead
 /// of hashing array data.
 void testTypeInfoArrayGetHash1()


^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2021-07-30  8:44 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-07-30  8:44 [gcc(refs/users/ibuclaw/heads/gdc)] Import dmd v2.097.1: dmd 50bdf003a, druntime f8df5552, phobos 4ea930b6c Iain Buclaw

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).