diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 467e886530417307a23b93d9f62a8c6ad3e39480..3e9067ea9c2b3fedc4d906721cde83125ae9d320 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -563,6 +563,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.previewIn = value;
       global.params.fix16997 = value;
       global.params.noSharedAccess = FeatureState::enabled;
+      global.params.safer = FeatureState::enabled;
       global.params.rvalueRefParam = FeatureState::enabled;
       global.params.inclusiveInContracts = value;
       global.params.systemVariables = FeatureState::enabled;
@@ -613,6 +614,10 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       global.params.noSharedAccess = FeatureState::enabled;
       break;
 
+    case OPT_fpreview_safer:
+      global.params.safer = FeatureState::enabled;
+      break;
+
     case OPT_fpreview_rvaluerefparam:
       global.params.rvalueRefParam = FeatureState::enabled;
       break;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index f660884c3b9590a9f318b1d3025a5c9b36456315..bfdc9ea21e1e45e373e84f60baddf81994375890 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-2b89c2909de239bd603d6f36379658fe902667db
+82a5d2a7c4dd3d270537bcede2981e047bfd0e6a
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
index 1e96152d04a7ab9aa84a3de2103e9cfe40ccacc3..2e93d26fe853b56658023178aead5f5a4baae64b 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -254,7 +254,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
 | [hdrgen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
 | [json.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d)     | Describe the module in a `.json` file for the `-X` flag                                                 |
 | [dtoh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d)     | C++ header generation from D source files                                                               |
-| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/disasm86.d)       | x86-64 dissassembly generation
+| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/x86/disasm86.d)       | x86-64 disassembly generation
 | [disasmarm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/arm/disasmarm.d) | AArch64 disassembly generation
 
 ### Utility
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index caf58a20634cc1853707bf937f9a7d67a8bb5475..cb3afc6e62ea007530b05a22ca4a05efde1c05b8 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -80,7 +80,7 @@ CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
                 {
                     eSink.error(e.loc, "%s `%s` is not `nothrow`", f.kind(), f.toPrettyChars());
                     if (!f.isDtorDeclaration())
-                        errorSupplementalInferredAttr(f, 10, false, STC.nothrow_);
+                        errorSupplementalInferredAttr(f, 10, false, STC.nothrow_, eSink);
 
                     import dmd.expressionsem : checkOverriddenDtor;
                     f.checkOverriddenDtor(null, e.loc, dd => dd.type.toTypeFunction().isNothrow, "not nothrow");
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 34b120b3412566845bbe91dc98524d764474b930..c15322f6b13f622354300b55e7ba353152bc9f85 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -2335,7 +2335,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         Type tb = t.toBasetype();
         Type typeb = e.type.toBasetype();
 
-        if (e.hexString && !e.committed)
+        if (e.hexString && !e.committed && tb.nextOf().isIntegral)
         {
             const szx = cast(ubyte) tb.nextOf().size();
             if (szx != se.sz && (e.len % szx) == 0)
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 4e04a272141ae64966db80b032c7d0c1f46ae497..f219e3f20279d7d97dd892d0ad56223a24f0d5d6 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -4855,33 +4855,6 @@ public:
 
                 return;
             }
-            else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendTTrace)
-            {
-                // In expressionsem.d `ea ~= eb` was lowered to `_d_arrayappendT{,Trace}({file, line, funcname}, ea, eb);`.
-                // The following code will rewrite it back to `ea ~= eb` and then interpret that expression.
-                Expression lhs, rhs;
-
-                if (fd.ident == Id._d_arrayappendT)
-                {
-                    assert(e.arguments.length == 2);
-                    lhs = (*e.arguments)[0];
-                    rhs = (*e.arguments)[1];
-                }
-                else
-                {
-                    assert(e.arguments.length == 5);
-                    lhs = (*e.arguments)[3];
-                    rhs = (*e.arguments)[4];
-                }
-
-                auto cae = new CatAssignExp(e.loc, lhs, rhs);
-                cae.type = e.type;
-
-                result = interpretRegion(cae, istate, CTFEGoal.LValue);
-                return;
-            }
-            else if (fd.ident == Id._d_arrayappendcTX)
-                assert(0, "CTFE cannot interpret _d_arrayappendcTX!");
         }
         else if (auto soe = ecall.isSymOffExp())
         {
@@ -6132,7 +6105,7 @@ public:
         {
             auto se = e1.isStringExp();
             // Allow casting a hex string literal to short[], int[] or long[]
-            if (se && se.hexString && se.postfix == StringExp.NoPostfix)
+            if (se && se.hexString && se.postfix == StringExp.NoPostfix && e.to.nextOf().isIntegral)
             {
                 const sz = cast(size_t) e.to.nextOf().size;
                 if ((se.len % sz) != 0)
@@ -6151,8 +6124,7 @@ public:
             }
             error(e.loc, "array cast from `%s` to `%s` is not supported at compile time", e1.type.toChars(), e.to.toChars());
             if (se && se.hexString && se.postfix != StringExp.NoPostfix)
-                errorSupplemental(e.loc, "perhaps remove postfix `%s` from hex string",
-                    (cast(char) se.postfix ~ "\0").ptr);
+                errorSupplemental(e.loc, "perhaps remove postfix `%.*s` from hex string", 1, &se.postfix);
 
             result = CTFEExp.cantexp;
             return;
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 05cc8f156e11869336a0413da66b19ccc4aaf40d..aa48d57ba999e810c2d47c54c0012dd5cbd0fac8 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -64,21 +64,11 @@ private extern (D) struct BitFields
     Contract contract;
     bool ctfe;              /// inside a ctfe-only expression
     bool traitsCompiles;    /// inside __traits(compile)
-
     /// ignore symbol visibility
     /// https://issues.dlang.org/show_bug.cgi?id=15907
     bool ignoresymbolvisibility;
-
-    bool _padding0; // To keep the layout the same as when the old `SCOPE` enum bitflags were used
-
     bool inCfile;            /// C semantics apply
-
-    bool _padding1;
-    bool _padding2;
-    bool _padding3;
-
     bool canFree;            /// is on free list
-
     bool fullinst;          /// fully instantiate templates
     bool ctfeBlock;         /// inside a `if (__ctfe)` block
     bool dip1000;           /// dip1000 errors enabled for this scope
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
index 99211e4985484381d9eda6360783726da27a24cc..e22bdba34963d3d87b53a11d381ab0e5c870216d 100644
--- a/gcc/d/dmd/enumsem.d
+++ b/gcc/d/dmd/enumsem.d
@@ -185,7 +185,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
 
     if (ed.members.length == 0)
     {
-        .error(ed.loc, "%s `%s enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
+        .error(ed.loc, "%s `%s` enum `%s` must have at least one member", ed.kind, ed.toPrettyChars, ed.toChars());
         ed.errors = true;
         ed.semanticRun = PASS.semanticdone;
         return;
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index 79efc6e51aa45b77bfc84ea84f366aa0536095a0..1babb18bcc6b8477409b376decb0ae3c2cac4de4 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -37,60 +37,39 @@ class ErrorSinkCompiler : ErrorSink
   extern (C++):
   override:
 
-    void error(const ref Loc loc, const(char)* format, ...)
+    void verror(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReport(loc, format, ap, ErrorKind.error);
-        va_end(ap);
     }
 
-    void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+    void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReportSupplemental(loc, format, ap, ErrorKind.error);
-        va_end(ap);
     }
 
-    void warning(const ref Loc loc, const(char)* format, ...)
+    void vwarning(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReport(loc, format, ap, ErrorKind.warning);
-        va_end(ap);
     }
 
-    void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+    void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReportSupplemental(loc, format, ap, ErrorKind.warning);
-        va_end(ap);
     }
 
-    void deprecation(const ref Loc loc, const(char)* format, ...)
+    void vdeprecation(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReport(loc, format, ap, ErrorKind.deprecation);
-        va_end(ap);
     }
 
-    void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+    void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReportSupplemental(loc, format, ap, ErrorKind.deprecation);
-        va_end(ap);
     }
 
-    void message(const ref Loc loc, const(char)* format, ...)
+    void vmessage(const ref Loc loc, const(char)* format, va_list ap)
     {
-        va_list ap;
-        va_start(ap, format);
         verrorReport(loc, format, ap, ErrorKind.message);
-        va_end(ap);
     }
 }
 
diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d
index afea689546b110b801fb3137430f3e019485f2c7..98841123ef1312636c5891831da7937a99c90b42 100644
--- a/gcc/d/dmd/errorsink.d
+++ b/gcc/d/dmd/errorsink.d
@@ -11,6 +11,8 @@
 
 module dmd.errorsink;
 
+import core.stdc.stdarg;
+
 import dmd.location;
 
 /***************************************
@@ -21,19 +23,78 @@ abstract class ErrorSink
   nothrow:
   extern (C++):
 
-    void error(const ref Loc loc, const(char)* format, ...);
+    void verror(const ref Loc loc, const(char)* format, va_list ap);
+    void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+    void vwarning(const ref Loc loc, const(char)* format, va_list ap);
+    void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap);
+    void vmessage(const ref Loc loc, const(char)* format, va_list ap);
+    void vdeprecation(const ref Loc loc, const(char)* format, va_list ap);
+    void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
 
-    void errorSupplemental(const ref Loc loc, const(char)* format, ...);
+    void error(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        verror(loc, format, ap);
+        va_end(ap);
+    }
 
-    void warning(const ref Loc loc, const(char)* format, ...);
+    void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        verrorSupplemental(loc, format, ap);
+        va_end(ap);
+    }
 
-    void warningSupplemental(const ref Loc loc, const(char)* format, ...);
+    void warning(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        vwarning(loc, format, ap);
+        va_end(ap);
+    }
+
+    void warningSupplemental(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        vwarningSupplemental(loc, format, ap);
+        va_end(ap);
+    }
+
+    void message(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        vmessage(loc, format, ap);
+        va_end(ap);
+    }
 
-    void message(const ref Loc loc, const(char)* format, ...);
+    void deprecation(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        vdeprecation(loc, format, ap);
+        va_end(ap);
+    }
 
-    void deprecation(const ref Loc loc, const(char)* format, ...);
+    void deprecationSupplemental(const ref Loc loc, const(char)* format, ...)
+    {
+        va_list ap;
+        va_start(ap, format);
+        vdeprecationSupplemental(loc, format, ap);
+        va_end(ap);
+    }
 
-    void deprecationSupplemental(const ref Loc loc, const(char)* format, ...);
+    /**
+     * This will be called to indicate compilation has either
+     * finished or terminated, no more errors are possible - it's
+     * now the time to print any stored errors.
+     *
+     * The default implementation does nothing since most error sinks have no state
+     */
+    void plugSink() {}
 }
 
 /*****************************************
@@ -45,19 +106,19 @@ class ErrorSinkNull : ErrorSink
   extern (C++):
   override:
 
-    void error(const ref Loc loc, const(char)* format, ...) { }
+    void verror(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void warning(const ref Loc loc, const(char)* format, ...) { }
+    void vwarning(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void warningSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void message(const ref Loc loc, const(char)* format, ...) { }
+    void vmessage(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void deprecation(const ref Loc loc, const(char)* format, ...) { }
+    void vdeprecation(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 }
 
 /*****************************************
@@ -71,7 +132,7 @@ class ErrorSinkLatch : ErrorSinkNull
 
     bool sawErrors;
 
-    void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
+    void verror(const ref Loc loc, const(char)* format, va_list ap) { sawErrors = true; }
 }
 
 /*****************************************
@@ -87,7 +148,7 @@ class ErrorSinkStderr : ErrorSink
   extern (C++):
   override:
 
-    void error(const ref Loc loc, const(char)* format, ...)
+    void verror(const ref Loc loc, const(char)* format, va_list ap)
     {
         fputs("Error: ", stderr);
         const p = loc.toChars();
@@ -97,16 +158,13 @@ class ErrorSinkStderr : ErrorSink
             //mem.xfree(cast(void*)p); // loc should provide the free()
         }
 
-        va_list ap;
-        va_start(ap, format);
         vfprintf(stderr, format, ap);
         fputc('\n', stderr);
-        va_end(ap);
     }
 
-    void errorSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void verrorSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void warning(const ref Loc loc, const(char)* format, ...)
+    void vwarning(const ref Loc loc, const(char)* format, va_list ap)
     {
         fputs("Warning: ", stderr);
         const p = loc.toChars();
@@ -116,16 +174,13 @@ class ErrorSinkStderr : ErrorSink
             //mem.xfree(cast(void*)p); // loc should provide the free()
         }
 
-        va_list ap;
-        va_start(ap, format);
         vfprintf(stderr, format, ap);
         fputc('\n', stderr);
-        va_end(ap);
     }
 
-    void warningSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void vwarningSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 
-    void deprecation(const ref Loc loc, const(char)* format, ...)
+    void vdeprecation(const ref Loc loc, const(char)* format, va_list ap)
     {
         fputs("Deprecation: ", stderr);
         const p = loc.toChars();
@@ -135,14 +190,11 @@ class ErrorSinkStderr : ErrorSink
             //mem.xfree(cast(void*)p); // loc should provide the free()
         }
 
-        va_list ap;
-        va_start(ap, format);
         vfprintf(stderr, format, ap);
         fputc('\n', stderr);
-        va_end(ap);
     }
 
-    void message(const ref Loc loc, const(char)* format, ...)
+    void vmessage(const ref Loc loc, const(char)* format, va_list ap)
     {
         const p = loc.toChars();
         if (*p)
@@ -151,12 +203,9 @@ class ErrorSinkStderr : ErrorSink
             //mem.xfree(cast(void*)p); // loc should provide the free()
         }
 
-        va_list ap;
-        va_start(ap, format);
         vfprintf(stderr, format, ap);
         fputc('\n', stderr);
-        va_end(ap);
     }
 
-    void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
+    void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap) { }
 }
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index e1b2ef791a7f113ed6df88788e443387a6c8c504..3e18051afc12f0103919b0d309a4b84ab9b993c8 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -180,7 +180,7 @@ bool checkMutableArguments(ref Scope sc, FuncDeclaration fd, TypeFunction tf,
         if (!(eb.isMutable || eb2.isMutable))
             return;
 
-        if (!tf.isLive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
+        if (!tf.isLive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && setFunctionToUnsafe(sc.func)))
             return;
 
         if (!gag)
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 3c79b02caa026586eda134010582f14224aed1ba..dc72b3a8df1b7c0d3edd203f55f8ea8429ac068e 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -4143,10 +4143,9 @@ extern (C++) final class IndexExp : BinExp
 
     override bool isLvalue()
     {
-        if (e1.op == EXP.assocArrayLiteral)
-            return false;
-        if (e1.type.ty == Tsarray ||
-            (e1.op == EXP.index && e1.type.ty != Tarray))
+        auto t1b = e1.type.toBasetype();
+        if (t1b.isTypeAArray() || t1b.isTypeSArray() ||
+            (e1.isIndexExp() && t1b != t1b.isTypeDArray()))
         {
             return e1.isLvalue();
         }
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index b26ce2380f9a2995bdeb92867dcdedc8ecefcf75..e1baa4887e7928792a1baac4ae1ff6050a0abc9e 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -1935,7 +1935,7 @@ private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
             f.toPrettyChars());
 
         if (!f.isDtorDeclaration())
-            errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_);
+            errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.pure_, global.errorSink);
 
         f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().purity != PURE.impure, "impure");
         return true;
@@ -2018,15 +2018,18 @@ void checkOverriddenDtor(FuncDeclaration f, Scope* sc, const ref Loc loc,
     }
 }
 
-/// Print the reason why `fd` was inferred `@system` as a supplemental error
-/// Params:
-///   fd = function to check
-///   maxDepth = up to how many functions deep to report errors
-///   deprecation = print deprecations instead of errors
-///   stc = storage class of attribute to check
-public void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
+/********************************************
+ * Print the reason why `fd` was inferred `@system` as a supplemental error
+ * Params:
+ *   fd = function to check
+ *   maxDepth = up to how many functions deep to report errors
+ *   deprecation = print deprecations instead of errors
+ *   stc = storage class of attribute to check
+ *   eSink = where the error messages go
+ */
+public void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc, ErrorSink eSink)
 {
-    auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
+    auto errorFunc = deprecation ? &eSink.deprecationSupplemental : &eSink.errorSupplemental;
 
     AttributeViolation* s;
     const(char)* attr;
@@ -2054,7 +2057,7 @@ public void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool
     if (!s)
         return;
 
-    if (s.fmtStr)
+    if (s.format)
     {
         errorFunc(s.loc, deprecation ?
             "which wouldn't be `%s` because of:" :
@@ -2062,25 +2065,24 @@ public void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool
         if (stc == STC.nogc || stc == STC.pure_)
         {
             auto f = (cast(Dsymbol) s.arg0).isFuncDeclaration();
-            errorFunc(s.loc, s.fmtStr, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
+            errorFunc(s.loc, s.format, f.kind(), f.toPrettyChars(), s.arg1 ? s.arg1.toChars() : "");
         }
         else
         {
-            errorFunc(s.loc, s.fmtStr,
+            errorFunc(s.loc, s.format,
                 s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
         }
     }
-    else if (auto sa = s.arg0.isDsymbol())
+    else if (s.fd)
     {
-        if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+        if (maxDepth > 0)
         {
-            if (maxDepth > 0)
-            {
-                errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
-                errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
-            }
+            errorFunc(s.loc, "which calls `%s`", s.fd.toPrettyChars());
+            errorSupplementalInferredAttr(s.fd, maxDepth - 1, deprecation, stc, eSink);
         }
     }
+    else
+        assert(0);
 }
 
 /*******************************************
@@ -2262,7 +2264,7 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
                 sc.func.kind(), sc.func.toPrettyChars(), f.kind(),
                 prettyChars);
             if (!f.isDtorDeclaration)
-                errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe);
+                errorSupplementalInferredAttr(f, /*max depth*/ 10, /*deprecation*/ false, STC.safe, global.errorSink);
             .errorSupplemental(f.loc, "`%s` is declared here", prettyChars);
 
             f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().trust > TRUST.system, "@system");
@@ -2276,12 +2278,12 @@ private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
         if (sc.func.isSafeBypassingInference())
         {
             .deprecation(loc, "`@safe` function `%s` calling `%s`", sc.func.toChars(), f.toChars());
-            errorSupplementalInferredAttr(f, 10, true, STC.safe);
+            errorSupplementalInferredAttr(f, 10, true, STC.safe, global.errorSink);
         }
         else if (!sc.func.safetyViolation)
         {
             import dmd.func : AttributeViolation;
-            sc.func.safetyViolation = new AttributeViolation(loc, null, f, null, null);
+            sc.func.safetyViolation = new AttributeViolation(loc, f);
         }
     }
     return false;
@@ -2329,7 +2331,7 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
             sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
 
         if (!f.isDtorDeclaration)
-            f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
+            f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc, global.errorSink);
     }
 
     f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isNogc, "non-@nogc");
@@ -2850,12 +2852,12 @@ private Expression rewriteOpAssign(BinExp exp)
  * Params:
  *     sc           =  scope
  *     argumentList =  arguments to function
- *     reportErrors =  whether or not to report errors here. Some callers are not
+ *     eSink        =  if not null, used to report errors. Some callers are not
  *                      checking actual function params, so they'll do their own error reporting
  * Returns:
  *     `true` when a semantic error occurred
  */
-private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const bool reportErrors = true)
+private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, ErrorSink eSink)
 {
     Expressions* exps = argumentList.arguments;
     if (!exps)
@@ -2876,9 +2878,9 @@ private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const b
 
             if (arg.op == EXP.type)
             {
-                if (reportErrors)
+                if (eSink)
                 {
-                    error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
+                    eSink.error(arg.loc, "cannot pass type `%s` as a function argument", arg.toChars());
                     arg = ErrorExp.get();
                 }
                 err = true;
@@ -2886,9 +2888,9 @@ private bool preFunctionParameters(Scope* sc, ArgumentList argumentList, const b
         }
         else if (arg.type.toBasetype().ty == Tfunction)
         {
-            if (reportErrors)
+            if (eSink)
             {
-                error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
+                eSink.error(arg.loc, "cannot pass function `%s` as a function argument", arg.toChars());
                 arg = ErrorExp.get();
             }
             err = true;
@@ -2961,14 +2963,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
 
     if (argumentList.names)
     {
-        const(char)* msg = null;
-        auto resolvedArgs = tf.resolveNamedArgs(argumentList, &msg);
+        OutBuffer buf;
+        auto resolvedArgs = tf.resolveNamedArgs(argumentList, &buf);
         if (!resolvedArgs)
         {
             // while errors are usually already caught by `tf.callMatch`,
             // this can happen when calling `typeof(freefunc)`
-            if (msg)
-                error(loc, "%s", msg);
+            if (buf.length)
+                error(loc, "%s", buf.peekChars());
             return true;
         }
         // note: the argument list should be mutated with named arguments / default arguments,
@@ -4974,7 +4976,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             return setError();
         }
-        if (preFunctionParameters(sc, exp.argumentList))
+        if (preFunctionParameters(sc, exp.argumentList, global.errorSink))
         {
             return setError();
         }
@@ -5194,21 +5196,14 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 auto tiargs = new Objects();
                 tiargs.push(exp.newtype);
-                id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
-                id = new CallExp(exp.loc, id).expressionSemantic(sc);
 
-                Expression idVal;
-                Expression tmp = extractSideEffect(sc, "__tmpThrowable", idVal, id, true);
-                // auto castTmp = new CastExp(exp.loc, tmp, exp.type);
+                id = new DotTemplateInstanceExp(exp.loc, id, Id._d_newThrowable, tiargs);
 
-                auto ctor = new DotIdExp(exp.loc, tmp, Id.ctor).expressionSemantic(sc);
-                auto ctorCall = new CallExp(exp.loc, ctor, exp.arguments);
+                id = new CallExp(exp.loc, id).expressionSemantic(sc);
 
-                id = Expression.combine(idVal, exp.argprefix).expressionSemantic(sc);
-                id = Expression.combine(id, ctorCall).expressionSemantic(sc);
-                // id = Expression.combine(id, castTmp).expressionSemantic(sc);
+                exp.lowering = id.expressionSemantic(sc);
 
-                result = id.expressionSemantic(sc);
+                result = exp;
                 return;
             }
             else if (sc.needsCodegen() && // interpreter doesn't need this lowered
@@ -5648,7 +5643,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (exp.fd.ident != Id.empty)
             return;
 
-        const(char)[] s;
+        string s;
         if (exp.fd.fes)
             s = "__foreachbody";
         else if (exp.fd.tok == TOK.reserved)
@@ -5682,7 +5677,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             symtab = sds.symtab;
         }
         assert(symtab);
-        Identifier id = Identifier.generateId(s, symtab.length() + 1);
+        Identifier id = Identifier.generateIdWithLoc(s, exp.loc);
         exp.fd.ident = id;
         if (exp.td)
             exp.td.ident = id;
@@ -5925,7 +5920,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (FuncExp fe = exp.e1.isFuncExp())
         {
             if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
-                preFunctionParameters(sc, exp.argumentList))
+                preFunctionParameters(sc, exp.argumentList, global.errorSink))
                 return setError();
 
             // Run e1 semantic even if arguments have any errors
@@ -6165,7 +6160,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
         if (arrayExpressionSemantic(exp.arguments.peekSlice(), sc) ||
-            preFunctionParameters(sc, exp.argumentList))
+            preFunctionParameters(sc, exp.argumentList, global.errorSink))
             return setError();
 
         // Check for call operator overload
@@ -9334,7 +9329,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
             {
                 if (msg.length)
-                    errorSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
+                    errorSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
                 return setError();
             }
         }
@@ -9344,7 +9339,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to);
             // if message was printed
             if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated())
-                deprecationSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
+                deprecationSupplemental(exp.loc, "%.*s", msg.fTuple.expand);
             if (err)
                 return setError();
         }
@@ -13083,9 +13078,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         return;
     }
 
-    override void visit(ShlExp exp)
+    private void visitShift(BinExp exp)
     {
-        //printf("ShlExp::semantic(), type = %p\n", type);
         if (exp.type)
         {
             result = exp;
@@ -13112,87 +13106,32 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             result = exp.incompatibleTypes();
             return;
         }
+
         exp.e1 = integralPromotions(exp.e1, sc);
         if (exp.e2.type.toBasetype().ty != Tvector)
-            exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
+        {
+            Type tb1 = exp.e1.type.toBasetype();
+            exp.e2 = exp.e2.castTo(sc, tb1.ty == Tvector ? tb1 : Type.tshiftcnt);
+        }
 
         exp.type = exp.e1.type;
         result = exp;
     }
 
+    override void visit(ShlExp exp)
+    {
+        visitShift(exp);
+    }
     override void visit(ShrExp exp)
     {
-        if (exp.type)
-        {
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = binSemanticProp(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-        Expression e = exp.op_overload(sc);
-        if (e)
-        {
-            result = e;
-            return;
-        }
-
-        if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
-            return setError();
-
-        if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
-        {
-            result = exp.incompatibleTypes();
-            return;
-        }
-        exp.e1 = integralPromotions(exp.e1, sc);
-        if (exp.e2.type.toBasetype().ty != Tvector)
-            exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
-
-        exp.type = exp.e1.type;
-        result = exp;
+        visitShift(exp);
     }
-
     override void visit(UshrExp exp)
     {
-        if (exp.type)
-        {
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = binSemanticProp(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-        Expression e = exp.op_overload(sc);
-        if (e)
-        {
-            result = e;
-            return;
-        }
-
-        if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
-            return setError();
-
-        if (!target.isVectorOpSupported(exp.e1.type.toBasetype(), exp.op, exp.e2.type.toBasetype()))
-        {
-            result = exp.incompatibleTypes();
-            return;
-        }
-        exp.e1 = integralPromotions(exp.e1, sc);
-        if (exp.e2.type.toBasetype().ty != Tvector)
-            exp.e2 = exp.e2.castTo(sc, Type.tshiftcnt);
-
-        exp.type = exp.e1.type;
-        result = exp;
+        visitShift(exp);
     }
 
-    override void visit(AndExp exp)
+    private void visitBinaryBitOp(BinExp exp)
     {
         if (exp.type)
         {
@@ -13247,114 +13186,17 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         result = exp;
     }
 
+    override void visit(AndExp exp)
+    {
+        visitBinaryBitOp(exp);
+    }
     override void visit(OrExp exp)
     {
-        if (exp.type)
-        {
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = binSemanticProp(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-        Expression e = exp.op_overload(sc);
-        if (e)
-        {
-            result = e;
-            return;
-        }
-
-        if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
-        {
-            exp.type = exp.e1.type;
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = typeCombine(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-
-        Type tb = exp.type.toBasetype();
-        if (tb.ty == Tarray || tb.ty == Tsarray)
-        {
-            if (!isArrayOpValid(exp))
-            {
-                result = arrayOpInvalidError(exp);
-                return;
-            }
-            result = exp;
-            return;
-        }
-        if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
-        {
-            result = exp.incompatibleTypes();
-            return;
-        }
-        if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
-            return setError();
-
-        result = exp;
+        visitBinaryBitOp(exp);
     }
-
     override void visit(XorExp exp)
     {
-        if (exp.type)
-        {
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = binSemanticProp(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-        Expression e = exp.op_overload(sc);
-        if (e)
-        {
-            result = e;
-            return;
-        }
-
-        if (exp.e1.type.toBasetype().ty == Tbool && exp.e2.type.toBasetype().ty == Tbool)
-        {
-            exp.type = exp.e1.type;
-            result = exp;
-            return;
-        }
-
-        if (Expression ex = typeCombine(exp, sc))
-        {
-            result = ex;
-            return;
-        }
-
-        Type tb = exp.type.toBasetype();
-        if (tb.ty == Tarray || tb.ty == Tsarray)
-        {
-            if (!isArrayOpValid(exp))
-            {
-                result = arrayOpInvalidError(exp);
-                return;
-            }
-            result = exp;
-            return;
-        }
-        if (!target.isVectorOpSupported(tb, exp.op, exp.e2.type.toBasetype()))
-        {
-            result = exp.incompatibleTypes();
-            return;
-        }
-        if (exp.checkIntegralBin() || exp.checkSharedAccessBin(sc))
-            return setError();
-
-        result = exp;
+        visitBinaryBitOp(exp);
     }
 
     override void visit(LogicalExp exp)
@@ -15217,6 +15059,27 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
     {
         return false;
     }
+    else if (sc._module.ident == Id.atomic && sc._module.parent !is null)
+    {
+        // Allow core.internal.atomic, it is an compiler implementation for a given platform module.
+        // It is then exposed by other modules such as core.atomic and core.stdc.atomic.
+        // This is available as long as druntime is on the import path and the platform supports that operation.
+
+        // https://issues.dlang.org/show_bug.cgi?id=24846
+
+        Package parent = sc._module.parent.isPackage();
+        if (parent !is null)
+        {
+            // This can be easily converted over to apply to core.atomic and core.internal.atomic
+            if (parent.ident == Id.internal)
+            {
+                parent = parent.parent.isPackage();
+
+                if (parent !is null && parent.ident == Id.core && parent.parent is null)
+                   return false;
+            }
+        }
+    }
 
     //printf("checkSharedAccess() `%s` returnRef: %d\n", e.toChars(), returnRef);
 
@@ -17184,8 +17047,11 @@ void semanticTypeInfo(Scope* sc, Type t)
             Scope scx;
             scx.eSink = global.errorSink;
             scx._module = sd.getModule();
-            getTypeInfoType(sd.loc, t, &scx);
-            sd.requestTypeInfo = true;
+            if (global.params.useTypeInfo)
+            {
+                getTypeInfoType(sd.loc, t, &scx);
+                sd.requestTypeInfo = true;
+            }
         }
         else if (!sc.minst)
         {
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index e9b9367fd32ef0971cdc4acf20bed75799167b78..153befdb9a98b4cdf281e3ae0adcd74af7e0bdae 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -685,14 +685,15 @@ extern (C++) class FuncDeclaration : Declaration
      *
      * Params:
      *     loc = location of action
-     *     fmt = format string for error message
+     *     format = format string for error message
      *     arg0 = (optional) argument to format string
      */
-    extern (D) final void setThrow(Loc loc, const(char)* fmt, RootObject arg0 = null)
+    extern (D) final void setThrow(Loc loc, const(char)* format, RootObject arg0 = null)
     {
         if (nothrowInprocess && !nothrowViolation)
         {
-            nothrowViolation = new AttributeViolation(loc, fmt, arg0); // action that requires GC
+            assert(format);
+            nothrowViolation = new AttributeViolation(loc, format, arg0); // action that requires GC
         }
     }
 
@@ -700,11 +701,14 @@ extern (C++) class FuncDeclaration : Declaration
      * The function calls non-`nothrow` function f, register that in case nothrow is being inferred
      * Params:
      *     loc = location of call
-     *     f = function being called
+     *     fd = function being called
      */
-    extern (D) final void setThrowCall(Loc loc, FuncDeclaration f)
+    extern (D) final void setThrowCall(Loc loc, FuncDeclaration fd)
     {
-        return setThrow(loc, null, f);
+        if (nothrowInprocess && !nothrowViolation)
+        {
+            nothrowViolation = new AttributeViolation(loc, fd); // action that requires GC
+        }
     }
 
     /****************************************
@@ -1871,14 +1875,26 @@ extern (C++) final class NewDeclaration : FuncDeclaration
 ///   The `FunctionDeclaration` is then stored in `arg0` and `fmtStr` must be `null`.
 struct AttributeViolation
 {
-    /// location of error
-    Loc loc = Loc.init;
-    /// printf-style format string
-    const(char)* fmtStr = null;
-    /// Arguments for up to two `%s` format specifiers in format string
-    RootObject arg0 = null;
-    /// ditto
-    RootObject arg1 = null;
-    /// ditto
-    RootObject arg2 = null;
+    Loc loc;               /// location of error
+
+    FuncDeclaration fd;    /// function is the focus of the violation
+
+    // -- OR --
+
+    const(char)* format;   /// printf-style format string
+    RootObject arg0;       /// Arguments for up to two `%s` format specifiers in format string
+    RootObject arg1;       /// ditto
+    RootObject arg2;       /// ditto
+
+    this(ref Loc loc, FuncDeclaration fd) { this.loc = loc; this.fd = fd; }
+
+    this(ref Loc loc, const(char)* format, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+    {
+        assert(format);
+        this.loc = loc;
+        this.format = format;
+        this.arg0 = arg0;
+        this.arg1 = arg1;
+        this.arg2 = arg2;
+    }
 }
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index c142a16f065da237782a1b29e1a3f16cbf521e4b..bfa0faca60f315580f881c2d3fc8b8d1e70d032c 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -3001,7 +3001,15 @@ extern (D) bool setImpure(FuncDeclaration fd, Loc loc = Loc.init, const(char)* f
         if (fmt)
             fd.pureViolation = new AttributeViolation(loc, fmt, fd, arg0); // impure action
         else if (arg0)
-            fd.pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
+        {
+            if (auto sa = arg0.isDsymbol())
+            {
+                if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+                {
+                    fd.pureViolation = new AttributeViolation(loc, fd2); // call to impure function
+                }
+            }
+        }
 
         if (fd.fes)
             fd.fes.func.setImpure(loc, fmt, arg0);
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index ccb63e330e9e5879b67bd65585e1c173461c9895..88b27d20bb54ef6c00e7229883a39f87a9d63d8b 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -188,6 +188,8 @@ extern (C++) struct Param
                                  // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
                                  // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
                                  // Implementation: https://github.com/dlang/dmd/pull/9817
+    FeatureState safer;          // safer by default (more @safe checks in unattributed code)
+                                 // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
     FeatureState noSharedAccess; // read/write access to shared memory objects
     bool previewIn;              // `in` means `[ref] scope const`, accepts rvalues
     bool inclusiveInContracts;   // 'in' contracts of overridden methods must be a superset of parent contract
@@ -467,6 +469,17 @@ extern (C++) struct Global
         return major * 1000 + minor;
     }
 
+    /**
+     * Indicate to stateful error sinks that no more errors can be produced.
+     * This is to support error sinks that collect information to produce a
+     * single (say) report.
+     */
+    extern(C++) void plugErrorSinks()
+    {
+        global.errorSink.plugSink();
+        global.errorSinkNull.plugSink();
+    }
+
     /**
     Returns: the version as the number that would be returned for __VERSION__
     */
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 5348d614ebb3a64429042b805fd668bdef9e6136..c5659ea10b6268f03cd62f2c65d161a813e5fe08 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -191,6 +191,9 @@ struct Param
                                  // https://gist.github.com/andralex/e5405a5d773f07f73196c05f8339435a
                                  // https://digitalmars.com/d/archives/digitalmars/D/Binding_rvalues_to_ref_parameters_redux_325087.html
                                  // Implementation: https://github.com/dlang/dmd/pull/9817
+    FeatureState safer;          // safer by default (more @safe checks in unattributed code)
+				 // https://github.com/WalterBright/documents/blob/38f0a846726b571f8108f6e63e5e217b91421c86/safer.md
+
     FeatureState noSharedAccess; // read/write access to shared memory objects
     d_bool previewIn;              // `in` means `[ref] scope const`, accepts rvalues
     d_bool inclusiveInContracts;   // 'in' contracts of overridden methods must be a superset of parent contract
@@ -350,6 +353,13 @@ struct Global
 
     void _init();
 
+    /**
+     * Indicate to stateful error sinks that no more errors can be produced.
+     * This is to support error sinks that collect information to produce a
+     * single (say) report.
+     */
+    void plugErrorSinks();
+
     /**
     Returns: the version as the number that would be returned for __VERSION__
     */
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index f676361d958bba49dda83dfa6df59cefa7219a52..aae07bc15370371555ba0f888081a5ced1338f7d 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -389,6 +389,7 @@ immutable Msgtable[] msgtable =
     // Builtin functions
     { "std" },
     { "core" },
+    { "internal" },
     { "config" },
     { "c_complex_float" },
     { "c_complex_double" },
@@ -481,9 +482,12 @@ immutable Msgtable[] msgtable =
     { "isRef" },
     { "isOut" },
     { "isLazy" },
+    { "isCOMClass" },
     { "hasMember" },
     { "identifier" },
     { "fullyQualifiedName" },
+    { "getBitfieldOffset" },
+    { "getBitfieldWidth" },
     { "getProtection" },
     { "getVisibility" },
     { "parent" },
diff --git a/gcc/d/dmd/intrange.d b/gcc/d/dmd/intrange.d
index 51f28013f22bd2c9a8b83b366cbaffd81e8dbc8e..d89fbb2ffc1121946ea7e787952ed34b8fd61fde 100644
--- a/gcc/d/dmd/intrange.d
+++ b/gcc/d/dmd/intrange.d
@@ -13,10 +13,9 @@ module dmd.intrange;
 
 import core.stdc.stdio;
 
-import dmd.astenums;
-import dmd.mtype;
-import dmd.expression;
-import dmd.globals;
+import dmd.astenums : Tdchar;
+import dmd.mtype : Type;
+import dmd.globals : uinteger_t;
 
 private uinteger_t copySign(uinteger_t x, bool sign) @safe
 {
@@ -322,7 +321,7 @@ struct IntRange
 
     static IntRange fromType(Type type, bool isUnsigned)
     {
-        if (!type.isIntegral() || type.toBasetype().ty == Tvector)
+        if (!type.isIntegral() || type.toBasetype().isTypeVector())
             return widest();
 
         uinteger_t mask = type.sizemask();
@@ -444,7 +443,7 @@ struct IntRange
 
     IntRange _cast(Type type)
     {
-        if (!type.isIntegral() || type.toBasetype().ty == Tvector)
+        if (!type.isIntegral() || type.toBasetype().isTypeVector())
             return this;
         else if (!type.isUnsigned())
             return castSigned(type.sizemask());
@@ -456,7 +455,7 @@ struct IntRange
 
     IntRange castUnsigned(Type type)
     {
-        if (!type.isIntegral() || type.toBasetype().ty == Tvector)
+        if (!type.isIntegral() || type.toBasetype().isTypeVector())
             return castUnsigned(ulong.max);
         else if (type.toBasetype().ty == Tdchar)
             return castDchar();
@@ -504,7 +503,7 @@ struct IntRange
         union_ = true;
     }
 
-    ref const(IntRange) dump(const(char)* funcName, Expression e) const return
+    ref const(IntRange) dump(Exp)(const(char)* funcName, Exp e) const return
     {
         printf("[(%c)%#018llx, (%c)%#018llx] @ %s ::: %s\n",
                imin.negative?'-':'+', cast(ulong)imin.value,
@@ -668,7 +667,7 @@ struct IntRange
             return widest();
 
         // Don't treat the whole range as divide by 0 if only one end of a range is 0.
-        // Issue 15289
+        // https://issues.dlang.org/show_bug.cgi?id=15289
         if (rhs.imax.value == 0)
         {
             rhs.imax.value--;
@@ -682,6 +681,11 @@ struct IntRange
         {
             return IntRange(imin / rhs.imax, imax / rhs.imin);
         }
+        else if (rhs.imin.negative && !rhs.imax.negative) // divisor spans [-1, 0, 1]
+        {
+            SignExtendedNumber[4] bdy = [-imin, imin, -imax, imax];
+            return IntRange.fromNumbers4(bdy.ptr);
+        }
         else
         {
             // [a,b] / [c,d] = [min (a/c, a/d, b/c, b/d), max (a/c, a/d, b/c, b/d)]
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 476a700bdeb7da13b58663130c87aff85ce1c751..d9f4b1c678f655a040869ad0dc76549dca2f7474 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -1555,6 +1555,8 @@ class Lexer
                     if (ndigits != 2 && !utf_isValidDchar(v))
                     {
                         error(loc, "invalid UTF character \\U%08x", v);
+                        if (v >= 0xD800 && v <= 0xDFFF)
+                            errorSupplemental("The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?");
                         v = '?'; // recover with valid UTF character
                     }
                 }
@@ -3168,6 +3170,11 @@ class Lexer
         eSink.error(loc, format, args);
     }
 
+    void errorSupplemental(T...)(const(char)* format, T args)
+    {
+        eSink.errorSupplemental(token.loc, format, args);
+    }
+
     void deprecation(T...)(const ref Loc loc, const(char)* format, T args)
     {
         eSink.deprecation(loc, format, args);
@@ -3434,13 +3441,14 @@ class Lexer
             if (*q != ct)
                 break;
         }
-        /* Remove leading spaces until start of the comment
+        /* Remove leading line feed or space
          */
         int linestart = 0;
         if (ct == '/')
         {
-            while (q < qend && (*q == ' ' || *q == '\t'))
+            if (q < qend && *q == ' ') {
                 ++q;
+            }
         }
         else if (q < qend)
         {
@@ -3671,25 +3679,35 @@ unittest
         import core.stdc.stdarg;
 
         string expected;
+        string expectedSupplemental;
         bool gotError;
 
-        void error(const ref Loc loc, const(char)* format, ...)
+        void verror(const ref Loc loc, const(char)* format, va_list ap)
         {
             gotError = true;
             char[100] buffer = void;
+            auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)];
+            assert(expected == actual);
+        }
+
+        void errorSupplemental(const ref Loc loc, const(char)* format, ...)
+        {
+            gotError = true;
+            char[128] buffer = void;
             va_list ap;
             va_start(ap, format);
             auto actual = buffer[0 .. vsnprintf(buffer.ptr, buffer.length, format, ap)];
             va_end(ap);
-            assert(expected == actual);
+            assert(expectedSupplemental == actual);
         }
     }
 
     ErrorSinkTest errorSink = new ErrorSinkTest;
 
-    void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
+    void test2(string sequence, string[2] expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
     {
-        errorSink.expected = expectedError;
+        errorSink.expected = expectedError[0];
+        errorSink.expectedSupplemental = expectedError[1];
         errorSink.gotError = false;
         auto p = cast(const(char)*)sequence.ptr;
         Lexer lexer = new Lexer(errorSink);
@@ -3702,6 +3720,11 @@ unittest
         assert(expectedScanLength == actualScanLength);
     }
 
+    void test(string sequence, string expectedError, dchar expectedReturnValue, uint expectedScanLength, bool Ccompile = false)
+    {
+        test2(sequence, [expectedError, null], expectedReturnValue, expectedScanLength, Ccompile);
+    }
+
     test("c", `undefined escape sequence \c`, 'c', 1);
     test("!", `undefined escape sequence \!`, '!', 1);
     test("&quot;", `undefined escape sequence \&`, '&', 1, true);
@@ -3720,8 +3743,6 @@ unittest
     test("U0001f6" , `escape hex sequence has 6 hex digits instead of 8`,  0x0001f6, 7);
     test("U0001f60", `escape hex sequence has 7 hex digits instead of 8`, 0x0001f60, 8);
 
-    test("ud800"    , `invalid UTF character \U0000d800`, '?', 5);
-    test("udfff"    , `invalid UTF character \U0000dfff`, '?', 5);
     test("U00110000", `invalid UTF character \U00110000`, '?', 9);
 
     test("xg0"      , `undefined escape hex sequence \xg`, 'g', 2);
@@ -3733,6 +3754,9 @@ unittest
     test("&quot", `unterminated named entity &quot;`, '?', 5);
 
     test("400", `escape octal sequence \400 is larger than \377`, 0x100, 3);
+
+    test2("uD800", [`invalid UTF character \U0000d800`, `The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?`], '?', 5);
+    test2("uDFFF", [`invalid UTF character \U0000dfff`, `The code unit is a UTF-16 surrogate, is the escape UTF-16 not a Unicode code point?`], '?', 5);
 }
 
 unittest
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index be70b02dec90c4489f711e704396671330c5ec04..6d57467314ce04606a76d1fc20f543b51ab9c8c1 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -2602,13 +2602,20 @@ extern (C++) final class TypeFunction : TypeNext
         return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
     }
 
-    extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
+    /*********************************
+     * Append error message to buf.
+     * Input:
+     *  buf = message sink
+     *  format = printf format
+     */
+    extern(C) static void getMatchError(ref OutBuffer buf, const(char)* format, ...)
     {
         if (global.gag && !global.params.v.showGaggedErrors)
-            return null;
-        OutBuffer buf;
-        buf.printf(format, args);
-        return buf.extractChars();
+            return;
+        va_list ap;
+        va_start(ap, format);
+        buf.vprintf(format, ap);
+        va_end(ap);
     }
 
     /********************************
@@ -2617,10 +2624,10 @@ extern (C++) final class TypeFunction : TypeNext
      *
      * Params:
      *      argumentList = array of function arguments
-     *      pMessage = address to store error message, or `null`
+     *      buf = if not null, append error message to it
      * Returns: re-ordered argument list, or `null` on error
      */
-    extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, const(char)** pMessage)
+    extern(D) Expressions* resolveNamedArgs(ArgumentList argumentList, OutBuffer* buf)
     {
         Expression[] args = argumentList.arguments ? (*argumentList.arguments)[] : null;
         Identifier[] names = argumentList.names ? (*argumentList.names)[] : null;
@@ -2644,8 +2651,8 @@ extern (C++) final class TypeFunction : TypeNext
                 const pi = findParameterIndex(name);
                 if (pi == -1)
                 {
-                    if (pMessage)
-                        *pMessage = getMatchError("no parameter named `%s`", name.toChars());
+                    if (buf)
+                        getMatchError(*buf, "no parameter named `%s`", name.toChars());
                     return null;
                 }
                 ci = pi;
@@ -2655,8 +2662,8 @@ extern (C++) final class TypeFunction : TypeNext
                 if (!isVariadic)
                 {
                     // Without named args, let the caller diagnose argument overflow
-                    if (hasNamedArgs && pMessage)
-                        *pMessage = getMatchError("argument `%s` goes past end of parameter list", arg.toChars());
+                    if (hasNamedArgs && buf)
+                        getMatchError(*buf, "argument `%s` goes past end of parameter list", arg.toChars());
                     return null;
                 }
                 while (ci >= newArgs.length)
@@ -2665,8 +2672,8 @@ extern (C++) final class TypeFunction : TypeNext
 
             if ((*newArgs)[ci])
             {
-                if (pMessage)
-                    *pMessage = getMatchError("parameter `%s` assigned twice", parameterList[ci].toChars());
+                if (buf)
+                    getMatchError(*buf, "parameter `%s` assigned twice", parameterList[ci].toChars());
                 return null;
             }
             (*newArgs)[ci++] = arg;
@@ -2684,8 +2691,8 @@ extern (C++) final class TypeFunction : TypeNext
             if (this.incomplete)
                 continue;
 
-            if (pMessage)
-                *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
+            if (buf)
+                getMatchError(*buf, "missing argument for parameter #%d: `%s`",
                     i + 1, parameterToChars(parameterList[i], this, false));
             return null;
         }
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index cedc4a43c8f15867cb864979a02261c1849d62ff..4a060c9330656952d50c9e904673ce157cb0ecd9 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -302,7 +302,15 @@ extern (D) bool setGC(FuncDeclaration fd, Loc loc, const(char)* fmt, RootObject
         if (fmt)
             fd.nogcViolation = new AttributeViolation(loc, fmt, fd, arg0); // action that requires GC
         else if (arg0)
-            fd.nogcViolation = new AttributeViolation(loc, fmt, arg0); // call to non-@nogc function
+        {
+            if (auto sa = arg0.isDsymbol())
+            {
+                if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+                {
+                    fd.nogcViolation = new AttributeViolation(loc, fd2); // call to non-@nogc function
+                }
+            }
+        }
 
         fd.type.toTypeFunction().isNogc = false;
         if (fd.fes)
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index e8324eb0710654db7f9984e2581f4094bf96fa39..3e145be5499ff8de3bbab926d485190cede09535 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -6812,7 +6812,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
             {
                 case TOK.identifier:
                 {
-
                     if (commaExpected)
                         error("comma expected separating field initializers");
                     const t = peek(&token);
@@ -6846,6 +6845,20 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 default:
                     if (commaExpected)
                         error("comma expected separating field initializers");
+                    const t = peek(&token);
+                    if (t.value == TOK.colon)
+                    {
+                        error("incorrect syntax for associative array, expected `[]`, found `{}`");
+                        while (token.value != TOK.rightCurly && token.value != TOK.endOfFile)
+                        {
+                            nextToken();
+                        }
+                        if (token.value == TOK.rightCurly)
+                        {
+                            nextToken();
+                        }
+                        break;
+                    }
                     auto value = parseInitializer();
                     _is.addInit(null, value);
                     commaExpected = true;
@@ -8647,7 +8660,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
             error("expression expected, not `%s`", token.toChars());
         Lerr:
             // Anything for e, as long as it's not NULL
-            e = new AST.IntegerExp(loc, 0, AST.Type.tint32);
+            e = AST.ErrorExp.get();
             nextToken();
             break;
         }
diff --git a/gcc/d/dmd/root/array.d b/gcc/d/dmd/root/array.d
index 81355774de3d0c36a35f38d072cdee8a5d86abc9..6e7db065e7ec81566dc42b596eef045c9c389ec9 100644
--- a/gcc/d/dmd/root/array.d
+++ b/gcc/d/dmd/root/array.d
@@ -52,7 +52,7 @@ public:
     ~this() pure nothrow
     {
         debug (stomp) memset(data.ptr, 0xFF, data.length);
-        if (data.ptr != &smallarray[0])
+        if (data.ptr && data.ptr != &smallarray[0])
             mem.xfree(data.ptr);
     }
     ///returns elements comma separated in []
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 24d87458551655a2595f0b68f2a3117e49aa19c7..86dff7b5bcf7db13e6691b1366a0b620455885cc 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -21,12 +21,13 @@ import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dscope;
+import dmd.dsymbol;
 import dmd.dsymbolsem : determineSize;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
 import dmd.funcsem : isRootTraitsCompilesScope;
-import dmd.globals : FeatureState;
+import dmd.globals : FeatureState, global;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
@@ -316,10 +317,20 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
     return false;
 }
 
+/**************************************
+ * Safer D adds safety checks to functions with the default
+ * trust setting.
+ */
+bool isSaferD(FuncDeclaration fd)
+{
+    return fd.type.toTypeFunction().trust == TRUST.default_ &&
+           global.params.safer == FeatureState.enabled;
+}
+
 bool isSafe(FuncDeclaration fd)
 {
     if (fd.safetyInprocess)
-        fd.setUnsafe();
+        setFunctionToUnsafe(fd);
     return fd.type.toTypeFunction().trust == TRUST.safe;
 }
 
@@ -331,48 +342,73 @@ extern (D) bool isSafeBypassingInference(FuncDeclaration fd)
 bool isTrusted(FuncDeclaration fd)
 {
     if (fd.safetyInprocess)
-        fd.setUnsafe();
+        setFunctionToUnsafe(fd);
     return fd.type.toTypeFunction().trust == TRUST.trusted;
 }
 
-/**************************************
- * The function is doing something unsafe, so mark it as unsafe.
- *
+/*****************************************************
+ * Report safety violation for function `fd`, or squirrel away
+ * error message in fd.safetyViolation if needed later.
+ * Call when `fd` was just inferred to be @system OR
+ * `fd` was @safe and an tried something unsafe.
  * Params:
- *   fd  = func declaration to set unsafe
- *   gag = surpress error message (used in escape.d)
- *   loc = location of error
- *   fmt = printf-style format string
+ *   fd    = function we're gonna rat on
+ *   gag   = suppress error message (used in escape.d)
+ *   loc   = location of error
+ *   format = printf-style format string
  *   arg0  = (optional) argument for first %s format specifier
  *   arg1  = (optional) argument for second %s format specifier
  *   arg2  = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
  */
-extern (D) bool setUnsafe(
-    FuncDeclaration fd,
-    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
-    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+extern (D) void reportSafeError(FuncDeclaration fd, bool gag, Loc loc,
+    const(char)* format = null, RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+{
+    if (fd.type.toTypeFunction().trust == TRUST.system) // function was just inferred to be @system
+    {
+        if (format)
+            fd.safetyViolation = new AttributeViolation(loc, format, arg0, arg1, arg2);
+        else if (arg0)
+        {
+            if (FuncDeclaration fd2 = (cast(Dsymbol) arg0).isFuncDeclaration())
+            {
+                fd.safetyViolation = new AttributeViolation(loc, fd2); // call to non-@nogc function
+            }
+        }
+    }
+    else if (fd.isSafe() || fd.isSaferD())
+    {
+        if (!gag && format)
+            .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+    }
+}
+
+
+/**********************************************
+ * Function is doing something unsafe. If inference
+ * is in process, commit the function to be @system.
+ * Params:
+ *      fd = the naughty function
+ * Returns:
+ *      true if this is a safe function and so an error OR is inferred to be @system,
+ *      false otherwise.
+ */
+extern (D) bool setFunctionToUnsafe(FuncDeclaration fd)
 {
     if (fd.safetyInprocess)
     {
         fd.safetyInprocess = false;
         fd.type.toTypeFunction().trust = TRUST.system;
-        if (fmt || arg0)
-            fd.safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
 
         if (fd.fes)
-            fd.fes.func.setUnsafe();
-    }
-    else if (fd.isSafe())
-    {
-        if (!gag && fmt)
-            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-
+            setFunctionToUnsafe(fd.fes.func);
         return true;
     }
+    else if (fd.isSafe() || fd.isSaferD())
+        return true;
     return false;
 }
 
+
 /**************************************
  * The function is calling `@system` function `f`, so mark it as unsafe.
  *
@@ -383,7 +419,12 @@ extern (D) bool setUnsafe(
  */
 extern (D) bool setUnsafeCall(FuncDeclaration fd, FuncDeclaration f)
 {
-    return fd.setUnsafe(false, f.loc, null, f, null);
+    if (setFunctionToUnsafe(fd))
+    {
+        reportSafeError(fd, false, f.loc, null, f, null);
+        return fd.isSafe();
+    }
+    return false;
 }
 
 /**************************************
@@ -394,14 +435,14 @@ extern (D) bool setUnsafeCall(FuncDeclaration fd, FuncDeclaration f)
  *   sc = scope that the unsafe statement / expression is in
  *   gag = surpress error message (used in escape.d)
  *   loc = location of error
- *   fmt = printf-style format string
+ *   format = printf-style format string
  *   arg0  = (optional) argument for first %s format specifier
  *   arg1  = (optional) argument for second %s format specifier
  *   arg2  = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
+ * Returns: whether there is a safe error
  */
 bool setUnsafe(Scope* sc,
-    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
+    bool gag = false, Loc loc = Loc.init, const(char)* format = null,
     RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
 {
     if (sc.intypeof)
@@ -416,7 +457,7 @@ bool setUnsafe(Scope* sc,
         {
             if (sc.varDecl.storage_class & STC.safe)
             {
-                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+                .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
                 return true;
             }
             else if (!(sc.varDecl.storage_class & STC.trusted))
@@ -435,13 +476,21 @@ bool setUnsafe(Scope* sc,
         {
             // Message wil be gagged, but still call error() to update global.errors and for
             // -verrors=spec
-            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+            .error(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
             return true;
         }
         return false;
     }
 
-    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
+    if (setFunctionToUnsafe(sc.func))
+    {
+        if (format || arg0)
+        {
+            reportSafeError(sc.func, gag, loc, format, arg0, arg1, arg2);
+        }
+        return sc.func.isSafe(); // it is only an error if in an @safe function
+    }
+    return false;
 }
 
 /***************************************
@@ -459,23 +508,24 @@ bool setUnsafe(Scope* sc,
  *   fs = feature state from the preview flag
  *   gag = surpress error message
  *   loc = location of error
- *   msg = printf-style format string
+ *   format = printf-style format string
  *   arg0  = (optional) argument for first %s format specifier
  *   arg1  = (optional) argument for second %s format specifier
  *   arg2  = (optional) argument for third %s format specifier
  * Returns: whether an actual safe error (not deprecation) occured
  */
-bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* msg,
+bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)* format,
     RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
 {
-    //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
+    //printf("setUnsafePreview() fs:%d %s\n", fs, fmt);
+    assert(format);
     with (FeatureState) final switch (fs)
     {
       case disabled:
         return false;
 
       case enabled:
-        return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
+        return sc.setUnsafe(gag, loc, format, arg0, arg1, arg2);
 
       case default_:
         if (!sc.func)
@@ -484,13 +534,13 @@ bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
         {
             if (!gag && !sc.isDeprecated())
             {
-                deprecation(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+                deprecation(loc, format, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
             }
         }
         else if (!sc.func.safetyViolation)
         {
             import dmd.func : AttributeViolation;
-            sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
+            sc.func.safetyViolation = new AttributeViolation(loc, format, arg0, arg1, arg2);
         }
         return false;
     }
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index c584b846489060fa8287f9dfa167acb47043b982..8138bd2eb952711efe458d98d6ae7b93f0547b6a 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -57,7 +57,7 @@ import dmd.opover;
 import dmd.parse;
 import dmd.common.outbuffer;
 import dmd.root.string;
-import dmd.safe : isSafe, setUnsafe;
+import dmd.safe : isSafe, isSaferD, setUnsafe;
 import dmd.semantic2;
 import dmd.sideeffect;
 import dmd.statement;
@@ -779,14 +779,9 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
 
         Dsymbol sapplyOld = sapply; // 'sapply' will be NULL if and after 'inferApplyArgTypes' errors
 
-        /* Check for inference errors
-         */
+        /* Check for inference errors and apply mutability checks inline */
         if (!inferApplyArgTypes(fs, sc, sapply))
         {
-            /**
-             Try and extract the parameter count of the opApply callback function, e.g.:
-             int opApply(int delegate(int, float)) => 2 args
-             */
             bool foundMismatch = false;
             size_t foreachParamCount = 0;
             if (sapplyOld)
@@ -806,6 +801,19 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
                             auto tf = fparam.type.nextOf().isTypeFunction();
                             foreachParamCount = tf.parameterList.length;
                             foundMismatch = true;
+
+                            // Mutability check
+                            if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
+                            {
+                                // First error: The call site
+                                error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
+                                    fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());
+
+                                // Second error: Suggest how to fix
+                                errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+
+                                return setError();
+                            }
                         }
                     }
                 }
@@ -824,6 +832,24 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
             return setError();
         }
 
+        // If inference succeeds, proceed with post-checks
+        if (sapply && sapply.isFuncDeclaration())
+        {
+            FuncDeclaration fd = sapply.isFuncDeclaration();
+
+            if (fs.aggr && fs.aggr.type && fd.type && fs.aggr.type.isConst() && !fd.type.isConst())
+            {
+                // First error: The call site
+                error(fs.loc, "mutable method `%s.%s` is not callable using a `const` object",
+                    fd.parent ? fd.parent.toPrettyChars() : "unknown", fd.toChars());
+
+                // Second error: Suggest how to fix
+                errorSupplemental(fd.loc, "Consider adding `const` or `inout` here");
+
+                return setError();
+            }
+        }
+
         Type tab = fs.aggr.type.toBasetype();
 
         if (tab.ty == Ttuple) // don't generate new scope for tuple loops
@@ -1961,7 +1987,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
         }
 
         ss.hasDefault = sc.sw.sdefault ||
-            !(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe);
+            !(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe || sc.func.isSaferD);
         if (!ss.hasDefault)
         {
             if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !sc.inCfile)
diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d
index bd3674a8cc8260b39c46ce0e7b54bc04ca3da070..0e9c4338a05203214b4b37beaa042e99ce7f8605 100644
--- a/gcc/d/dmd/templatesem.d
+++ b/gcc/d/dmd/templatesem.d
@@ -1252,7 +1252,13 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
                 //printf("farg = %s %s\n", farg.type.toChars(), farg.toChars());
 
                 RootObject oarg = farg;
-                if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
+
+                if (farg.isFuncExp())
+                {
+                    // When assigning an untyped (void) lambda `x => y` to a `(F)(ref F)` parameter,
+                    // we don't want to deduce type void creating a void parameter
+                }
+                else if ((fparam.storageClass & STC.ref_) && (!(fparam.storageClass & STC.auto_) || farg.isLvalue()))
                 {
                     /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
                      */
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 7b32209fd2ef7fecdb69de99968823113dd64119..f7f4cd2bb5e235a9ac258bdbf579ed8a774cb611 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -701,6 +701,26 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
 
         return isDeclX(d => (d.storage_class & STC.lazy_) != 0);
     }
+    if (e.ident == Id.isCOMClass)
+    {
+        if (dim != 1)
+            return dimError(1);
+
+        auto o = (*e.args)[0];
+        auto s = getDsymbol(o);
+        AggregateDeclaration agg;
+
+        if (!s || ((agg = s.isAggregateDeclaration()) is null))
+        {
+            error(e.loc, "argument to `__traits(isCOMClass, %s)` is not a declaration", o.toChars());
+            return ErrorExp.get();
+        }
+
+        if (ClassDeclaration cd = agg.isClassDeclaration())
+            return cd.com ? True() : False();
+        else
+            return False();
+    }
     if (e.ident == Id.identifier)
     {
         // Get identifier for symbol as a string literal
@@ -776,6 +796,43 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
         return se.expressionSemantic(sc);
 
     }
+    if (e.ident == Id.getBitfieldOffset || e.ident == Id.getBitfieldWidth)
+    {
+        if (dim != 1)
+            return dimError(1);
+
+        auto o = (*e.args)[0];
+        auto s = getDsymbolWithoutExpCtx(o);
+        if (!s)
+        {
+            error(e.loc, "bitfield symbol expected not `%s`", o.toChars());
+            return ErrorExp.get();
+        }
+
+        auto vd = s.toAlias.isVarDeclaration();
+        if (!vd || !(vd.storage_class & STC.field))
+        {
+            error(e.loc, "bitfield symbol expected not %s `%s`", s.kind, s.toPrettyChars);
+            return ErrorExp.get();
+        }
+
+        uint fieldWidth;
+        uint bitOffset;
+        if (auto bf = vd.isBitFieldDeclaration())
+        {
+            fieldWidth = bf.fieldWidth;
+            bitOffset  = bf.bitOffset;
+        }
+        else // just a regular field
+        {
+            const sz = size(vd.type);
+            assert(sz < uint.max / 8);    // overflow check
+            fieldWidth = cast(uint)sz * 8;
+            bitOffset  = 0;
+        }
+        uint value = e.ident == Id.getBitfieldOffset ? bitOffset : fieldWidth;
+        return new IntegerExp(e.loc, value, Type.tuns32);
+    }
     if (e.ident == Id.getProtection || e.ident == Id.getVisibility)
     {
         if (dim != 1)
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index eebbf45573dc32c15ae3712d645569a0c5d6a4e0..aea969a2e08df4746c8d93b578111cdd695182c7 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -753,13 +753,14 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
     }
     const(char)* failMessage;
     const(char)** pMessage = errorHelper ? &failMessage : null;
-    auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
+    OutBuffer buf;
+    auto resolvedArgs = tf.resolveNamedArgs(argumentList, errorHelper ? &buf : null);
     Expression[] args;
     if (!resolvedArgs)
     {
-        if (failMessage)
+        if (buf.length)
         {
-            errorHelper(failMessage);
+            errorHelper(buf.peekChars());
             return MATCH.nomatch;
         }
 
@@ -820,6 +821,11 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
             if (!arg)
                 continue; // default argument
             m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
+            if (failMessage)
+            {
+                buf.reset();
+                buf.writestring(failMessage);
+            }
         }
         else if (p.defaultArg)
             continue;
@@ -846,15 +852,17 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
                     errorHelper(failMessage);
                 return MATCH.nomatch;
             }
-            if (pMessage && u >= args.length)
-                *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
-                    u + 1, parameterToChars(p, tf, false));
-            // If an error happened previously, `pMessage` was already filled
-            else if (pMessage && !*pMessage)
-                *pMessage = tf.getParamError(args[u], p);
-
             if (errorHelper)
-                errorHelper(*pMessage);
+            {
+                if (u >= args.length)
+                    TypeFunction.getMatchError(buf, "missing argument for parameter #%d: `%s`",
+                        u + 1, parameterToChars(p, tf, false));
+                // If an error happened previously, `pMessage` was already filled
+                else if (buf.length == 0)
+                    buf.writestring(tf.getParamError(args[u], p));
+
+                errorHelper(buf.peekChars());
+            }
             return MATCH.nomatch;
         }
         if (m < match)
@@ -864,7 +872,9 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
     if (errorHelper && !parameterList.varargs && args.length > nparams)
     {
         // all parameters had a match, but there are surplus args
-        errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
+        OutBuffer buf2;
+        TypeFunction.getMatchError(buf2, "expected %d argument(s), not %d", nparams, args.length);
+        errorHelper(buf2.extractChars());
         return MATCH.nomatch;
     }
     //printf("match = %d\n", match);
@@ -1174,8 +1184,12 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
         if (sz != trailingArgs.length)
         {
             if (pMessage)
-                *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
+            {
+                OutBuffer buf;
+                TypeFunction.getMatchError(buf, "expected %llu variadic argument(s), not %zu",
                     sz, trailingArgs.length);
+                *pMessage = buf.extractChars();
+            }
             return MATCH.nomatch;
         }
         goto case Tarray;
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index ff09c0927158f8fc0675a10b5eaa34b2901d5fe5..304d6bd203c5898cb6ac9b6121d415be331796d8 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -2246,15 +2246,10 @@ public:
 	    new_call = build_nop (type, build_address (var));
 	    setup_exp = modify_expr (var, aggregate_initializer_decl (cd));
 	  }
-	else if (global.params.ehnogc && e->thrownew)
-	  {
-	    /* Allocating a `@nogc' Exception with `_d_newThrowable' has already
-	       been handled by the front-end.  */
-	    gcc_unreachable ();
-	  }
 	else
 	  {
-	    /* Generate: _d_newclass()  */
+	    /* Generate: _d_newclass()
+		     or: _d_newThrowable()  */
 	    new_call = build_expr (e->lowering);
 	  }
 
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index b101a3a73c7f012a192249729f801a4363023da5..f769a71aee81deff9bebdfc03824adcca68d2131 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -400,6 +400,10 @@ fpreview=nosharedaccess
 D RejectNegative
 Disable access to shared memory objects.
 
+fpreview=safer
+D RejectNegative
+Enable safety checks on all functions by default.
+
 fpreview=rvaluerefparam
 D RejectNegative
 Enable rvalue arguments to ref parameters.
diff --git a/gcc/testsuite/gdc.test/compilable/atomic_store_2_shared_classes.d b/gcc/testsuite/gdc.test/compilable/atomic_loadstore_shared_classes.d
similarity index 60%
rename from gcc/testsuite/gdc.test/compilable/atomic_store_2_shared_classes.d
rename to gcc/testsuite/gdc.test/compilable/atomic_loadstore_shared_classes.d
index 0d8cd7489376c9c5520758472d0c1dc997e8a790..f719aa829f0207e401e99596d61eacbefe6100c4 100644
--- a/gcc/testsuite/gdc.test/compilable/atomic_store_2_shared_classes.d
+++ b/gcc/testsuite/gdc.test/compilable/atomic_loadstore_shared_classes.d
@@ -5,9 +5,14 @@ class Foo
 {
 }
 
+shared Foo toLoad;
+
 void oops()
 {
     auto f0 = new shared Foo;
     auto f1 = new shared Foo;
     atomicStore(f0, f1);
+
+    // https://issues.dlang.org/show_bug.cgi?id=24846
+    shared(Foo) f2 = atomicLoad(toLoad);
 }
diff --git a/gcc/testsuite/gdc.test/compilable/betterCinline.d b/gcc/testsuite/gdc.test/compilable/betterCinline.d
new file mode 100644
index 0000000000000000000000000000000000000000..31cc8498b0da59bfae2313c570096f6a43362a95
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/betterCinline.d
@@ -0,0 +1,22 @@
+/* REQUIRED_ARGS: -betterC -inline
+   PERMUTE_ARGS:
+*/
+
+struct InvBoneBindInfo
+{
+}
+
+
+struct Test(Value)
+{
+    void test()
+    {
+        auto t = Value.init;
+    }
+}
+
+extern(C) void main()
+{
+    Test!(InvBoneBindInfo[32]) test;
+    test.test();
+}
diff --git a/gcc/testsuite/gdc.test/compilable/compile1.d b/gcc/testsuite/gdc.test/compilable/compile1.d
index 676108f68cfa51b6e2fc2318f16875211ab098b4..15973cf11f92cebfa6febaf7b23474a46b37d6d6 100644
--- a/gcc/testsuite/gdc.test/compilable/compile1.d
+++ b/gcc/testsuite/gdc.test/compilable/compile1.d
@@ -861,7 +861,7 @@ S14166 s14166;
 
 struct X14166 { this(int) { } X14166 opAssign(int) { return this; } }
 X14166[int] aa14166;
-X14166[int] makeAA14166() { return aa14166; }
+ref X14166[int] makeAA14166() { return aa14166; }
 
 struct Tup14166(T...) { T field; alias field this; }
 Tup14166!(int, int) tup14166;
diff --git a/gcc/testsuite/gdc.test/compilable/ddoc24871.d b/gcc/testsuite/gdc.test/compilable/ddoc24871.d
new file mode 100644
index 0000000000000000000000000000000000000000..8e1c227e0326f11dfd2dcde8d1a9d905872925d1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/ddoc24871.d
@@ -0,0 +1,18 @@
+// PERMUTE_ARGS:
+// REQUIRED_ARGS: -D -Dd${RESULTS_DIR}/compilable -o-
+// POST_SCRIPT: compilable/extra-files/ddocAny-postscript.sh
+import std.stdio;
+
+/// Example
+/// ---
+/// void main() {
+/// 	foreach (i; 0..10) {
+/// 		writeln("Hello, world!");
+/// 	}
+/// }
+/// ---
+void main() {
+
+    writeln("Hello, World!");
+
+}
diff --git a/gcc/testsuite/gdc.test/compilable/rvalueref.d b/gcc/testsuite/gdc.test/compilable/rvalueref.d
index 1c96c36f1f5b3334f0b9a363d9f506e88e7eea3e..fbef10f059fae0c5985fa2f4a91da040418d70bd 100644
--- a/gcc/testsuite/gdc.test/compilable/rvalueref.d
+++ b/gcc/testsuite/gdc.test/compilable/rvalueref.d
@@ -11,3 +11,9 @@ struct AS
 
 void popFront(ref string) { }
 static assert(!is(typeof((R r) => r.popFront)));
+
+// https://issues.dlang.org/show_bug.cgi?id=24883
+int toString(Writer)(ref Writer sink) => 3;
+int toString(void delegate(scope const(char)[]) sink) => 4;
+void put() {}
+static assert(toString(dst => put()) == 4);
diff --git a/gcc/testsuite/gdc.test/compilable/testVRP.d b/gcc/testsuite/gdc.test/compilable/testVRP.d
index bdd72d0962b8e52644e65dc0b5a66b62d0982862..33d366d17271d026b89e5824d0a8ab519168ed36 100644
--- a/gcc/testsuite/gdc.test/compilable/testVRP.d
+++ b/gcc/testsuite/gdc.test/compilable/testVRP.d
@@ -4,6 +4,7 @@
 // https://issues.dlang.org/show_bug.cgi?id=3147
 // https://issues.dlang.org/show_bug.cgi?id=6000
 // https://issues.dlang.org/show_bug.cgi?id=5225
+// https://issues.dlang.org/show_bug.cgi?id=24855
 
 void add()
 {
@@ -100,6 +101,10 @@ void divideFail()
     short w;
     byte y;
     static assert(!__traits(compiles, y = w / -1));
+    static assert(!__traits(compiles, y = y / w));
+
+    short z;
+    static assert(!__traits(compiles, z = w / z + 1));
 }
 
 void plus1Fail()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b19523.d b/gcc/testsuite/gdc.test/fail_compilation/b19523.d
index d2a05c73dc1adfb15f48565596bbcfd2d0937169..3b2a5e0f2243194e712d65046df30df07b649421 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b19523.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b19523.d
@@ -3,7 +3,7 @@ TEST_OUTPUT:
 ----
 fail_compilation/b19523.d(13): Error: undefined identifier `SomeStruct`
 fail_compilation/b19523.d(14): Error: function `foo` is not callable using argument types `(_error_)`
-fail_compilation/b19523.d(14):        cannot pass argument `__lambda2` of type `_error_` to parameter `int delegate() arg`
+fail_compilation/b19523.d(14):        cannot pass argument `__lambda_L14_C6` of type `_error_` to parameter `int delegate() arg`
 fail_compilation/b19523.d(19):        `b19523.foo(int delegate() arg)` declared here
 ----
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/binexperr.d b/gcc/testsuite/gdc.test/fail_compilation/binexperr.d
new file mode 100644
index 0000000000000000000000000000000000000000..695b2746b186674efd45d479209923411e788625
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/binexperr.d
@@ -0,0 +1,14 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/binexperr.d(12): Error: expression expected, not `)`
+fail_compilation/binexperr.d(12): Error: missing closing `)` after `if (A1 * (__error)`
+---
+*/
+
+void main()
+{
+    struct A1 {}
+    if (A1*) {}
+    return;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/biterrors5.d b/gcc/testsuite/gdc.test/fail_compilation/biterrors5.d
new file mode 100644
index 0000000000000000000000000000000000000000..2665d69cc98e7608d5d6021e936674755d5f5e10
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/biterrors5.d
@@ -0,0 +1,25 @@
+/* REQUIRED_ARGS: -preview=bitfields
+ * TEST_OUTPUT:
+---
+fail_compilation/biterrors5.d(23): Error: bitfield symbol expected not struct `biterrors5.S`
+fail_compilation/biterrors5.d(24): Error: bitfield symbol expected not variable `biterrors5.test0.i`
+---
+*/
+
+struct S
+{
+    int a,b;
+    int :2, c:3;
+}
+
+static assert(__traits(getBitfieldOffset, S.b) == 0);
+static assert(__traits(getBitfieldWidth, S.b) == 32);
+static assert(__traits(getBitfieldOffset, S.c) == 2);
+static assert(__traits(getBitfieldWidth, S.c) == 3);
+
+void test0()
+{
+    int i;
+    i = __traits(getBitfieldOffset, S);
+    i = __traits(getBitfieldOffset, i);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
index 02fc7db06183e8debd7b4c22cef4d806cdc442e4..60828bef17a7b6234fc30bd59ad5d10d74203579 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
@@ -65,7 +65,7 @@ TEST_OUTPUT:
 fail_compilation/bug9631.d(80): Error: function `f` is not callable using argument types `(int, S)`
 fail_compilation/bug9631.d(80):        cannot pass argument `y` of type `bug9631.tem!().S` to parameter `bug9631.S s`
 fail_compilation/bug9631.d(79):        `bug9631.arg.f(int i, S s)` declared here
-fail_compilation/bug9631.d(81): Error: function literal `__lambda4(S s)` is not callable using argument types `(S)`
+fail_compilation/bug9631.d(81): Error: function literal `__lambda_L81_C5(S s)` is not callable using argument types `(S)`
 fail_compilation/bug9631.d(81):        cannot pass argument `x` of type `bug9631.S` to parameter `bug9631.tem!().S s`
 fail_compilation/bug9631.d(87): Error: constructor `bug9631.arg.A.this(S __param_0)` is not callable using argument types `(S)`
 fail_compilation/bug9631.d(87):        cannot pass argument `S(0)` of type `bug9631.tem!().S` to parameter `bug9631.S __param_0`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d
index 7515208643711fb29ad8914ad27acae6f9dce0ee..b3a335b4e242e0ec6bec0715fcfdca7e8de65f1f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_defs.d
@@ -5,7 +5,7 @@ TEST_OUTPUT:
 fail_compilation/constraints_defs.d(49): Error: template instance `constraints_defs.main.def!(int, 0, (a) => a)` does not match template declaration `def(T, int i = 5, alias R)()`
   with `T = int,
        i = 0,
-       R = __lambda1`
+       R = __lambda_L49_C18`
   must satisfy the following constraint:
 `       N!T`
 fail_compilation/constraints_defs.d(50): Error: template instance `imports.constraints.defa!int` does not match template declaration `defa(T, U = int)()`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d b/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d
index 06caa52493d2e2285467545bcb424e8a300a13fc..fee7a3e3e7b1ad425714cc7959d28a5366578ee4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/constraints_tmpl.d
@@ -22,7 +22,7 @@ fail_compilation/constraints_tmpl.d(41): Error: template instance `imports.const
 `       N!T
        N!U`
 fail_compilation/constraints_tmpl.d(43): Error: template instance `constraints_tmpl.main.lambda!((a) => a)` does not match template declaration `lambda(alias pred)()`
-  with `pred = __lambda1`
+  with `pred = __lambda_L43_C13`
   must satisfy the following constraint:
 `       N!int`
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cppvar.d b/gcc/testsuite/gdc.test/fail_compilation/cppvar.d
index 885a55547c9bd3ca3fed34f81984fabc7abbe02f..213b54d10f56a797659223a42e5f94bbd1d58031 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/cppvar.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/cppvar.d
@@ -9,7 +9,7 @@ fail_compilation/cppvar.d(21): Error: variable `cppvar.staticVar` cannot have `e
 fail_compilation/cppvar.d(21):        perhaps declare it as `__gshared` instead
 fail_compilation/cppvar.d(22): Error: variable `cppvar.sharedVar` cannot have `extern(C++)` linkage because it is `shared`
 fail_compilation/cppvar.d(22):        perhaps declare it as `__gshared` instead
-fail_compilation/cppvar.d(30): Error: delegate `cppvar.__lambda7` cannot return type `bool[3]` because its linkage is `extern(C++)`
+fail_compilation/cppvar.d(30): Error: delegate `cppvar.__lambda_L30_C46` cannot return type `bool[3]` because its linkage is `extern(C++)`
 ---
 */
 #line 10
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
index aaedd0f72175a06ba085c37ce0dccead62502ae3..0ed04d3a7495f1ab40e9bd43b25a96b21a5fdf34 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag12829.d
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/diag12829.d(15): Error: function `diag12829.test1` is `@nogc` yet allocates closure for `test1()` with the GC
-fail_compilation/diag12829.d(18):        delegate `diag12829.test1.__lambda2` closes over variable `x`
+fail_compilation/diag12829.d(18):        delegate `diag12829.test1.__lambda_L18_C33` closes over variable `x`
 fail_compilation/diag12829.d(17):        `x` declared here
 fail_compilation/diag12829.d(22):        function `diag12829.test1.bar` closes over variable `x`
 fail_compilation/diag12829.d(17):        `x` declared here
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag15411.d b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
index 8b18c19d0276f58fa3d7ff8438356bb6511b976e..51060b8ffc158020f44eda3077e86911557fbb4e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag15411.d
@@ -2,9 +2,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag15411.d(17): Error: function `diag15411.test15411.__funcliteral2` cannot access variable `i` in frame of function `diag15411.test15411`
+fail_compilation/diag15411.d(17): Error: function `diag15411.test15411.__funcliteral_L17_C15` cannot access variable `i` in frame of function `diag15411.test15411`
 fail_compilation/diag15411.d(16):        `i` declared here
-fail_compilation/diag15411.d(18): Error: function `diag15411.test15411.__funcliteral4` cannot access variable `i` in frame of function `diag15411.test15411`
+fail_compilation/diag15411.d(18): Error: function `diag15411.test15411.__funcliteral_L18_C15` cannot access variable `i` in frame of function `diag15411.test15411`
 fail_compilation/diag15411.d(16):        `i` declared here
 fail_compilation/diag15411.d(26): Error: `static` function `diag15411.testNestedFunction.myFunc2` cannot access function `myFunc1` in frame of function `diag15411.testNestedFunction`
 fail_compilation/diag15411.d(25):        `myFunc1` declared here
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d
index 0653490267005f5440a8fe1db36406409007055c..5504aad0c7834d1c7e09f14838e03c045241ee7c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag20268.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag20268.d
@@ -3,8 +3,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag20268.d(12): Error: template `__lambda4` is not callable using argument types `!()(int)`
-fail_compilation/diag20268.d(11):        Candidate is: `__lambda4(__T1, __T2)(x, y)`
+fail_compilation/diag20268.d(12): Error: template `__lambda_L11_C1` is not callable using argument types `!()(int)`
+fail_compilation/diag20268.d(11):        Candidate is: `__lambda_L11_C1(__T1, __T2)(x, y)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag24812.d b/gcc/testsuite/gdc.test/fail_compilation/diag24812.d
new file mode 100644
index 0000000000000000000000000000000000000000..626f47ebf010f7708fd403e3913971057c9397fa
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag24812.d
@@ -0,0 +1,7 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/diag24812.d(7): Error: enum `diag24812.Foo` enum `Foo` must have at least one member
+---
+*/
+enum Foo {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
index c93a06a465ac85fe921d09d60276b344e8c98e8f..13995d4b6ad1216f5a50faa7470ed8512cb3b8b5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9831.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda3(__T1)(x)` cannot access variable `c` in frame of function `D main`
+fail_compilation/diag9831.d(13): Error: function `diag9831.main.__lambda_L13_C12(__T1)(x)` cannot access variable `c` in frame of function `D main`
 fail_compilation/diag9831.d(11):        `c` declared here
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d b/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
index f00f91a1fc81c3fc0799d01576a1c0112689411f..0173d4b78eff7dd88f1953e754cf8761c9692f52 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag_funclit.d
@@ -1,19 +1,19 @@
 /**
 TEST_OUTPUT:
 ---
-fail_compilation/diag_funclit.d(103): Error: function literal `__lambda1(x, y, z)` is not callable using argument types `()`
+fail_compilation/diag_funclit.d(103): Error: function literal `__lambda_L103_C5(x, y, z)` is not callable using argument types `()`
 fail_compilation/diag_funclit.d(103):        too few arguments, expected 3, got 0
-fail_compilation/diag_funclit.d(106): Error: function literal `__lambda2(x, y, z)` is not callable using argument types `(int, string, int, int)`
+fail_compilation/diag_funclit.d(106): Error: function literal `__lambda_L106_C5(x, y, z)` is not callable using argument types `(int, string, int, int)`
 fail_compilation/diag_funclit.d(106):        too many arguments, expected 3, got 4
-fail_compilation/diag_funclit.d(108): Error: function literal `__lambda3(x, y, string z = "Hello")` is not callable using argument types `(int, int, string, string)`
+fail_compilation/diag_funclit.d(108): Error: function literal `__lambda_L108_C5(x, y, string z = "Hello")` is not callable using argument types `(int, int, string, string)`
 fail_compilation/diag_funclit.d(108):        too many arguments, expected 3, got 4
-fail_compilation/diag_funclit.d(110): Error: function literal `__lambda4(x, y, string z = "Hello")` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(110): Error: function literal `__lambda_L110_C5(x, y, string z = "Hello")` is not callable using argument types `(int)`
 fail_compilation/diag_funclit.d(110):        too few arguments, expected 3, got 1
-fail_compilation/diag_funclit.d(112): Error: function literal `__lambda5(x, y, z)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(112): Error: function literal `__lambda_L112_C5(x, y, z)` is not callable using argument types `(int)`
 fail_compilation/diag_funclit.d(112):        too few arguments, expected 3, got 1
-fail_compilation/diag_funclit.d(115): Error: function literal `__lambda6(x, y, ...)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(115): Error: function literal `__lambda_L115_C5(x, y, ...)` is not callable using argument types `(int)`
 fail_compilation/diag_funclit.d(115):        too few arguments, expected 2, got 1
-fail_compilation/diag_funclit.d(117): Error: function literal `__lambda7(x, y, string z = "Hey", ...)` is not callable using argument types `(int)`
+fail_compilation/diag_funclit.d(117): Error: function literal `__lambda_L117_C5(x, y, string z = "Hey", ...)` is not callable using argument types `(int)`
 fail_compilation/diag_funclit.d(117):        too few arguments, expected 3, got 1
 ---
  */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d
index 0482e87a5492801df5d9c6fc9e2c74c51d9a79c6..100c5e1ed5a9ea5ddcb52a12b9cdf6fda37582dd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_3.d
@@ -16,7 +16,7 @@ fail_compilation/e15876_3.d(29): Error: found `End of File` when expecting `)`
 fail_compilation/e15876_3.d(29): Error: no identifier for declarator `d(_error_ = ()
 {
 for (__error__
- 0; 0)
+ __error; __error)
 {
 __error__
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d
index e5c3bbf5673313d235e56ac274fcae6e74de6789..a9115b92dd54d9af66496e405a37cbe3a831f8b0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/e15876_4.d
@@ -15,7 +15,7 @@ fail_compilation/e15876_4.d(27): Error: found `End of File` when expecting `)`
 fail_compilation/e15876_4.d(27): Error: no identifier for declarator `typeof(()
 {
 for (__error__
- 0; 0)
+ __error; __error)
 {
 __error__
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail11125.d b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
index 1a682cd197c834a079207fb64107e6638ecee48c..4349755519d17fa109ff312d87d6acf98f35de7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail11125.d
@@ -2,11 +2,11 @@
 TEST_OUTPUT:
 ---
 fail_compilation/fail11125.d(26): Error: template instance `fail11125.filter!(function (int a) pure nothrow @nogc @safe => a + 1)` does not match template declaration `filter(alias predfun)`
-  with `predfun = __lambda1`
+  with `predfun = __lambda_L26_C13`
   must satisfy the following constraint:
 `       is(ReturnType!predfun == bool)`
 fail_compilation/fail11125.d(27): Error: template instance `fail11125.filter!(function (int a) pure nothrow @nogc @safe => a + 1)` does not match template declaration `filter(alias predfun)`
-  with `predfun = __lambda2`
+  with `predfun = __lambda_L27_C17`
   must satisfy the following constraint:
 `       is(ReturnType!predfun == bool)`
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
index 824f5e48db2590d4dd305bf97c3a74b4f47f7adc..f27cc2a52159b870a2cf86b1b047382249a91a30 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12236.d
@@ -6,8 +6,8 @@ fail_compilation/fail12236.d(16):        while evaluating `pragma(msg, f1.mangle
 fail_compilation/fail12236.d(21): Error: forward reference to inferred return type of function `f2`
 fail_compilation/fail12236.d(21):        while evaluating `pragma(msg, f2(T)(T).mangleof)`
 fail_compilation/fail12236.d(27): Error: template instance `fail12236.f2!int` error instantiating
-fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda1`
-fail_compilation/fail12236.d(31):        while evaluating `pragma(msg, __lambda1(__T1)(a).mangleof)`
+fail_compilation/fail12236.d(31): Error: forward reference to inferred return type of function `__lambda_L29_C5`
+fail_compilation/fail12236.d(31):        while evaluating `pragma(msg, __lambda_L29_C5(__T1)(a).mangleof)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12378.d b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
index 77678ebc0fc08e757f224734ba0f15eb054b6241..5a0f9e05ab66d690b9b10cb0eb71639420e98a68 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12378.d
@@ -5,7 +5,7 @@ fail_compilation/fail12378.d(18): Error: undefined identifier `ANYTHING`
 fail_compilation/fail12378.d(18): Error: undefined identifier `GOES`
 fail_compilation/fail12378.d(91):        instantiated from here: `MapResultS!((x0) => ANYTHING - GOES, Result)`
 fail_compilation/fail12378.d(17):        instantiated from here: `mapS!(Result)`
-fail_compilation/fail12378.d(100):        instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(100):        instantiated from here: `__lambda_L16_C19!int`
 fail_compilation/fail12378.d(91):        instantiated from here: `MapResultS!((y0) => iota(2).mapS!((x0) => ANYTHING - GOES), Result)`
 fail_compilation/fail12378.d(16):        instantiated from here: `mapS!(Result)`
 ---
@@ -27,7 +27,7 @@ fail_compilation/fail12378.d(40): Error: undefined identifier `ANYTHING`
 fail_compilation/fail12378.d(40): Error: undefined identifier `GOES`
 fail_compilation/fail12378.d(112):        instantiated from here: `MapResultC!((x0) => ANYTHING - GOES, Result)`
 fail_compilation/fail12378.d(39):        instantiated from here: `mapC!(Result)`
-fail_compilation/fail12378.d(123):        instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(123):        instantiated from here: `__lambda_L38_C19!int`
 fail_compilation/fail12378.d(112):        instantiated from here: `MapResultC!((y0) => iota(2).mapC!((x0) => ANYTHING - GOES), Result)`
 fail_compilation/fail12378.d(38):        instantiated from here: `mapC!(Result)`
 ---
@@ -49,7 +49,7 @@ fail_compilation/fail12378.d(64): Error: undefined identifier `ANYTHING`
 fail_compilation/fail12378.d(64): Error: undefined identifier `GOES`
 fail_compilation/fail12378.d(135):        instantiated from here: `MapResultI!((x0) => ANYTHING - GOES, Result)`
 fail_compilation/fail12378.d(63):        instantiated from here: `mapI!(Result)`
-fail_compilation/fail12378.d(143):        instantiated from here: `__lambda1!int`
+fail_compilation/fail12378.d(143):        instantiated from here: `__lambda_L62_C19!int`
 fail_compilation/fail12378.d(135):        instantiated from here: `MapResultI!((y0) => iota(2).mapI!((x0) => ANYTHING - GOES), Result)`
 fail_compilation/fail12378.d(62):        instantiated from here: `mapI!(Result)`
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail12908.d b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
index 67ea6cefb22747862de49b0e9253652c62a1e9f8..3cc6306a80bb896e8edee6852074483c5c3b4e43 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail12908.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail12908.d(14): Error: `pure` delegate `fail12908.main.__foreachbody1` cannot call impure function `fail12908.g`
+fail_compilation/fail12908.d(14): Error: `pure` delegate `fail12908.main.__foreachbody_L12_C5` cannot call impure function `fail12908.g`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
index 6a1335eebd5b006ee8ad6345e31a018c19dc095a..1d1127c4c305b12f089be5afd1d07783b4322d53 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13120.d
@@ -1,8 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13120.d(13): Error: `pure` delegate `fail13120.g1.__foreachbody2` cannot call impure function `fail13120.f1`
-fail_compilation/fail13120.d(13): Error: `@nogc` delegate `fail13120.g1.__foreachbody2` cannot call non-@nogc function `fail13120.f1`
+fail_compilation/fail13120.d(13): Error: `pure` delegate `fail13120.g1.__foreachbody_L12_C5` cannot call impure function `fail13120.f1`
+fail_compilation/fail13120.d(13): Error: `@nogc` delegate `fail13120.g1.__foreachbody_L12_C5` cannot call non-@nogc function `fail13120.f1`
 ---
 */
 void f1() {}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13424.d b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
index dcec523a0133588373f646fee0d51045a0fb85d6..1a7f16b55c5599c8663c91c6225b18afb38d0bb0 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13424.d
@@ -1,9 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13424.d(12): Error: delegate `fail13424.S.__lambda2` cannot be struct members
-fail_compilation/fail13424.d(17): Error: delegate `fail13424.U.__lambda2` cannot be union members
-fail_compilation/fail13424.d(22): Error: delegate `fail13424.C.__lambda2` cannot be class members
+fail_compilation/fail13424.d(12): Error: delegate `fail13424.S.__lambda_L12_C35` cannot be struct members
+fail_compilation/fail13424.d(17): Error: delegate `fail13424.U.__lambda_L17_C35` cannot be union members
+fail_compilation/fail13424.d(22): Error: delegate `fail13424.C.__lambda_L22_C35` cannot be class members
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
index 29bc3f448d8364238bc93ad0fc7960bedec1390e..8272fb0b18c30028c298017426a59e5e6e1f3614 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17969.d
@@ -1,6 +1,6 @@
 /* TEST_OUTPUT:
 ---
-fail_compilation/fail17969.d(10): Error: no property `sum` for type `fail17969.__lambda6!(int[]).__lambda6.MapResult2!((b) => b)`
+fail_compilation/fail17969.d(10): Error: no property `sum` for type `fail17969.__lambda_L10_C1!(int[]).__lambda_L10_C1.MapResult2!((b) => b)`
 fail_compilation/fail17969.d(16):        struct `MapResult2` defined here
 ---
  * https://issues.dlang.org/show_bug.cgi?id=17969
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail39.d b/gcc/testsuite/gdc.test/fail_compilation/fail39.d
index c0bb0e16a076042f2856b75b577cbc1fa5aa3826..f740dda98f16744ff6da3e9fe9b3bd097de34f8c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail39.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail39.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail39.d(12): Error: function `fail39.main.__funcliteral2` cannot access function `foo` in frame of function `D main`
+fail_compilation/fail39.d(12): Error: function `fail39.main.__funcliteral_L12_C27` cannot access function `foo` in frame of function `D main`
 fail_compilation/fail39.d(11):        `foo` declared here
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
index 26d44296498801414682b78222ef778e90fc3d8a..dbdd5d5666b5eba1bb22f0f167c0adcb0ae7d77e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
@@ -8,9 +8,9 @@ fail_compilation/fail6795.d(22): Error: cannot modify expression `[0][0]` becaus
 fail_compilation/fail6795.d(23): Error: cannot modify expression `[0:0][0]` because it is not an lvalue
 fail_compilation/fail6795.d(25): Error: cannot take address of expression `[0][0]` because it is not an lvalue
 fail_compilation/fail6795.d(26): Error: cannot take address of expression `[0:0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(30): Error: cannot modify expression `Some["zz"]` because it is not an lvalue
 ---
 */
-
 void test_wrong_line_num()
 {
     enum int[1] sa = [0];
@@ -24,4 +24,8 @@ void test_wrong_line_num()
 
     auto ps = &sa[0];
     auto pa = &aa[0];
+
+    // https://issues.dlang.org/show_bug.cgi?id=24845
+    enum Maps : int[string] { Some = ["aa" : 12], Other = ["bb" : 24] }
+    Maps.Some["zz"] = 44;
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d
index 0f23f444389d901191fec1ac3759c11828f44c93..edbb4e67bc0daf0f08cf608f5d920cc9391423ab 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/hexstring.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/hexstring.d
@@ -14,6 +14,7 @@ fail_compilation/hexstring.d(39):        perhaps remove postfix `c` from hex str
 fail_compilation/hexstring.d(40): Error: hex string with `dstring` type needs to be multiple of 4 bytes, not 5
 fail_compilation/hexstring.d(41): Error: cannot implicitly convert expression `x"11223344"d` of type `dstring` to `immutable(float[])`
 fail_compilation/hexstring.d(42): Error: cannot implicitly convert expression `x"1122"w` of type `wstring` to `immutable(ubyte[])`
+fail_compilation/hexstring.d(50): Error: array cast from `string` to `S[]` is not supported at compile time
 fail_compilation/hexstring.d(28): Error: cannot implicitly convert expression `x"123F"` of type `string` to `ubyte[]`
 ---
 */
@@ -21,7 +22,6 @@ immutable ubyte[] s0 = x"123F";
 static assert(s0[0] == 0x12);
 static assert(s0[1] == 0x3F);
 immutable byte[] s1 = x"123F";
-
 enum E(X) = cast(X[]) x"AABBCCDD";
 static assert(E!int[0] == 0xAABBCCDD);
 
@@ -40,3 +40,11 @@ immutable uint[] f11 = cast(immutable uint[]) x"AABBCCDD"c;
 immutable uint[] f12 = x"1122334455"d;
 immutable float[] f13 = x"11223344"d;
 immutable ubyte[] f14 = x"1122"w;
+
+// https://issues.dlang.org/show_bug.cgi?id=24832
+struct S
+{
+    ushort l0, l1, l2, l3, l4, l5;
+}
+
+immutable S[] returnValues = cast(S[]) x"FFFFFFFFFFFFFFFFFFFFFFFF";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
index 552a9824f32e6a892d1e6c5187184a8d48394e36..fc6c593ae0a638049a18bc2d5b44cf0f049ef6ab 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10922.d
@@ -1,9 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice10922.d(11): Error: function `__lambda4` is not callable using argument types `()`
+fail_compilation/ice10922.d(11): Error: function `__lambda_L10_C12` is not callable using argument types `()`
 fail_compilation/ice10922.d(11):        too few arguments, expected 1, got 0
-fail_compilation/ice10922.d(10):        `ice10922.__lambda4(in uint n)` declared here
+fail_compilation/ice10922.d(10):        `ice10922.__lambda_L10_C12(in uint n)` declared here
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11822.d b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
index 830af212cb7add9261debf3343367e0f17907b78..a673a6b2dda6042eb878ca0aabdd66ea416c73bb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11822.d
@@ -5,8 +5,8 @@
 TEST_OUTPUT:
 ---
 fail_compilation/ice11822.d(33): Deprecation: function `ice11822.d` is deprecated
-fail_compilation/ice11822.d(16):        instantiated from here: `__lambda2!int`
-fail_compilation/ice11822.d(22):        instantiated from here: `S!(__lambda2)`
+fail_compilation/ice11822.d(16):        instantiated from here: `__lambda_L33_C15!int`
+fail_compilation/ice11822.d(22):        instantiated from here: `S!(__lambda_L33_C15)`
 fail_compilation/ice11822.d(33):        instantiated from here: `g!((n) => d(i))`
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice11850.d b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
index d33549a27f2ba79d1b6dd709b7a4275d68035cb1..510fe0aae82dcc9ba23bb4828ea3de6601a9f614 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice11850.d
@@ -3,7 +3,7 @@ EXTRA_FILES: imports/a11850.d
 TEST_OUTPUT:
 ---
 fail_compilation/ice11850.d(15): Error: incompatible types for `(a) < ([0])`: `uint[]` and `int[]`
-fail_compilation/imports/a11850.d(9):        instantiated from here: `FilterResult!(__lambda1, uint[][])`
+fail_compilation/imports/a11850.d(9):        instantiated from here: `FilterResult!(__lambda_L15_C13, uint[][])`
 fail_compilation/ice11850.d(15):        instantiated from here: `filter!(uint[][])`
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12235.d b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
index 8f2fefd099efb45d8f085e18ff000e6035655d26..ca453e0928d0774ec3a850cefef916f481be5bc6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12235.d
@@ -1,9 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function `__lambda1`
-fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function `__lambda1`
-fail_compilation/ice12235.d(15):        while evaluating `pragma(msg, __lambda1.mangleof)`
+fail_compilation/ice12235.d(14): Error: forward reference to inferred return type of function `__lambda_L12_C5`
+fail_compilation/ice12235.d(15): Error: forward reference to inferred return type of function `__lambda_L12_C5`
+fail_compilation/ice12235.d(15):        while evaluating `pragma(msg, __lambda_L12_C5.mangleof)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice15855.d b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d
index f7ad3900683f05d202a6e96a7d9433c69356ebbc..5d1cea1de72bd5bf944dc7fc0002070dc0bf9b60 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice15855.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice15855.d
@@ -15,7 +15,7 @@ fail_compilation/ice15855.d(28): Error: found `End of File` when expecting `]`
 fail_compilation/ice15855.d(28): Error: no identifier for declarator `a[()
 {
 for (__error__
- 0; 0)
+ __error; __error)
 {
 __error__
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8309.d b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
index 2446914477a177077658cddc7d7f3ef1f3a2940e..a9f6f7253acbf6e52e6d8e104156584c868c92c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8309.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice8309.d(10): Error: incompatible types for `(__lambda1) : (__lambda2)`: `double function() pure nothrow @nogc @safe` and `int function() pure nothrow @nogc @safe`
+fail_compilation/ice8309.d(10): Error: incompatible types for `(__lambda_L10_C15) : (__lambda_L10_C24)`: `double function() pure nothrow @nogc @safe` and `int function() pure nothrow @nogc @safe`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice8795.d b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
index a30a65b200b75ca1b296fee469d8a7c5486d16ab..33aa6e4d54b4b464f900dffcdf43ba252736a3b3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice8795.d
@@ -3,7 +3,7 @@ TEST_OUTPUT:
 ---
 fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` when expecting `(`
 fail_compilation/ice8795.d-mixin-14(14): Error: expression expected, not `End of File`
-fail_compilation/ice8795.d-mixin-14(14): Error: missing closing `)` after `switch (0`
+fail_compilation/ice8795.d-mixin-14(14): Error: missing closing `)` after `switch (__error`
 fail_compilation/ice8795.d-mixin-14(14): Error: found `End of File` instead of statement
 fail_compilation/ice8795.d-mixin-15(15): Error: { } expected following `interface` declaration
 fail_compilation/ice8795.d-mixin-15(15): Error: anonymous interfaces not allowed
diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc1.d b/gcc/testsuite/gdc.test/fail_compilation/misc1.d
index 95bcc6d03d47db704f0752b69cfed7596660ebe0..90e42d83e9911a0c43aadf3ef1e2362a53a52c5e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/misc1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/misc1.d
@@ -5,7 +5,7 @@ fail_compilation/misc1.d(109): Error: `5` has no effect
 fail_compilation/misc1.d(110): Error: `1 + 2` has no effect
 fail_compilation/misc1.d(111): Error: `x` has no effect
 fail_compilation/misc1.d(117): Deprecation: `1 * 1` has no effect
-fail_compilation/misc1.d(118): Deprecation: `__lambda3` has no effect
+fail_compilation/misc1.d(118): Deprecation: `__lambda_L118_C34` has no effect
 fail_compilation/misc1.d(124): Deprecation: `false` has no effect
 fail_compilation/misc1.d(127): Deprecation: `*sp++` has no effect
 fail_compilation/misc1.d(128): Deprecation: `j` has no effect
diff --git a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
index a170b77b88c2fd6e78a584d98b9cc3f324b54a06..4a8875d6d69cde16ef0baf69982063ab07c23929 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/misc_parser_err_cov1.d
@@ -24,7 +24,7 @@ fail_compilation/misc_parser_err_cov1.d(40): Error: identifier or `new` expected
 fail_compilation/misc_parser_err_cov1.d(41): Error: identifier or new keyword expected following `(...)`.
 fail_compilation/misc_parser_err_cov1.d(41): Error: expression expected, not `;`
 fail_compilation/misc_parser_err_cov1.d(42): Error: found `}` when expecting `;` following expression
-fail_compilation/misc_parser_err_cov1.d(41):        expression: `(__error) + 0`
+fail_compilation/misc_parser_err_cov1.d(41):        expression: `(__error) + (__error)`
 fail_compilation/misc_parser_err_cov1.d(43): Error: matching `}` expected following compound statement, not `End of File`
 fail_compilation/misc_parser_err_cov1.d(33):        unmatched `{`
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
index 8414bf12845481547afb22c0cb2d5e58edc47cc9..3eef0f92937210c980f82c9ceba12d18b430e148 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
@@ -1,7 +1,7 @@
 /* TEST_OUTPUT:
 ---
 fail_compilation/opapplyscope.d(113): Error: function `opapplyscope.S.opApply(scope int delegate(scope int* ptr) @safe dg)` is not callable using argument types `(int delegate(int* x) nothrow @nogc @safe)`
-fail_compilation/opapplyscope.d(113):        cannot pass argument `__foreachbody3` of type `int delegate(int* x) nothrow @nogc @safe` to parameter `scope int delegate(scope int* ptr) @safe dg`
+fail_compilation/opapplyscope.d(113):        cannot pass argument `__foreachbody_L113_C5` of type `int delegate(int* x) nothrow @nogc @safe` to parameter `scope int delegate(scope int* ptr) @safe dg`
 ---
  */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/previewin.d b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
index 486dcd5244d28da01bf35f1fd7b670417e796e27..c3d11cbfd0b9f2a7f81bc891501ae611678f9de3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/previewin.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/previewin.d
@@ -3,13 +3,13 @@ REQUIRED_ARGS: -preview=in -preview=dip1000
 TEST_OUTPUT:
 ----
 fail_compilation/previewin.d(4): Error: function `takeFunction` is not callable using argument types `(void function(real x) pure nothrow @nogc @safe)`
-fail_compilation/previewin.d(4):        cannot pass argument `__lambda1` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(4):        cannot pass argument `__lambda_L4_C18` of type `void function(real x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
 fail_compilation/previewin.d(11):        `previewin.takeFunction(void function(in real) f)` declared here
 fail_compilation/previewin.d(5): Error: function `takeFunction` is not callable using argument types `(void function(scope const(real) x) pure nothrow @nogc @safe)`
-fail_compilation/previewin.d(5):        cannot pass argument `__lambda2` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(5):        cannot pass argument `__lambda_L5_C18` of type `void function(scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
 fail_compilation/previewin.d(11):        `previewin.takeFunction(void function(in real) f)` declared here
 fail_compilation/previewin.d(6): Error: function `takeFunction` is not callable using argument types `(void function(ref scope const(real) x) pure nothrow @nogc @safe)`
-fail_compilation/previewin.d(6):        cannot pass argument `__lambda3` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
+fail_compilation/previewin.d(6):        cannot pass argument `__lambda_L6_C18` of type `void function(ref scope const(real) x) pure nothrow @nogc @safe` to parameter `void function(in real) f`
 fail_compilation/previewin.d(11):        `previewin.takeFunction(void function(in real) f)` declared here
 fail_compilation/previewin.d(15): Error: scope variable `arg` assigned to global variable `myGlobal`
 fail_compilation/previewin.d(16): Error: scope variable `arg` assigned to global variable `myGlobal`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
index 919d9401cd5f960d1b72ef579edd1f9c2f665dff..acad99bdaf6c9086183ce5aa29cf5811d6ce1a5a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
@@ -55,7 +55,7 @@ void test2(scope int* p, int[] a ...) @safe
 TEST_OUTPUT:
 ---
 fail_compilation/retscope.d(75): Error: function `retscope.HTTP.Impl.onReceive` is `@nogc` yet allocates closure for `onReceive()` with the GC
-fail_compilation/retscope.d(77):        delegate `retscope.HTTP.Impl.onReceive.__lambda1` closes over variable `this`
+fail_compilation/retscope.d(77):        delegate `retscope.HTTP.Impl.onReceive.__lambda_L77_C23` closes over variable `this`
 ---
 */
 
@@ -234,10 +234,10 @@ void* funretscope(scope dg_t ptr) @safe
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
-fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda2` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
-fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
-fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda4` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
+fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda_L248_C21` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
+fail_compilation/retscope.d(248): Error: cannot implicitly convert expression `__lambda_L248_C21` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
+fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda_L249_C21` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
+fail_compilation/retscope.d(249): Error: cannot implicitly convert expression `__lambda_L249_C21` of type `void* delegate() pure nothrow @nogc @safe` to `void* delegate() scope @safe`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/safer.d b/gcc/testsuite/gdc.test/fail_compilation/safer.d
new file mode 100644
index 0000000000000000000000000000000000000000..a7f260a2848930ba9be89141ac648237e9d866d4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/safer.d
@@ -0,0 +1,18 @@
+/* REQUIRED_ARGS: -preview=safer
+TEST_OUTPUT:
+---
+fail_compilation/safer.d(10): Error: `void` initializers for pointers not allowed in safe functions
+---
+*/
+
+void test1()
+{
+    int* p = void;
+}
+
+void foo3() { }
+
+void test2()
+{
+    foo3(); // should not be an error
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15306.d b/gcc/testsuite/gdc.test/fail_compilation/test15306.d
index ff532aea220aba820883d88a99ef8146a5d19842..a60e27404215092eb5de79ad34f6b801daa5de46 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15306.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15306.d
@@ -1,8 +1,8 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test15306.d(15): Error: `immutable` delegate `test15306.main.__dgliteral2` cannot access mutable data `i`
-fail_compilation/test15306.d(19): Error: `shared` delegate `test15306.main.__dgliteral5` cannot access non-shared data `p`
+fail_compilation/test15306.d(15): Error: `immutable` delegate `test15306.main.__dgliteral_L15_C16` cannot access mutable data `i`
+fail_compilation/test15306.d(19): Error: `shared` delegate `test15306.main.__dgliteral_L19_C16` cannot access non-shared data `p`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16193.d b/gcc/testsuite/gdc.test/fail_compilation/test16193.d
index 39399cf01d8056b0a9f282b476ace0e233c7d075..84dc7d1c6d75e7d42b1fa1cdb08989a1bda659b4 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16193.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16193.d
@@ -3,7 +3,7 @@ REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
 fail_compilation/test16193.d(39): Error: function `test16193.abc` is `@nogc` yet allocates closure for `abc()` with the GC
-fail_compilation/test16193.d(41):        delegate `test16193.abc.__foreachbody2` closes over variable `x`
+fail_compilation/test16193.d(41):        delegate `test16193.abc.__foreachbody_L41_C5` closes over variable `x`
 fail_compilation/test16193.d(40):        `x` declared here
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test17451.d b/gcc/testsuite/gdc.test/fail_compilation/test17451.d
index b0cda2105a22aeff6230696b8dc365db60d8d9a7..7df77f591f304b037c4ddf52ccdec462a15b7fd7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test17451.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test17451.d
@@ -2,7 +2,7 @@
 ---
 fail_compilation/test17451.d(22): Error: undefined identifier `allocator`
 fail_compilation/test17451.d(23): Error: `false` has no effect
-fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda2.v` - size of type `ThreadSlot` is invalid
+fail_compilation/test17451.d(30): Error: variable `test17451.HashMap!(ThreadSlot).HashMap.__lambda_L30_C20.v` - size of type `ThreadSlot` is invalid
 fail_compilation/test17451.d(44): Error: template instance `test17451.HashMap!(ThreadSlot)` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19107.d b/gcc/testsuite/gdc.test/fail_compilation/test19107.d
index 9a6e335864779fbb07b52035c10e27a5ed37924b..8bbfa82717f65c902a69379d7f1cc2d49584d8c5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test19107.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19107.d
@@ -4,7 +4,7 @@ TEST_OUTPUT:
 ---
 fail_compilation/test19107.d(24): Error: template `all` is not callable using argument types `!((c) => c)(string[])`
 fail_compilation/test19107.d(18):        Candidate is: `all(alias pred, T)(T t)`
-  with `pred = __lambda2,
+  with `pred = __lambda_L24_C15,
        T = string[]`
   must satisfy the following constraint:
 `       is(typeof(I!pred(t)))`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19971.d b/gcc/testsuite/gdc.test/fail_compilation/test19971.d
index 3d46eeb82ef07feb8beb80a45a97616b74e7dc75..b99afddbdd50ee94db786ee0afb75e53f5a0c1bb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test19971.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19971.d
@@ -3,7 +3,7 @@
 fail_compilation/test19971.d(16): Error: function `f` is not callable using argument types `(string)`
 fail_compilation/test19971.d(16):        cannot pass argument `"%s"` of type `string` to parameter `int x`
 fail_compilation/test19971.d(13):        `test19971.f(int x)` declared here
-fail_compilation/test19971.d(17): Error: function literal `__lambda1(int x)` is not callable using argument types `(string)`
+fail_compilation/test19971.d(17): Error: function literal `__lambda_L17_C5(int x)` is not callable using argument types `(string)`
 fail_compilation/test19971.d(17):        cannot pass argument `"%s"` of type `string` to parameter `int x`
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test20719.d b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
index b9305f20f80fac4ff7311e1d0c33053cf0249a8b..4db59d62ae1f4baa1a7782003d93ea0f6a01eac9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test20719.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test20719.d
@@ -1,7 +1,7 @@
 /* TEST_OUTPUT:
 ---
 fail_compilation/test20719.d(13): Error: struct `test20719.SumType` no size because of forward reference
-fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda2.foo` - size of type `SumType` is invalid
+fail_compilation/test20719.d(32): Error: variable `test20719.isCopyable!(SumType).__lambda_L32_C22.foo` - size of type `SumType` is invalid
 fail_compilation/test20719.d(18): Error: template instance `test20719.isCopyable!(SumType)` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21912.d b/gcc/testsuite/gdc.test/fail_compilation/test21912.d
index f8bcb40b5dfbe058368c7eaecbe1b5d8ab9adcdb..7e236c8a33a226b7f2f69c61669da266f380fbe7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test21912.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21912.d
@@ -3,16 +3,16 @@ PERMUTE_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
 fail_compilation/test21912.d(28): Error: function `test21912.escapeParam` is `@nogc` yet allocates closure for `escapeParam()` with the GC
-fail_compilation/test21912.d(30):        delegate `test21912.escapeParam.__lambda2` closes over variable `i`
+fail_compilation/test21912.d(30):        delegate `test21912.escapeParam.__lambda_L30_C21` closes over variable `i`
 fail_compilation/test21912.d(28):        `i` declared here
 fail_compilation/test21912.d(33): Error: function `test21912.escapeAssign` is `@nogc` yet allocates closure for `escapeAssign()` with the GC
-fail_compilation/test21912.d(35):        delegate `test21912.escapeAssign.__lambda3` closes over variable `i`
+fail_compilation/test21912.d(35):        delegate `test21912.escapeAssign.__lambda_L35_C10` closes over variable `i`
 fail_compilation/test21912.d(33):        `i` declared here
 fail_compilation/test21912.d(44): Error: function `test21912.escapeAssignRef` is `@nogc` yet allocates closure for `escapeAssignRef()` with the GC
-fail_compilation/test21912.d(46):        delegate `test21912.escapeAssignRef.__lambda3` closes over variable `i`
+fail_compilation/test21912.d(46):        delegate `test21912.escapeAssignRef.__lambda_L46_C10` closes over variable `i`
 fail_compilation/test21912.d(44):        `i` declared here
 fail_compilation/test21912.d(55): Error: function `test21912.escapeParamInferred` is `@nogc` yet allocates closure for `escapeParamInferred()` with the GC
-fail_compilation/test21912.d(57):        delegate `test21912.escapeParamInferred.__lambda2` closes over variable `i`
+fail_compilation/test21912.d(57):        delegate `test21912.escapeParamInferred.__lambda_L57_C29` closes over variable `i`
 fail_compilation/test21912.d(55):        `i` declared here
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23170.d b/gcc/testsuite/gdc.test/fail_compilation/test23170.d
index eb79cd81565eda2bb9802e0e1e1d5c9a8af45a33..fedf31b5fc838364797dc3bf664dd6d744eb3554 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test23170.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test23170.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test23170.d(10): Error: array literal in `@nogc` delegate `test23170.__lambda5` may cause a GC allocation
+fail_compilation/test23170.d(10): Error: array literal in `@nogc` delegate `test23170.__lambda_L10_C15` may cause a GC allocation
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=23170
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24353.d b/gcc/testsuite/gdc.test/fail_compilation/test24353.d
new file mode 100644
index 0000000000000000000000000000000000000000..76174aee62dda9639cf9caa0c66c0bb296571554
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24353.d
@@ -0,0 +1,24 @@
+// https://issues.dlang.org/show_bug.cgi?id=24353
+
+/**
+TEST_OUTPUT:
+---
+fail_compilation/test24353.d(23): Error: mutable method `test24353.S.opApply` is not callable using a `const` object
+fail_compilation/test24353.d(14):        Consider adding `const` or `inout` here
+---
+*/
+
+
+struct S
+{
+    int opApply(int delegate(int) dg)
+    {
+        return 0;
+    }
+}
+
+void example()
+{
+    const S s;
+    foreach (e; s) {} // Error expected here
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24745.d b/gcc/testsuite/gdc.test/fail_compilation/test24745.d
new file mode 100644
index 0000000000000000000000000000000000000000..6d9c335bb4af3f30752506d6c06563fb3225d725
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24745.d
@@ -0,0 +1,13 @@
+// https://issues.dlang.org/show_bug.cgi?id=24745
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24745.d(12): Error: incorrect syntax for associative array, expected `[]`, found `{}`
+---
+*/
+
+void main()
+{
+    int[int] f = {1: 1, 2: 2};
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testInference.d b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
index 145fc9e8b9d6cb19353e3efa52cf861e7483a18b..b3a8a561cf9f0ef875a0918bd10f9e39b940ba55 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testInference.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testInference.d
@@ -138,7 +138,7 @@ immutable(void)* g10063(inout int* p) pure
 TEST_OUTPUT:
 ---
 fail_compilation/testInference.d(154): Error: `pure` function `testInference.bar14049` cannot call impure function `testInference.foo14049!int.foo14049`
-fail_compilation/testInference.d(149):        which calls `testInference.foo14049!int.foo14049.__lambda2`
+fail_compilation/testInference.d(149):        which calls `testInference.foo14049!int.foo14049.__lambda_L147_C14`
 fail_compilation/testInference.d(148):        which calls `testInference.impure14049`
 fail_compilation/testInference.d(143):        which wasn't inferred `pure` because of:
 fail_compilation/testInference.d(143):        `pure` function `testInference.impure14049` cannot access mutable static data `i`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/traits_alone.d b/gcc/testsuite/gdc.test/fail_compilation/traits_alone.d
index 8f6f145e6bf48dd8e4507c23f318a7d0b10b0c5f..66062fdab69c29cb8485ad9d858eaaa70c954d9f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/traits_alone.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/traits_alone.d
@@ -3,7 +3,7 @@ TEST_OUTPUT:
 ---
 fail_compilation/traits_alone.d(11): Error: found `End of File` when expecting `(`
 fail_compilation/traits_alone.d(11): Error: `__traits(identifier, args...)` expected
-fail_compilation/traits_alone.d(11): Error: no identifier for declarator `_error_`
+fail_compilation/traits_alone.d(11): Error: no identifier for declarator `$r:_?_error_?$`
 ---
 */
 //used to segfault
diff --git a/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d
index 8609d29b58cbc3a0ede1525ce30060e258747a07..0753b13f31857dd5817076e382de2a860e6d470b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/var_func_attr.d
@@ -1,7 +1,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/var_func_attr.d(19): Error: cannot implicitly convert expression `__lambda8` of type `void function() nothrow @nogc @safe` to `void function() pure`
+fail_compilation/var_func_attr.d(19): Error: cannot implicitly convert expression `__lambda_L19_C27` of type `void function() nothrow @nogc @safe` to `void function() pure`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d b/gcc/testsuite/gdc.test/runnable/mangle.d
index 53d7648099734d7dafdedac3d7ae7ad6923e3841..76a4adfab7fa888a956470a3ec8c8e6bd03a7f81 100644
--- a/gcc/testsuite/gdc.test/runnable/mangle.d
+++ b/gcc/testsuite/gdc.test/runnable/mangle.d
@@ -448,11 +448,11 @@ void test11776()
         if (1)
         {
             auto s = S11776!(a => 1)();
-            static assert(typeof(s).mangleof ==
-                "S"~"6mangle"~tl!("56")~
+            enum expected = "S"~"6mangle"~tl!("56")~
                 ("__T"~"6S11776"~"S"~tl!("42")~
-                 (id!("6mangle","Qs")~"9test11776"~"FZ"~"9__lambda1MFZ"~id!("9__lambda1","Qn"))~"Z"
-                 )~id!("6S11776", "QBm"));
+                 (id!("6mangle","Qs")~"9test11776"~"FZ"~"17__lambda_L444_C14MFZ17__lambda_L450_C30")~"Z"
+                 )~id!("6S11776", "QCm");
+            static assert(typeof(s).mangleof == expected);
         }
     };
 }
@@ -509,7 +509,7 @@ void func12231a()()
 if (is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle"~tl!("16")~"__U10func12231aZ"~id!("10func12231a","Qn")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("16")~"__U10func12231aZ"~id!("10func12231a","Qn")~"FZ17__lambda_L509_C15MFZ1C");
             //         ###            L                       #
     })))
 {}
@@ -517,13 +517,13 @@ if (is(typeof({
 void func12231b()()
 if (is(typeof({
         class C {}        static assert(C.mangleof ==
-            "C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ17__lambda_L518_C15MFZ1C");
             //         L__L           L                       LL
       })) &&
     is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ9__lambda2MFZ1C");
+            "C6mangle"~tl!("16")~"__U10func12231bZ"~id!("10func12231b","Qn")~"FZ17__lambda_L523_C15MFZ1C");
             //         L__L           L                       LL
     })))
 {}
@@ -532,14 +532,14 @@ void func12231c()()
 if (is(typeof({
         class C {}
         static assert(C.mangleof ==
-            "C6mangle"~tl!("16")~"__U10func12231cZ"~id!("10func12231c","Qn")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("16")~"__U10func12231cZ"~id!("10func12231c","Qn")~"FZ17__lambda_L532_C15MFZ1C");
             //         L__L           L                       LL
     })))
 {
     (){
         class C {}
         static assert(C.mangleof ==
-            "C6mangle"~tl!("16")~"__T10func12231cZ"~id!("10func12231c","Qn")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("16")~"__T10func12231cZ"~id!("10func12231c","Qn")~"FZ16__lambda_L539_C5MFZ1C");
             //         L__L           L                       LL
     }();
 }
@@ -548,14 +548,14 @@ void func12231c(X)()
 if (is(typeof({
         class C {}
     static assert(C.mangleof ==
-            "C6mangle"~tl!("20")~"__U10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("20")~"__U10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ17__lambda_L548_C15MFZ1C");
             //         L__L           L___L                       LL
     })))
 {
     (){
         class C {}
         static assert(C.mangleof ==
-            "C6mangle"~tl!("20")~"__T10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ9__lambda1MFZ1C");
+            "C6mangle"~tl!("20")~"__T10func12231cTAyaZ"~id!("10func12231c","Qr")~"FZ16__lambda_L555_C5MFZ1C");
             //         L__L           L___L                       LL
     }();
 }
@@ -616,7 +616,7 @@ static assert(funcd.mangleof == "_D6mangle5funcdFPFZNnZi");
 struct S21753 { void function() f1; }
 void fun21753(S21753 v)() {}
 alias fl21753 = (){};
-static assert((fun21753!(S21753(fl21753))).mangleof == "_D6mangle__T8fun21753VSQv6S21753S1f_DQBj10" ~ fl21753.stringof ~ "MFNaNbNiNfZvZQCbQp");
+static assert((fun21753!(S21753(fl21753))).mangleof == "_D6mangle__T8fun21753VSQv6S21753S1f_DQBj16" ~ fl21753.stringof ~ "MFNaNbNiNfZvZQChQp");
 
 /***************************************************/
 void main()
diff --git a/gcc/testsuite/gdc.test/runnable/test24884.d b/gcc/testsuite/gdc.test/runnable/test24884.d
new file mode 100644
index 0000000000000000000000000000000000000000..0070d2b932452a33be4fa84cb5e1a960587232c1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test24884.d
@@ -0,0 +1,34 @@
+/*
+REQUIRED_ARGS: -inline
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24884
+
+pragma(inline, false)
+bool norm(int a) => 0;
+
+pragma(inline, false)
+void inlinebug(ref double[4] point1, ref double[4] point2, ref double[4] point3, ref double[4] abcd)
+{
+    double[4] v1 = 0.0;
+    double[4] v2 = 0.0;
+
+    v1[0] = point1[0] - point2[0];
+    v1[1] = point1[1] - point2[1];
+    v1[2] = point1[2] - point2[2];
+    v1[3] = point1[3];
+    v2[0] = point2[0] - point3[0];
+    v2[1] = point2[1] - point3[1];
+    v2[2] = point2[2] - point3[2];
+
+    int p = cast(int) &abcd;
+    int q = cast(int) &point1;
+    abcd[0] = norm(7) + p;
+    abcd[1] = q + p;
+}
+
+extern(C) void main()
+{
+    double[4] a = 0.0;
+    inlinebug(a, a, a, a);
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testkeyword.d b/gcc/testsuite/gdc.test/runnable/testkeyword.d
index 5fb4d4420380503323d4c49a6652a306a752e3bb..7f8bded2543b9132ce826c7b1f58245cec99c6c8 100644
--- a/gcc/testsuite/gdc.test/runnable/testkeyword.d
+++ b/gcc/testsuite/gdc.test/runnable/testkeyword.d
@@ -97,8 +97,8 @@ void main(string[] args) nothrow
 
     auto funcLiteral = (int x, int y)
     {
-        enum thisFunc  = "testkeyword.main.__lambda5";
-        enum thisFunc2 = "testkeyword.main.__lambda5(int x, int y)";
+        enum thisFunc  = "testkeyword.main.__lambda_L98_C24";
+        enum thisFunc2 = "testkeyword.main.__lambda_L98_C24(int x, int y)";
 
         static assert(getFuncArgFile()  == thisFile);
         static assert(getFuncArgLine()  == 104);
diff --git a/gcc/testsuite/gdc.test/runnable/traits.d b/gcc/testsuite/gdc.test/runnable/traits.d
index 5186987deaea57354da92d5bae515532deeef318..7722d9dd6d9190c973ca8e0008df6c1175695639 100644
--- a/gcc/testsuite/gdc.test/runnable/traits.d
+++ b/gcc/testsuite/gdc.test/runnable/traits.d
@@ -10,7 +10,7 @@ Creating library {{RESULTS_DIR}}/runnable/traits_0.lib and object {{RESULTS_DIR}
 TRANSFORM_OUTPUT: remove_lines("Creating library")
 TEST_OUTPUT:
 ---
-__lambda1
+__lambda_L1073_C5
 ---
 */
 
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index f660884c3b9590a9f318b1d3025a5c9b36456315..bfdc9ea21e1e45e373e84f60baddf81994375890 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-2b89c2909de239bd603d6f36379658fe902667db
+82a5d2a7c4dd3d270537bcede2981e047bfd0e6a
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index a20bf6bdff76b398ca4fb5652360bbc9ca29e97a..7713c8cf5a8da322a1182ac009f059de0576e759 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -188,6 +188,7 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
 	core/internal/container/treap.d core/internal/convert.d \
 	core/internal/dassert.d core/internal/destruction.d \
 	core/internal/entrypoint.d core/internal/gc/bits.d \
+	core/internal/gc/blkcache.d core/internal/gc/blockmeta.d \
 	core/internal/gc/impl/conservative/gc.d \
 	core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \
 	core/internal/gc/os.d core/internal/gc/pooltable.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 53c197e5d89f0d4ef3b8192e95dc341249851dc1..f4d55523bfaa8784f557b55434eca65405ede1b9 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -209,6 +209,7 @@ am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
 	core/internal/container/treap.lo core/internal/convert.lo \
 	core/internal/dassert.lo core/internal/destruction.lo \
 	core/internal/entrypoint.lo core/internal/gc/bits.lo \
+	core/internal/gc/blkcache.lo core/internal/gc/blockmeta.lo \
 	core/internal/gc/impl/conservative/gc.lo \
 	core/internal/gc/impl/manual/gc.lo \
 	core/internal/gc/impl/proto/gc.lo core/internal/gc/os.lo \
@@ -868,6 +869,7 @@ DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
 	core/internal/container/treap.d core/internal/convert.d \
 	core/internal/dassert.d core/internal/destruction.d \
 	core/internal/entrypoint.d core/internal/gc/bits.d \
+	core/internal/gc/blkcache.d core/internal/gc/blockmeta.d \
 	core/internal/gc/impl/conservative/gc.d \
 	core/internal/gc/impl/manual/gc.d core/internal/gc/impl/proto/gc.d \
 	core/internal/gc/os.d core/internal/gc/pooltable.d \
@@ -1265,6 +1267,8 @@ core/internal/gc/$(am__dirstamp):
 	@$(MKDIR_P) core/internal/gc
 	@: > core/internal/gc/$(am__dirstamp)
 core/internal/gc/bits.lo: core/internal/gc/$(am__dirstamp)
+core/internal/gc/blkcache.lo: core/internal/gc/$(am__dirstamp)
+core/internal/gc/blockmeta.lo: core/internal/gc/$(am__dirstamp)
 core/internal/gc/impl/conservative/$(am__dirstamp):
 	@$(MKDIR_P) core/internal/gc/impl/conservative
 	@: > core/internal/gc/impl/conservative/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/internal/array/arrayassign.d b/libphobos/libdruntime/core/internal/array/arrayassign.d
index 6e3c1fdc3effd8389190f68ed13d13cfe2c31a2f..21690caf5d940e231c4fa5121d0726b02345b26f 100644
--- a/libphobos/libdruntime/core/internal/array/arrayassign.d
+++ b/libphobos/libdruntime/core/internal/array/arrayassign.d
@@ -347,7 +347,7 @@ Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @
         static if (__traits(isCopyable, T))
             copyEmplace(value, dst);
         else
-            memcpy(cast(void*) &value, cast(void*) &dst, elemSize);
+            memcpy(cast(void*) &dst, cast(void*) &value, elemSize);
         auto elem = cast(Unqual!T*) &tmp;
         destroy(*elem);
     }
@@ -395,6 +395,20 @@ Tarr _d_arraysetassign(Tarr : T[], T)(return scope Tarr to, scope ref T value) @
     assert(arr == [S(1234), S(1234), S(1234), S(1234)]);
 }
 
+// disabled copy constructor
+@safe unittest
+{
+    static struct S
+    {
+        int val;
+        @disable this(ref S);
+    }
+    S[1] arr;
+    S s = S(1234);
+    _d_arraysetassign(arr[], s);
+    assert(arr[0].val == 1234);
+}
+
 // throwing and `nothrow`
 @safe nothrow unittest
 {
diff --git a/libphobos/libdruntime/core/internal/array/utils.d b/libphobos/libdruntime/core/internal/array/utils.d
index 89ce6ca21837868dda61d3bb9d0c065e7fb3929e..c45913d87e1b0d9483b3325da92c3733e879f506 100644
--- a/libphobos/libdruntime/core/internal/array/utils.d
+++ b/libphobos/libdruntime/core/internal/array/utils.d
@@ -263,111 +263,7 @@ void *__arrayStart()(return scope BlkInfo info) nothrow pure
  */
 bool __setArrayAllocLength(T)(ref BlkInfo info, size_t newLength, bool isShared, size_t oldLength = ~0)
 {
-    import core.atomic;
     import core.lifetime : TypeInfoSize;
-
-    size_t typeInfoSize = TypeInfoSize!T;
-
-    if (info.size <= 256)
-    {
-        import core.checkedint;
-
-        bool overflow;
-        auto newLengthPadded = addu(newLength,
-                                     addu(SMALLPAD, typeInfoSize, overflow),
-                                     overflow);
-
-        if (newLengthPadded > info.size || overflow)
-            // new size does not fit inside block
-            return false;
-
-        auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
-        if (oldLength != ~0)
-        {
-            if (isShared)
-            {
-                return cas(cast(shared)length, cast(ubyte)oldLength, cast(ubyte)newLength);
-            }
-            else
-            {
-                if (*length == cast(ubyte)oldLength)
-                    *length = cast(ubyte)newLength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = cast(ubyte)newLength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
-            *typeInfo = cast()typeid(T);
-        }
-    }
-    else if (info.size < PAGESIZE)
-    {
-        if (newLength + MEDPAD + typeInfoSize > info.size)
-            // new size does not fit inside block
-            return false;
-        auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
-        if (oldLength != ~0)
-        {
-            if (isShared)
-            {
-                return cas(cast(shared)length, cast(ushort)oldLength, cast(ushort)newLength);
-            }
-            else
-            {
-                if (*length == oldLength)
-                    *length = cast(ushort)newLength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = cast(ushort)newLength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
-            *typeInfo = cast()typeid(T);
-        }
-    }
-    else
-    {
-        if (newLength + LARGEPAD > info.size)
-            // new size does not fit inside block
-            return false;
-        auto length = cast(size_t *)(info.base);
-        if (oldLength != ~0)
-        {
-            if (isShared)
-            {
-                return cas(cast(shared)length, cast(size_t)oldLength, cast(size_t)newLength);
-            }
-            else
-            {
-                if (*length == oldLength)
-                    *length = newLength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = newLength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
-            *typeInfo = cast()typeid(T);
-        }
-    }
-    return true; // resize succeeded
+    import core.internal.gc.blockmeta : __setArrayAllocLengthImpl;
+    return __setArrayAllocLengthImpl(info, newLength, isShared, typeid(T), oldLength, TypeInfoSize!T);
 }
diff --git a/libphobos/libdruntime/core/internal/gc/blkcache.d b/libphobos/libdruntime/core/internal/gc/blkcache.d
new file mode 100644
index 0000000000000000000000000000000000000000..c555c22f636fb728e7e9d8d23ab7407dcd7abe04
--- /dev/null
+++ b/libphobos/libdruntime/core/internal/gc/blkcache.d
@@ -0,0 +1,243 @@
+/**
+BlkInfo thread-local cache. Used for array appending in the conservative GC to avoid the lock when possible.
+
+Note: this used to be in rt.lifetime, but was moved here to allow GCs to take over array operations.
+*/
+module core.internal.gc.blkcache;
+
+import core.memory;
+import core.attribute;
+
+alias BlkInfo = GC.BlkInfo;
+alias BlkAttr = GC.BlkAttr;
+
+/**
+  cache for the lookup of the block info
+  */
+private enum N_CACHE_BLOCKS = 8;
+
+// note this is TLS, so no need to sync.
+BlkInfo *__blkcache_storage;
+
+static if (N_CACHE_BLOCKS == 1)
+{
+    version=single_cache;
+}
+else
+{
+    //version=simple_cache; // uncomment to test simple cache strategy
+    //version=random_cache; // uncomment to test random cache strategy
+
+    // ensure N_CACHE_BLOCKS is power of 2.
+    static assert(!((N_CACHE_BLOCKS - 1) & N_CACHE_BLOCKS));
+
+    version (random_cache)
+    {
+        int __nextRndNum = 0;
+    }
+    int __nextBlkIdx;
+}
+
+@property BlkInfo *__blkcache() nothrow
+{
+    if (!__blkcache_storage)
+    {
+        import core.stdc.stdlib;
+        import core.stdc.string;
+        import core.thread.threadbase;
+        auto tBase = ThreadBase.getThis();
+        if (tBase is null)
+            // if we don't have a thread object, this is a detached thread, and
+            // this won't be properly maintained by the GC.
+            return null;
+
+        // allocate the block cache for the first time
+        immutable size = BlkInfo.sizeof * N_CACHE_BLOCKS;
+        // use C alloc, because this may become a detached thread, and the GC
+        // would then clean up the cache without zeroing this pointer.
+        __blkcache_storage = cast(BlkInfo*) calloc(size, 1);
+        tBase.tlsGCData = __blkcache_storage;
+    }
+    return __blkcache_storage;
+}
+
+// free the allocation on thread exit.
+@standalone static ~this()
+{
+    if (__blkcache_storage)
+    {
+        import core.stdc.stdlib;
+        import core.thread.threadbase;
+        auto tBase = ThreadBase.getThis();
+        if (tBase !is null)
+            tBase.tlsGCData = null;
+        free(__blkcache_storage);
+        __blkcache_storage = null;
+    }
+}
+
+/**
+ * Indicates whether an address has been marked by the GC.
+ */
+enum IsMarked : int
+{
+         no, /// Address is not marked.
+        yes, /// Address is marked.
+    unknown, /// Address is not managed by the GC.
+}
+
+alias IsMarkedDg = IsMarked delegate(void* addr) nothrow; /// The isMarked callback function.
+
+// we expect this to be called with the lock in place
+void processGCMarks(void* data, scope IsMarkedDg isMarked) nothrow
+{
+    if (!data)
+        return;
+
+    auto cache = cast(BlkInfo*) data;
+    // called after the mark routine to eliminate block cache data when it
+    // might be ready to sweep
+
+    debug(PRINTF) printf("processing GC Marks, %x\n", cache);
+    debug(PRINTF) foreach (i; 0 .. N_CACHE_BLOCKS)
+    {
+        printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr);
+    }
+    auto cache_end = cache + N_CACHE_BLOCKS;
+    for (;cache < cache_end; ++cache)
+    {
+        if (cache.base != null && isMarked(cache.base) == IsMarked.no)
+        {
+            debug(PRINTF) printf("clearing cache entry at %x\n", cache.base);
+            cache.base = null; // clear that data.
+        }
+    }
+}
+
+unittest
+{
+    // Bugzilla 10701 - segfault in GC
+    ubyte[] result; result.length = 4096;
+    GC.free(result.ptr);
+    GC.collect();
+}
+
+/**
+  Get the cached block info of an interior pointer.  Returns null if the
+  interior pointer's block is not cached.
+
+  NOTE: The following note was not valid, but is retained for historical
+        purposes. The data cannot be cleared because the stack contains a
+        reference to the affected block (e.g. through `interior`). Therefore,
+        the element will not be collected, and the data will remain valid.
+
+  ORIGINAL: The base ptr in this struct can be cleared asynchronously by the GC,
+        so any use of the returned BlkInfo should copy it and then check the
+        base ptr of the copy before actually using it.
+  */
+BlkInfo *__getBlkInfo(void *interior) nothrow
+{
+    BlkInfo *ptr = __blkcache;
+    if (ptr is null)
+        // if for some reason we don't have a cache, return null.
+        return null;
+    version (single_cache)
+    {
+        if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
+            return ptr;
+        return null; // not in cache.
+    }
+    else version (simple_cache)
+    {
+        foreach (i; 0..N_CACHE_BLOCKS)
+        {
+            if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
+                return ptr;
+            ptr++;
+        }
+    }
+    else
+    {
+        // try to do a smart lookup, using __nextBlkIdx as the "head"
+        auto curi = ptr + __nextBlkIdx;
+        for (auto i = curi; i >= ptr; --i)
+        {
+            if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
+                return i;
+        }
+
+        for (auto i = ptr + N_CACHE_BLOCKS - 1; i > curi; --i)
+        {
+            if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
+                return i;
+        }
+    }
+    return null; // not in cache.
+}
+
+void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow
+{
+    auto cache = __blkcache;
+    if (cache is null)
+        // no cache to use.
+        return;
+
+    version (single_cache)
+    {
+        *cache = bi;
+        return;
+    }
+    else
+    {
+        version (simple_cache)
+        {
+            if (curpos)
+                *curpos = bi;
+            else
+            {
+                // note, this is a super-simple algorithm that does not care about
+                // most recently used.  It simply uses a round-robin technique to
+                // cache block info.  This means that the ordering of the cache
+                // doesn't mean anything.  Certain patterns of allocation may
+                // render the cache near-useless.
+                cache[__nextBlkIdx] = bi;
+                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
+            }
+        }
+        else version (random_cache)
+        {
+            // strategy: if the block currently is in the cache, move the
+            // current block index to the a random element and evict that
+            // element.
+            if (!curpos)
+            {
+                __nextBlkIdx = (__nextRndNum = 1664525 * __nextRndNum + 1013904223) & (N_CACHE_BLOCKS - 1);
+                curpos = cache + __nextBlkIdx;
+            }
+            else
+            {
+                __nextBlkIdx = curpos - cache;
+            }
+            *curpos = bi;
+        }
+        else
+        {
+            //
+            // strategy: If the block currently is in the cache, swap it with
+            // the head element.  Otherwise, move the head element up by one,
+            // and insert it there.
+            //
+            if (!curpos)
+            {
+                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
+                curpos = cache + __nextBlkIdx;
+            }
+            else if (curpos !is cache + __nextBlkIdx)
+            {
+                *curpos = cache[__nextBlkIdx];
+                curpos = cache + __nextBlkIdx;
+            }
+            *curpos = bi;
+        }
+    }
+}
diff --git a/libphobos/libdruntime/core/internal/gc/blockmeta.d b/libphobos/libdruntime/core/internal/gc/blockmeta.d
new file mode 100644
index 0000000000000000000000000000000000000000..c7dfeb6507529e9cf560ea0ec155e66b0760fa5e
--- /dev/null
+++ b/libphobos/libdruntime/core/internal/gc/blockmeta.d
@@ -0,0 +1,209 @@
+/**
+ Functions to manipulate metadata in-block.
+
+ functionality was moved from rt.lifetime
+ */
+module core.internal.gc.blockmeta;
+
+import core.memory;
+
+alias BlkInfo = GC.BlkInfo;
+alias BlkAttr = GC.BlkAttr;
+
+enum : size_t
+{
+    PAGESIZE = 4096,
+    BIGLENGTHMASK = ~(PAGESIZE - 1),
+    SMALLPAD = 1,
+    MEDPAD = ushort.sizeof,
+    LARGEPREFIX = 16, // 16 bytes padding at the front of the array
+    LARGEPAD = LARGEPREFIX + 1,
+    MAXSMALLSIZE = 256-SMALLPAD,
+    MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD
+}
+
+// size used to store the TypeInfo at the end of an allocation for structs that have a destructor
+size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
+{
+    if (ti && typeid(ti) is typeid(TypeInfo_Struct)) // avoid a complete dynamic type cast
+    {
+        auto sti = cast(TypeInfo_Struct)cast(void*)ti;
+        if (sti.xdtor)
+            return size_t.sizeof;
+    }
+    return 0;
+}
+
+/**
+  Set the allocated length of the array block.  This is called
+  any time an array is appended to or its length is set.
+
+  The allocated block looks like this for blocks < PAGESIZE:
+
+  |elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize|
+
+
+  The size of the allocated length at the end depends on the block size:
+
+  a block of 16 to 256 bytes has an 8-bit length.
+
+  a block with 512 to pagesize/2 bytes has a 16-bit length.
+
+  For blocks >= pagesize, the length is a size_t and is at the beginning of the
+  block.  The reason we have to do this is because the block can extend into
+  more pages, so we cannot trust the block length if it sits at the end of the
+  block, because it might have just been extended.  If we can prove in the
+  future that the block is unshared, we may be able to change this, but I'm not
+  sure it's important.
+
+  In order to do put the length at the front, we have to provide 16 bytes
+  buffer space in case the block has to be aligned properly.  In x86, certain
+  SSE instructions will only work if the data is 16-byte aligned.  In addition,
+  we need the sentinel byte to prevent accidental pointers to the next block.
+  Because of the extra overhead, we only do this for page size and above, where
+  the overhead is minimal compared to the block size.
+
+  So for those blocks, it looks like:
+
+  |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte|
+
+  where elem0 starts 16 bytes after the first byte.
+  */
+bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = ~0) pure nothrow
+{
+    size_t typeInfoSize = structTypeInfoSize(tinext);
+    return __setArrayAllocLengthImpl(info, newlength, isshared, tinext, oldlength, typeInfoSize);
+}
+
+// the impl function, used both above and in core.internal.array.utils
+bool __setArrayAllocLengthImpl(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength, size_t typeInfoSize) pure nothrow
+{
+    import core.atomic;
+
+    if (info.size <= 256)
+    {
+        import core.checkedint;
+
+        bool overflow;
+        auto newlength_padded = addu(newlength,
+                                     addu(SMALLPAD, typeInfoSize, overflow),
+                                     overflow);
+
+        if (newlength_padded > info.size || overflow)
+            // new size does not fit inside block
+            return false;
+
+        auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
+        if (oldlength != ~0)
+        {
+            if (isshared)
+            {
+                return cas(cast(shared)length, cast(ubyte)oldlength, cast(ubyte)newlength);
+            }
+            else
+            {
+                if (*length == cast(ubyte)oldlength)
+                    *length = cast(ubyte)newlength;
+                else
+                    return false;
+            }
+        }
+        else
+        {
+            // setting the initial length, no cas needed
+            *length = cast(ubyte)newlength;
+        }
+        if (typeInfoSize)
+        {
+            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
+            *typeInfo = cast() tinext;
+        }
+    }
+    else if (info.size < PAGESIZE)
+    {
+        if (newlength + MEDPAD + typeInfoSize > info.size)
+            // new size does not fit inside block
+            return false;
+        auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
+        if (oldlength != ~0)
+        {
+            if (isshared)
+            {
+                return cas(cast(shared)length, cast(ushort)oldlength, cast(ushort)newlength);
+            }
+            else
+            {
+                if (*length == oldlength)
+                    *length = cast(ushort)newlength;
+                else
+                    return false;
+            }
+        }
+        else
+        {
+            // setting the initial length, no cas needed
+            *length = cast(ushort)newlength;
+        }
+        if (typeInfoSize)
+        {
+            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
+            *typeInfo = cast() tinext;
+        }
+    }
+    else
+    {
+        if (newlength + LARGEPAD > info.size)
+            // new size does not fit inside block
+            return false;
+        auto length = cast(size_t *)(info.base);
+        if (oldlength != ~0)
+        {
+            if (isshared)
+            {
+                return cas(cast(shared)length, cast(size_t)oldlength, cast(size_t)newlength);
+            }
+            else
+            {
+                if (*length == oldlength)
+                    *length = newlength;
+                else
+                    return false;
+            }
+        }
+        else
+        {
+            // setting the initial length, no cas needed
+            *length = newlength;
+        }
+        if (typeInfoSize)
+        {
+            auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
+            *typeInfo = cast()tinext;
+        }
+    }
+    return true; // resize succeeded
+}
+
+/**
+  get the allocation size of the array for the given block (without padding or type info)
+  */
+size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow
+{
+    if (info.size <= 256)
+        return *cast(ubyte *)(info.base + info.size - structTypeInfoSize(tinext) - SMALLPAD);
+
+    if (info.size < PAGESIZE)
+        return *cast(ushort *)(info.base + info.size - structTypeInfoSize(tinext) - MEDPAD);
+
+    return *cast(size_t *)(info.base);
+}
+
+/**
+  get the padding required to allocate size bytes.  Note that the padding is
+  NOT included in the passed in size.  Therefore, do NOT call this function
+  with the size of an allocated block.
+  */
+size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted
+{
+    return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + structTypeInfoSize(tinext));
+}
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index dd6f92a8a7ab5fc41d59dab8cc507dae28adbdd7..149cc5d4cfbd2459d4d56f2903f9ec330f3dc90e 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -41,6 +41,7 @@ import core.gc.gcinterface;
 import core.internal.container.treap;
 import core.internal.spinlock;
 import core.internal.gc.pooltable;
+import core.internal.gc.blkcache;
 
 import cstdlib = core.stdc.stdlib : calloc, free, malloc, realloc;
 import core.stdc.string : memcpy, memset, memmove;
@@ -1426,7 +1427,7 @@ short[PAGESIZE / 16][Bins.B_NUMSMALL + 1] calcBinBase()
 
     foreach (i, size; binsize)
     {
-        short end = (PAGESIZE / size) * size;
+        short end = cast(short) ((PAGESIZE / size) * size);
         short bsz = size / 16;
         foreach (off; 0..PAGESIZE/16)
         {
@@ -2873,7 +2874,7 @@ struct Gcx
                 markProcPid = 0;
                 // process GC marks then sweep
                 thread_suspendAll();
-                thread_processGCMarks(&isMarked);
+                thread_processTLSGCData(&clearBlkCacheData);
                 thread_resumeAll();
                 break;
             case ChildStatus.running:
@@ -3108,7 +3109,7 @@ Lmark:
                     markAll!(markConservative!false)();
             }
 
-            thread_processGCMarks(&isMarked);
+            thread_processTLSGCData(&clearBlkCacheData);
             thread_resumeAll();
             isFinal = false;
         }
@@ -3161,13 +3162,27 @@ Lmark:
         return freedPages;
     }
 
+    /**
+     * Clear the block cache data if it exists, given the data which is the
+     * block info cache.
+     *
+     * Warning! This should only be called while the world is stopped inside
+     * the fullcollect function after all live objects have been marked, but
+     * before sweeping.
+     */
+    void *clearBlkCacheData(void* data) scope nothrow
+    {
+        processGCMarks(data, &isMarked);
+        return data;
+    }
+
     /**
      * Returns true if the addr lies within a marked block.
      *
      * Warning! This should only be called while the world is stopped inside
      * the fullcollect function after all live objects have been marked, but before sweeping.
      */
-    int isMarked(void *addr) scope nothrow
+    IsMarked isMarked(void *addr) scope nothrow
     {
         // first, we find the Pool this block is in, then check to see if the
         // mark bit is clear.
diff --git a/libphobos/libdruntime/core/internal/traits.d b/libphobos/libdruntime/core/internal/traits.d
index f0d9ebc9a81362b41005ea76f7607373c377698e..02898082e402a6010f9e8e8e05a4e40e6754a4d2 100644
--- a/libphobos/libdruntime/core/internal/traits.d
+++ b/libphobos/libdruntime/core/internal/traits.d
@@ -267,8 +267,12 @@ template hasElaborateDestructor(S)
     }
     else static if (is(S == struct))
     {
-        enum hasElaborateDestructor = __traits(hasMember, S, "__dtor")
-            || anySatisfy!(.hasElaborateDestructor, Fields!S);
+        // Once https://issues.dlang.org/show_bug.cgi?id=24865 is fixed, then
+        // this should be the implementation, but until that's fixed, we need the
+        // uncommented code.
+        // enum hasElaborateDestructor = __traits(hasMember, S, "__xdtor");
+
+        enum hasElaborateDestructor = hasDtor([__traits(allMembers, S)]);
     }
     else
     {
@@ -276,6 +280,64 @@ template hasElaborateDestructor(S)
     }
 }
 
+private bool hasDtor(string[] members)
+{
+    foreach (name; members)
+    {
+        if (name == "__xdtor")
+            return true;
+    }
+
+    return false;
+}
+
+@safe unittest
+{
+    static struct NoDestructor {}
+    static assert(!hasElaborateDestructor!NoDestructor);
+    static assert(!hasElaborateDestructor!(NoDestructor[42]));
+    static assert(!hasElaborateDestructor!(NoDestructor[0]));
+    static assert(!hasElaborateDestructor!(NoDestructor[]));
+
+    static struct HasDestructor { ~this() {} }
+    static assert( hasElaborateDestructor!HasDestructor);
+    static assert( hasElaborateDestructor!(HasDestructor[42]));
+    static assert(!hasElaborateDestructor!(HasDestructor[0]));
+    static assert(!hasElaborateDestructor!(HasDestructor[]));
+
+    static struct HasDestructor2 { HasDestructor s; }
+    static assert( hasElaborateDestructor!HasDestructor2);
+    static assert( hasElaborateDestructor!(HasDestructor2[42]));
+    static assert(!hasElaborateDestructor!(HasDestructor2[0]));
+    static assert(!hasElaborateDestructor!(HasDestructor2[]));
+
+    static class HasFinalizer { ~this() {} }
+    static assert(!hasElaborateDestructor!HasFinalizer);
+
+    static struct HasUnion { union { HasDestructor s; } }
+    static assert(!hasElaborateDestructor!HasUnion);
+    static assert(!hasElaborateDestructor!(HasUnion[42]));
+    static assert(!hasElaborateDestructor!(HasUnion[0]));
+    static assert(!hasElaborateDestructor!(HasUnion[]));
+
+    static assert(!hasElaborateDestructor!int);
+    static assert(!hasElaborateDestructor!(int[0]));
+    static assert(!hasElaborateDestructor!(int[42]));
+    static assert(!hasElaborateDestructor!(int[]));
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=24865
+@safe unittest
+{
+    static struct S2 { ~this() {} }
+    static struct S3 { S2 field; }
+    static struct S6 { S3[0] field; }
+
+    static assert( hasElaborateDestructor!S2);
+    static assert( hasElaborateDestructor!S3);
+    static assert(!hasElaborateDestructor!S6);
+}
+
 // std.traits.hasElaborateCopyDestructor
 template hasElaborateCopyConstructor(S)
 {
@@ -302,7 +364,7 @@ template hasElaborateCopyConstructor(S)
         this(int x, int y) {}
     }
 
-    static assert(hasElaborateCopyConstructor!S);
+    static assert( hasElaborateCopyConstructor!S);
     static assert(!hasElaborateCopyConstructor!(S[0][1]));
 
     static struct S2
@@ -320,7 +382,11 @@ template hasElaborateCopyConstructor(S)
         this(int x, int y) {}
     }
 
-    static assert(hasElaborateCopyConstructor!S3);
+    static assert( hasElaborateCopyConstructor!S3);
+
+    static struct S4 { union { S s; } }
+
+    static assert(!hasElaborateCopyConstructor!S4);
 }
 
 template hasElaborateAssign(S)
@@ -332,8 +398,7 @@ template hasElaborateAssign(S)
     else static if (is(S == struct))
     {
         enum hasElaborateAssign = is(typeof(S.init.opAssign(rvalueOf!S))) ||
-                                  is(typeof(S.init.opAssign(lvalueOf!S))) ||
-                                  anySatisfy!(.hasElaborateAssign, Fields!S);
+                                  is(typeof(S.init.opAssign(lvalueOf!S)));
     }
     else
     {
@@ -341,17 +406,148 @@ template hasElaborateAssign(S)
     }
 }
 
+unittest
+{
+    {
+        static struct S {}
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { int i; }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { void opAssign(S) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { void opAssign(ref S) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { void opAssign(int) {} }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { this(this) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    // https://issues.dlang.org/show_bug.cgi?id=24834
+    /+
+    {
+        static struct S { this(ref S) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    +/
+    {
+        static struct S { ~this() {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct S { @disable void opAssign(S); }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member {}
+        static struct S { Member member; }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member { void opAssign(Member) {} }
+        static struct S { Member member; }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member {}
+        static struct S { Member member; void opAssign(S) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member { @disable void opAssign(Member); }
+        static struct S { Member member; }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member { @disable void opAssign(Member); }
+        static struct S { Member member; void opAssign(S) {} }
+        static assert( hasElaborateAssign!S);
+        static assert( hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member { void opAssign(Member) {} }
+        static struct S { Member member; @disable void opAssign(S); }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+    {
+        static struct Member { void opAssign(Member) {} }
+        static struct S { union { Member member; } }
+        static assert(!hasElaborateAssign!S);
+        static assert(!hasElaborateAssign!(S[10]));
+        static assert(!hasElaborateAssign!(S[0]));
+        static assert(!hasElaborateAssign!(S[]));
+    }
+
+    static assert(!hasElaborateAssign!int);
+    static assert(!hasElaborateAssign!(string[]));
+    static assert(!hasElaborateAssign!Object);
+}
+
 template hasIndirections(T)
 {
     static if (is(T == struct) || is(T == union))
         enum hasIndirections = anySatisfy!(.hasIndirections, typeof(T.tupleof));
+    else static if (__traits(isAssociativeArray, T) || is(T == class) || is(T == interface))
+        enum hasIndirections = true;
     else static if (is(T == E[N], E, size_t N))
         enum hasIndirections = T.sizeof && is(E == void) ? true : hasIndirections!(BaseElemOf!E);
     else static if (isFunctionPointer!T)
         enum hasIndirections = false;
     else
-        enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T ||
-            __traits(isAssociativeArray, T) || is (T == class) || is(T == interface);
+        enum hasIndirections = isPointer!T || isDelegate!T || isDynamicArray!T;
 }
 
 template hasUnsharedIndirections(T)
diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d
index 7010d2ad3b08361fbfce5fa8520d6463f58fa4d4..84ffdde7a2cbdb45802778cf324aa31922962665 100644
--- a/libphobos/libdruntime/core/lifetime.d
+++ b/libphobos/libdruntime/core/lifetime.d
@@ -2739,8 +2739,11 @@ if (is(T == class))
     auto init = __traits(initSymbol, T);
     void* p;
 
-    static if (__traits(getLinkage, T) == "Windows")
+    static if (__traits(isCOMClass, T))
     {
+        // If this is a COM class we allocate it using malloc.
+        // This allows the reference counting to outlive the reference known about by the GC.
+
         p = pureMalloc(init.length);
         if (!p)
             onOutOfMemoryError();
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index 001c31596784187fefc119f659e68c5a1898173c..63a3c2e04c8035bb30f4df23adf94001cf599173 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -100,6 +100,10 @@
  * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
  * Authors:   Sean Kelly, Alex Rønne Petersen
  * Source:    $(DRUNTIMESRC core/_memory.d)
+ * Macros:
+ * WARN_UNINITIALIZED=$(RED Warning):
+ * $1 will be uninitialized, and may happen to hold pointers to GC memory.
+ * Consider zeroing out any uninitialized bytes which won't be immediately written to.
  */
 
 module core.memory;
@@ -400,7 +404,7 @@ extern(D):
      *  a = A bit field containing any bits to set for this memory block.
      *
      * Returns:
-     *  The result of a call to getAttr after the specified bits have been
+     *  The result of a call to $(LREF getAttr) after the specified bits have been
      *  set.
      */
     static uint setAttr( const scope void* p, uint a ) nothrow
@@ -427,7 +431,7 @@ extern(D):
      *  a = A bit field containing any bits to clear for this memory block.
      *
      * Returns:
-     *  The result of a call to getAttr after the specified bits have been
+     *  The result of a call to $(LREF getAttr) after the specified bits have been
      *  cleared.
      */
     static uint clrAttr( const scope void* p, uint a ) nothrow
@@ -461,6 +465,8 @@ extern(C):
      *  A reference to the allocated memory or null if insufficient memory
      *  is available.
      *
+     * $(WARN_UNINITIALIZED Allocated memory)
+     *
      * Throws:
      *  OutOfMemoryError on allocation failure.
      */
@@ -472,7 +478,7 @@ extern(C):
 
     /**
      * Requests an aligned block of managed memory from the garbage collector.
-     * This memory may be deleted at will with a call to free, or it may be
+     * This memory may be deleted at will with a call to $(LREF free), or it may be
      * discarded and cleaned up automatically during a collection run.  If
      * allocation fails, this function will call onOutOfMemory which is
      * expected to throw an OutOfMemoryError.
@@ -487,6 +493,8 @@ extern(C):
      *  Information regarding the allocated memory block or BlkInfo.init on
      *  error.
      *
+     * $(WARN_UNINITIALIZED Allocated memory)
+     *
      * Throws:
      *  OutOfMemoryError on allocation failure.
      */
@@ -564,6 +572,8 @@ extern(C):
      *  zero or the pointer does not point to the base of an GC allocated
      *  memory block.
      *
+     * $(WARN_UNINITIALIZED Any extra bytes past the initial size)
+     *
      * Throws:
      *  `OutOfMemoryError` on allocation failure.
      */
@@ -608,6 +618,8 @@ extern(C):
      *  The size in bytes of the extended memory block referenced by p or zero
      *  if no extension occurred.
      *
+     * $(WARN_UNINITIALIZED Any extension bytes)
+     *
      * Note:
      *  Extend may also be used to extend slices (or memory blocks with
      *  $(LREF APPENDABLE) info). However, use the return value only
@@ -669,7 +681,7 @@ extern(C):
      * If p references memory not originally allocated by this garbage
      * collector, if p points to the interior of a memory block, or if this
      * method is called from a finalizer, no action will be taken.  The block
-     * will not be finalized regardless of whether the FINALIZE attribute is
+     * will not be finalized regardless of whether the $(LREF FINALIZE) attribute is
      * set.  If finalization is desired, call $(REF1 destroy, object) prior to `GC.free`.
      *
      * Params:
@@ -707,7 +719,7 @@ extern(D):
 
     /**
      * Returns the true size of the memory block referenced by p.  This value
-     * represents the maximum number of bytes for which a call to realloc may
+     * represents the maximum number of bytes for which a call to $(LREF realloc) may
      * resize the existing block in place.  If p references memory not
      * originally allocated by this garbage collector, points to the interior
      * of a memory block, or if p is null, zero will be returned.
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index cf93094937c0928e18d6951f1907decbeec2d293..2379f7925e4175c7e065bab16b116e3c15545845 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -1237,7 +1237,7 @@ private extern (D) ThreadBase attachThread(ThreadBase _thisThread) @nogc nothrow
         atomicStore!(MemoryOrder.raw)(thisThread.toThread.m_isRunning, true);
     }
     thisThread.m_isDaemon = true;
-    thisThread.tlsGCdataInit();
+    thisThread.tlsRTdataInit();
     Thread.setThis( thisThread );
 
     version (Darwin)
@@ -1312,7 +1312,7 @@ version (Windows)
         if ( addr == GetCurrentThreadId() )
         {
             thisThread.m_hndl = GetCurrentThreadHandle();
-            thisThread.tlsGCdataInit();
+            thisThread.tlsRTdataInit();
             Thread.setThis( thisThread );
         }
         else
@@ -1320,7 +1320,7 @@ version (Windows)
             thisThread.m_hndl = OpenThreadHandle( addr );
             impersonate_thread(addr,
             {
-                thisThread.tlsGCdataInit();
+                thisThread.tlsRTdataInit();
                 Thread.setThis( thisThread );
             });
         }
diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d
index cb13e9ac0a0a585b534e4e8f50fe141f295b3218..f3854076b0bfb3b2dafcc0cc0df95c6c2b39c765 100644
--- a/libphobos/libdruntime/core/thread/threadbase.d
+++ b/libphobos/libdruntime/core/thread/threadbase.d
@@ -32,9 +32,6 @@ private
     alias ScanDg = void delegate(void* pstart, void* pend) nothrow;
     alias rt_tlsgc_scan =
         externDFunc!("rt.tlsgc.scan", void function(void*, scope ScanDg) nothrow);
-
-    alias rt_tlsgc_processGCMarks =
-        externDFunc!("rt.tlsgc.processGCMarks", void function(void*, scope IsMarkedDg) nothrow);
 }
 
 
@@ -131,9 +128,14 @@ class ThreadBase
         return (no_context || not_registered);
     }
 
-    package void tlsGCdataInit() nothrow @nogc
+    ref void* tlsGCData() nothrow @nogc
     {
-        m_tlsgcdata = rt_tlsgc_init();
+        return m_tlsgcdata;
+    }
+
+    package void tlsRTdataInit() nothrow @nogc
+    {
+        m_tlsrtdata = rt_tlsgc_init();
     }
 
     package void initDataStorage() nothrow
@@ -142,18 +144,18 @@ class ThreadBase
 
         m_main.bstack = getStackBottom();
         m_main.tstack = m_main.bstack;
-        tlsGCdataInit();
+        tlsRTdataInit();
     }
 
     package void destroyDataStorage() nothrow @nogc
     {
-        rt_tlsgc_destroy(m_tlsgcdata);
-        m_tlsgcdata = null;
+        rt_tlsgc_destroy(m_tlsrtdata);
+        m_tlsrtdata = null;
     }
 
     package void destroyDataStorageIfAvail() nothrow @nogc
     {
-        if (m_tlsgcdata)
+        if (m_tlsrtdata)
             destroyDataStorage();
     }
 
@@ -477,6 +479,7 @@ package(core.thread):
     StackContext*       m_curr;
     bool                m_lock;
     private void*       m_tlsgcdata;
+    private void*       m_tlsrtdata;
 
     ///////////////////////////////////////////////////////////////////////////
     // Thread Context and GC Scanning Support
@@ -1112,8 +1115,8 @@ private void scanAllTypeImpl(scope ScanAllThreadsTypeFn scan, void* curStackTop)
             scanWindowsOnly(scan, t);
         }
 
-        if (t.m_tlsgcdata !is null)
-            rt_tlsgc_scan(t.m_tlsgcdata, (p1, p2) => scan(ScanType.tls, p1, p2));
+        if (t.m_tlsrtdata !is null)
+            rt_tlsgc_scan(t.m_tlsrtdata, (p1, p2) => scan(ScanType.tls, p1, p2));
     }
 }
 
@@ -1163,43 +1166,15 @@ package void onThreadError(string msg) nothrow @nogc
 }
 
 
-/**
- * Indicates whether an address has been marked by the GC.
- */
-enum IsMarked : int
-{
-         no, /// Address is not marked.
-        yes, /// Address is marked.
-    unknown, /// Address is not managed by the GC.
-}
-
-alias IsMarkedDg = int delegate(void* addr) nothrow; /// The isMarked callback function.
+// GC-specific processing of TLSGC data.
+alias ProcessTLSGCDataDg = void* delegate(void* data) nothrow;
 
-/**
- * This routine allows the runtime to process any special per-thread handling
- * for the GC.  This is needed for taking into account any memory that is
- * referenced by non-scanned pointers but is about to be freed.  That currently
- * means the array append cache.
- *
- * Params:
- *  isMarked = The function used to check if $(D addr) is marked.
- *
- * In:
- *  This routine must be called just prior to resuming all threads.
- */
-extern(C) void thread_processGCMarks(scope IsMarkedDg isMarked) nothrow
+void thread_processTLSGCData(ProcessTLSGCDataDg dg) nothrow
 {
     for (ThreadBase t = ThreadBase.sm_tbeg; t; t = t.next)
-    {
-        /* Can be null if collection was triggered between adding a
-         * thread and calling rt_tlsgc_init.
-         */
-        if (t.m_tlsgcdata !is null)
-            rt_tlsgc_processGCMarks(t.m_tlsgcdata, isMarked);
-    }
+        t.m_tlsgcdata = dg(t.m_tlsgcdata);
 }
 
-
 /**
  * Returns the stack top of the currently active stack within the calling
  * thread.
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 1de993c0bff97501cb5efd86d669889ce5eae641..86f5f820cc024ee43d880f2e088cbcf5cd2f2e3d 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -15,6 +15,8 @@ module rt.lifetime;
 import core.attribute : weak;
 import core.internal.array.utils : __arrayStart, __arrayClearPad;
 import core.memory;
+import core.internal.gc.blkcache;
+import core.internal.gc.blockmeta;
 debug(PRINTF) import core.stdc.stdio;
 static import rt.tlsgc;
 
@@ -28,17 +30,6 @@ private
 
     extern (C) void _d_monitordelete(Object h, bool det);
 
-    enum : size_t
-    {
-        PAGESIZE = 4096,
-        BIGLENGTHMASK = ~(PAGESIZE - 1),
-        SMALLPAD = 1,
-        MEDPAD = ushort.sizeof,
-        LARGEPREFIX = 16, // 16 bytes padding at the front of the array
-        LARGEPAD = LARGEPREFIX + 1,
-        MAXSMALLSIZE = 256-SMALLPAD,
-        MAXMEDSIZE = (PAGESIZE / 2) - MEDPAD
-    }
 }
 
 // Now-removed symbol, kept around for ABI
@@ -211,191 +202,6 @@ inout(TypeInfo) unqualify(return scope inout(TypeInfo) cti) pure nothrow @nogc
     return ti;
 }
 
-// size used to store the TypeInfo at the end of an allocation for structs that have a destructor
-size_t structTypeInfoSize(const TypeInfo ti) pure nothrow @nogc
-{
-    if (ti && typeid(ti) is typeid(TypeInfo_Struct)) // avoid a complete dynamic type cast
-    {
-        auto sti = cast(TypeInfo_Struct)cast(void*)ti;
-        if (sti.xdtor)
-            return size_t.sizeof;
-    }
-    return 0;
-}
-
-/** dummy class used to lock for shared array appending */
-private class ArrayAllocLengthLock
-{}
-
-/**
-  Set the allocated length of the array block.  This is called
-  any time an array is appended to or its length is set.
-
-  The allocated block looks like this for blocks < PAGESIZE:
-
-  |elem0|elem1|elem2|...|elemN-1|emptyspace|N*elemsize|
-
-
-  The size of the allocated length at the end depends on the block size:
-
-  a block of 16 to 256 bytes has an 8-bit length.
-
-  a block with 512 to pagesize/2 bytes has a 16-bit length.
-
-  For blocks >= pagesize, the length is a size_t and is at the beginning of the
-  block.  The reason we have to do this is because the block can extend into
-  more pages, so we cannot trust the block length if it sits at the end of the
-  block, because it might have just been extended.  If we can prove in the
-  future that the block is unshared, we may be able to change this, but I'm not
-  sure it's important.
-
-  In order to do put the length at the front, we have to provide 16 bytes
-  buffer space in case the block has to be aligned properly.  In x86, certain
-  SSE instructions will only work if the data is 16-byte aligned.  In addition,
-  we need the sentinel byte to prevent accidental pointers to the next block.
-  Because of the extra overhead, we only do this for page size and above, where
-  the overhead is minimal compared to the block size.
-
-  So for those blocks, it looks like:
-
-  |N*elemsize|padding|elem0|elem1|...|elemN-1|emptyspace|sentinelbyte|
-
-  where elem0 starts 16 bytes after the first byte.
-  */
-bool __setArrayAllocLength(ref BlkInfo info, size_t newlength, bool isshared, const TypeInfo tinext, size_t oldlength = ~0) pure nothrow
-{
-    import core.atomic;
-
-    size_t typeInfoSize = structTypeInfoSize(tinext);
-
-    if (info.size <= 256)
-    {
-        import core.checkedint;
-
-        bool overflow;
-        auto newlength_padded = addu(newlength,
-                                     addu(SMALLPAD, typeInfoSize, overflow),
-                                     overflow);
-
-        if (newlength_padded > info.size || overflow)
-            // new size does not fit inside block
-            return false;
-
-        auto length = cast(ubyte *)(info.base + info.size - typeInfoSize - SMALLPAD);
-        if (oldlength != ~0)
-        {
-            if (isshared)
-            {
-                return cas(cast(shared)length, cast(ubyte)oldlength, cast(ubyte)newlength);
-            }
-            else
-            {
-                if (*length == cast(ubyte)oldlength)
-                    *length = cast(ubyte)newlength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = cast(ubyte)newlength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
-            *typeInfo = cast() tinext;
-        }
-    }
-    else if (info.size < PAGESIZE)
-    {
-        if (newlength + MEDPAD + typeInfoSize > info.size)
-            // new size does not fit inside block
-            return false;
-        auto length = cast(ushort *)(info.base + info.size - typeInfoSize - MEDPAD);
-        if (oldlength != ~0)
-        {
-            if (isshared)
-            {
-                return cas(cast(shared)length, cast(ushort)oldlength, cast(ushort)newlength);
-            }
-            else
-            {
-                if (*length == oldlength)
-                    *length = cast(ushort)newlength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = cast(ushort)newlength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + info.size - size_t.sizeof);
-            *typeInfo = cast() tinext;
-        }
-    }
-    else
-    {
-        if (newlength + LARGEPAD > info.size)
-            // new size does not fit inside block
-            return false;
-        auto length = cast(size_t *)(info.base);
-        if (oldlength != ~0)
-        {
-            if (isshared)
-            {
-                return cas(cast(shared)length, cast(size_t)oldlength, cast(size_t)newlength);
-            }
-            else
-            {
-                if (*length == oldlength)
-                    *length = newlength;
-                else
-                    return false;
-            }
-        }
-        else
-        {
-            // setting the initial length, no cas needed
-            *length = newlength;
-        }
-        if (typeInfoSize)
-        {
-            auto typeInfo = cast(TypeInfo*)(info.base + size_t.sizeof);
-            *typeInfo = cast()tinext;
-        }
-    }
-    return true; // resize succeeded
-}
-
-/**
-  get the allocation size of the array for the given block (without padding or type info)
-  */
-private size_t __arrayAllocLength(ref BlkInfo info, const TypeInfo tinext) pure nothrow
-{
-    if (info.size <= 256)
-        return *cast(ubyte *)(info.base + info.size - structTypeInfoSize(tinext) - SMALLPAD);
-
-    if (info.size < PAGESIZE)
-        return *cast(ushort *)(info.base + info.size - structTypeInfoSize(tinext) - MEDPAD);
-
-    return *cast(size_t *)(info.base);
-}
-
-/**
-  get the padding required to allocate size bytes.  Note that the padding is
-  NOT included in the passed in size.  Therefore, do NOT call this function
-  with the size of an allocated block.
-  */
-private size_t __arrayPad(size_t size, const TypeInfo tinext) nothrow pure @trusted
-{
-    return size > MAXMEDSIZE ? LARGEPAD : ((size > MAXSMALLSIZE ? MEDPAD : SMALLPAD) + structTypeInfoSize(tinext));
-}
-
 /**
   allocate an array memory block by applying the proper padding and
   assigning block attributes if not inherited from the existing block
@@ -442,206 +248,6 @@ private BlkInfo __arrayAlloc(size_t arrsize, ref BlkInfo info, const scope TypeI
     return bi;
 }
 
-/**
-  cache for the lookup of the block info
-  */
-private enum N_CACHE_BLOCKS=8;
-
-// note this is TLS, so no need to sync.
-BlkInfo *__blkcache_storage;
-
-static if (N_CACHE_BLOCKS==1)
-{
-    version=single_cache;
-}
-else
-{
-    //version=simple_cache; // uncomment to test simple cache strategy
-    //version=random_cache; // uncomment to test random cache strategy
-
-    // ensure N_CACHE_BLOCKS is power of 2.
-    static assert(!((N_CACHE_BLOCKS - 1) & N_CACHE_BLOCKS));
-
-    version (random_cache)
-    {
-        int __nextRndNum = 0;
-    }
-    int __nextBlkIdx;
-}
-
-@property BlkInfo *__blkcache() nothrow
-{
-    if (!__blkcache_storage)
-    {
-        import core.stdc.stdlib;
-        import core.stdc.string;
-        // allocate the block cache for the first time
-        immutable size = BlkInfo.sizeof * N_CACHE_BLOCKS;
-        __blkcache_storage = cast(BlkInfo *)malloc(size);
-        memset(__blkcache_storage, 0, size);
-    }
-    return __blkcache_storage;
-}
-
-// called when thread is exiting.
-static ~this()
-{
-    // free the blkcache
-    if (__blkcache_storage)
-    {
-        import core.stdc.stdlib;
-        free(__blkcache_storage);
-        __blkcache_storage = null;
-    }
-}
-
-
-// we expect this to be called with the lock in place
-void processGCMarks(BlkInfo* cache, scope rt.tlsgc.IsMarkedDg isMarked) nothrow
-{
-    // called after the mark routine to eliminate block cache data when it
-    // might be ready to sweep
-
-    debug(PRINTF) printf("processing GC Marks, %x\n", cache);
-    if (cache)
-    {
-        debug(PRINTF) foreach (i; 0 .. N_CACHE_BLOCKS)
-        {
-            printf("cache entry %d has base ptr %x\tsize %d\tflags %x\n", i, cache[i].base, cache[i].size, cache[i].attr);
-        }
-        auto cache_end = cache + N_CACHE_BLOCKS;
-        for (;cache < cache_end; ++cache)
-        {
-            if (cache.base != null && !isMarked(cache.base))
-            {
-                debug(PRINTF) printf("clearing cache entry at %x\n", cache.base);
-                cache.base = null; // clear that data.
-            }
-        }
-    }
-}
-
-unittest
-{
-    // Bugzilla 10701 - segfault in GC
-    ubyte[] result; result.length = 4096;
-    GC.free(result.ptr);
-    GC.collect();
-}
-
-/**
-  Get the cached block info of an interior pointer.  Returns null if the
-  interior pointer's block is not cached.
-
-  NOTE: The base ptr in this struct can be cleared asynchronously by the GC,
-        so any use of the returned BlkInfo should copy it and then check the
-        base ptr of the copy before actually using it.
-
-  TODO: Change this function so the caller doesn't have to be aware of this
-        issue.  Either return by value and expect the caller to always check
-        the base ptr as an indication of whether the struct is valid, or set
-        the BlkInfo as a side-effect and return a bool to indicate success.
-  */
-BlkInfo *__getBlkInfo(void *interior) nothrow
-{
-    BlkInfo *ptr = __blkcache;
-    version (single_cache)
-    {
-        if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
-            return ptr;
-        return null; // not in cache.
-    }
-    else version (simple_cache)
-    {
-        foreach (i; 0..N_CACHE_BLOCKS)
-        {
-            if (ptr.base && ptr.base <= interior && (interior - ptr.base) < ptr.size)
-                return ptr;
-            ptr++;
-        }
-    }
-    else
-    {
-        // try to do a smart lookup, using __nextBlkIdx as the "head"
-        auto curi = ptr + __nextBlkIdx;
-        for (auto i = curi; i >= ptr; --i)
-        {
-            if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
-                return i;
-        }
-
-        for (auto i = ptr + N_CACHE_BLOCKS - 1; i > curi; --i)
-        {
-            if (i.base && i.base <= interior && cast(size_t)(interior - i.base) < i.size)
-                return i;
-        }
-    }
-    return null; // not in cache.
-}
-
-void __insertBlkInfoCache(BlkInfo bi, BlkInfo *curpos) nothrow
-{
-    version (single_cache)
-    {
-        *__blkcache = bi;
-    }
-    else
-    {
-        version (simple_cache)
-        {
-            if (curpos)
-                *curpos = bi;
-            else
-            {
-                // note, this is a super-simple algorithm that does not care about
-                // most recently used.  It simply uses a round-robin technique to
-                // cache block info.  This means that the ordering of the cache
-                // doesn't mean anything.  Certain patterns of allocation may
-                // render the cache near-useless.
-                __blkcache[__nextBlkIdx] = bi;
-                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
-            }
-        }
-        else version (random_cache)
-        {
-            // strategy: if the block currently is in the cache, move the
-            // current block index to the a random element and evict that
-            // element.
-            auto cache = __blkcache;
-            if (!curpos)
-            {
-                __nextBlkIdx = (__nextRndNum = 1664525 * __nextRndNum + 1013904223) & (N_CACHE_BLOCKS - 1);
-                curpos = cache + __nextBlkIdx;
-            }
-            else
-            {
-                __nextBlkIdx = curpos - cache;
-            }
-            *curpos = bi;
-        }
-        else
-        {
-            //
-            // strategy: If the block currently is in the cache, swap it with
-            // the head element.  Otherwise, move the head element up by one,
-            // and insert it there.
-            //
-            auto cache = __blkcache;
-            if (!curpos)
-            {
-                __nextBlkIdx = (__nextBlkIdx+1) & (N_CACHE_BLOCKS - 1);
-                curpos = cache + __nextBlkIdx;
-            }
-            else if (curpos !is cache + __nextBlkIdx)
-            {
-                *curpos = cache[__nextBlkIdx];
-                curpos = cache + __nextBlkIdx;
-            }
-            *curpos = bi;
-        }
-    }
-}
-
 /**
 Shrink the "allocated" length of an array to be the exact size of the array.
 
diff --git a/libphobos/libdruntime/rt/tlsgc.d b/libphobos/libdruntime/rt/tlsgc.d
index b13a1b319cf0678181333a24b9e329b033acc68c..f1dcc598d7964971fa8d9552659debf6a5307aae 100644
--- a/libphobos/libdruntime/rt/tlsgc.d
+++ b/libphobos/libdruntime/rt/tlsgc.d
@@ -23,7 +23,6 @@ static import rt.lifetime, rt.sections;
 struct Data
 {
     typeof(rt.sections.initTLSRanges()) tlsRanges;
-    rt.lifetime.BlkInfo** blockInfoCache;
 }
 
 /**
@@ -39,8 +38,6 @@ void* init() nothrow @nogc
 
     // do module specific initialization
     data.tlsRanges = rt.sections.initTLSRanges();
-    data.blockInfoCache = &rt.lifetime.__blkcache_storage;
-
     return data;
 }
 
@@ -67,16 +64,3 @@ void scan(void* data, scope ScanDg dg) nothrow
     // do module specific marking
     rt.sections.scanTLSRanges((cast(Data*)data).tlsRanges, dg);
 }
-
-alias int delegate(void* addr) nothrow IsMarkedDg;
-
-/**
- * GC sweep hook, called FOR each thread. Can be used to free
- * additional thread local memory or associated data structures. Note
- * that only memory allocated from the GC can have marks.
- */
-void processGCMarks(void* data, scope IsMarkedDg dg) nothrow
-{
-    // do module specific sweeping
-    rt.lifetime.processGCMarks(*(cast(Data*)data).blockInfoCache, dg);
-}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index f7c522322632c6a1473017aafe90b52be287e178..0522cf85a3a8ba8645a49bf4185c0c050e9fde21 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-2a730adc07b0a708b31dd8e592f56df4adbaf4be
+dbc09d8230f0e273af8a78546e5431a7783478b5
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index 42a9df518c94f0ca2af47b735f253412a805ca97..b7119d24b608ccca21f5dc46e34ec34d686eb82d 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -3735,6 +3735,47 @@ if (isInputRange!Range && !isInfinite!Range &&
     assert(arr.minElement!"a.val".val == 0);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24827
+@safe unittest
+{
+    static struct S
+    {
+        int i;
+        bool destroyed;
+
+        this(int i) @safe
+        {
+            this.i = i;
+        }
+
+        ~this() @safe
+        {
+            destroyed = true;
+        }
+
+        bool opEquals()(auto ref S rhs)
+        {
+            return this.i == rhs.i;
+        }
+
+        int opCmp()(auto ref S rhs)
+        {
+            if (this.i < rhs.i)
+                return -1;
+
+            return this.i == rhs.i ? 0 : 1;
+        }
+
+        @safe invariant
+        {
+            assert(!destroyed);
+        }
+    }
+
+    auto arr = [S(19), S(2), S(145), S(7)];
+    assert(minElement(arr) == S(2));
+}
+
 /**
 Iterates the passed range and returns the maximal element.
 A custom mapping function can be passed to `map`.
@@ -3888,6 +3929,47 @@ if (isInputRange!Range && !isInfinite!Range &&
     assert(arr[0].getI == 2);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24827
+@safe unittest
+{
+    static struct S
+    {
+        int i;
+        bool destroyed;
+
+        this(int i) @safe
+        {
+            this.i = i;
+        }
+
+        ~this() @safe
+        {
+            destroyed = true;
+        }
+
+        bool opEquals()(auto ref S rhs)
+        {
+            return this.i == rhs.i;
+        }
+
+        int opCmp()(auto ref S rhs)
+        {
+            if (this.i < rhs.i)
+                return -1;
+
+            return this.i == rhs.i ? 0 : 1;
+        }
+
+        @safe invariant
+        {
+            assert(!destroyed);
+        }
+    }
+
+    auto arr = [S(19), S(2), S(145), S(7)];
+    assert(maxElement(arr) == S(145));
+}
+
 // minPos
 /**
 Computes a subrange of `range` starting at the first occurrence of `range`'s
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index acd5311c4d22cbe71268a166e7f9f3354a9b3b1f..3313dbb28d4492900bec0b56061dfad86a916c11 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -3639,6 +3639,7 @@ if (isDynamicArray!A)
         }
         else
         {
+            import core.stdc.string : memcpy, memset;
             // Time to reallocate.
             // We need to almost duplicate what's in druntime, except we
             // have better access to the capacity field.
@@ -3650,6 +3651,15 @@ if (isDynamicArray!A)
                 if (u)
                 {
                     // extend worked, update the capacity
+                    // if the type has indirections, we need to zero any new
+                    // data that we requested, as the existing data may point
+                    // at large unused blocks.
+                    static if (hasIndirections!T)
+                    {
+                        immutable addedSize = u - (_data.capacity * T.sizeof);
+                        () @trusted { memset(_data.arr.ptr + _data.capacity, 0, addedSize); }();
+                    }
+
                     _data.capacity = u / T.sizeof;
                     return;
                 }
@@ -3665,10 +3675,20 @@ if (isDynamicArray!A)
 
             auto bi = (() @trusted => GC.qalloc(nbytes, blockAttribute!T))();
             _data.capacity = bi.size / T.sizeof;
-            import core.stdc.string : memcpy;
             if (len)
                 () @trusted { memcpy(bi.base, _data.arr.ptr, len * T.sizeof); }();
+
             _data.arr = (() @trusted => (cast(Unqual!T*) bi.base)[0 .. len])();
+
+            // we requested new bytes that are not in the existing
+            // data. If T has pointers, then this new data could point at stale
+            // objects from the last time this block was allocated. Zero that
+            // new data out, it may point at large unused blocks!
+            static if (hasIndirections!T)
+                () @trusted {
+                    memset(bi.base + (len * T.sizeof), 0, (newlen - len) * T.sizeof);
+                }();
+
             _data.tryExtendBlock = true;
             // leave the old data, for safety reasons
         }
@@ -4047,6 +4067,43 @@ if (isDynamicArray!A)
     app2.toString();
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24856
+@system unittest
+{
+    import core.memory : GC;
+    import std.stdio : writeln;
+    import std.algorithm.searching : canFind;
+    GC.disable();
+    scope(exit) GC.enable();
+    void*[] freeme;
+    // generate some poison blocks to allocate from.
+    auto poison = cast(void*) 0xdeadbeef;
+    foreach (i; 0 .. 10)
+    {
+        auto blk = new void*[7];
+        blk[] = poison;
+        freeme ~= blk.ptr;
+    }
+
+    foreach (p; freeme)
+        GC.free(p);
+
+    int tests = 0;
+    foreach (i; 0 .. 10)
+    {
+        Appender!(void*[]) app;
+        app.put(null);
+        // if not a realloc of one of the deadbeef pointers, continue
+        if (!freeme.canFind(app.data.ptr))
+            continue;
+        ++tests;
+        assert(!app.data.ptr[0 .. app.capacity].canFind(poison), "Appender not zeroing data!");
+    }
+    // just notify in the log whether this test actually could be done.
+    if (tests == 0)
+        writeln("WARNING: test of Appender zeroing did not occur");
+}
+
 //Calculates an efficient growth scheme based on the old capacity
 //of data, and the minimum requested capacity.
 //arg curLen: The current length
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index 15211a3a98adab5ab2952bf801a350a5db76055c..f8a97dfbf19c989c1f57bdd610b4abd3de8523fc 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -106,7 +106,7 @@ private template createAccessors(
             enum RightShiftOp = ">>>=";
         }
 
-        static if (is(T == bool))
+        static if (is(T : bool))
         {
             enum createAccessors =
             // getter
@@ -4676,3 +4676,24 @@ if (isIntegral!T)
     foreach (i; 0 .. 63)
         assert(bitsSet(1UL << i).equal([i]));
 }
+
+// Fix https://issues.dlang.org/show_bug.cgi?id=24095
+@safe @nogc pure unittest
+{
+    enum Bar : bool
+    {
+        a,
+        b,
+    }
+
+    struct Foo
+    {
+        mixin(bitfields!(Bar, "bar", 1, ubyte, "", 7,));
+    }
+
+    Foo foo;
+    foo.bar = Bar.a;
+    assert(foo.bar == Bar.a);
+    foo.bar = Bar.b;
+    assert(foo.bar == Bar.b);
+}
diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d
index 728aacde5c086dfcf14eb7df1ced86d751d75f63..8f7df105c834e05d1f54f3eb24afb3f5fd393952 100644
--- a/libphobos/src/std/container/dlist.d
+++ b/libphobos/src/std/container/dlist.d
@@ -185,6 +185,7 @@ Implements a doubly-linked list.
 struct DList(T)
 {
     import std.range : Take;
+    import std.traits : isMutable;
 
     /*
     A Node with a Payload. A PayNode.
@@ -220,7 +221,10 @@ struct DList(T)
     {
         import std.algorithm.mutation : move;
 
-        return (new PayNode(BaseNode(prev, next), move(arg))).asBaseNode();
+        static if (isMutable!Stuff)
+            return (new PayNode(BaseNode(prev, next), move(arg))).asBaseNode();
+        else
+            return (new PayNode(BaseNode(prev, next), arg)).asBaseNode();
     }
 
     void initialize() nothrow @safe pure
@@ -1149,3 +1153,22 @@ private:
     list.removeFront();
     assert(list[].walkLength == 0);
 }
+
+//  https://issues.dlang.org/show_bug.cgi?id=24637
+@safe unittest
+{
+    import std.algorithm.comparison : equal;
+
+    struct A
+    {
+        int c;
+    }
+
+    DList!A B;
+    B.insert(A(1));
+    assert(B[].equal([A(1)]));
+
+    const a = A(3);
+    B.insert(a);
+    assert(B[].equal([A(1), A(3)]));
+}
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 9c9d8db236a4e05c990931887d748d4dbe6031ea..5e0165cb60973a96422328fc68d2120004f9f8db 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -2560,9 +2560,6 @@ Lerr:
     string s1 = "123";
     auto a1 = parse!(int, string, Yes.doCount)(s1);
     assert(a1.data == 123 && a1.count == 3);
-
-    // parse only accepts lvalues
-    static assert(!__traits(compiles, parse!int("123")));
 }
 
 ///
@@ -5611,6 +5608,14 @@ Params:
 
 Returns:
     a `string`, a `wstring` or a `dstring`, according to the type of hexData.
+
+See_Also:
+    Use $(REF fromHexString, std, digest) for run time conversions.
+    Note, these functions are not drop-in replacements and have different
+    input requirements.
+    This template inherits its data syntax from builtin
+    $(LINK2 $(ROOT_DIR)spec/lex.html#hex_string, hex strings).
+    See $(REF fromHexString, std, digest) for its own respective requirements.
  */
 template hexString(string hexData)
 if (hexData.isHexLiteral)
diff --git a/libphobos/src/std/digest/package.d b/libphobos/src/std/digest/package.d
index ea3738b2f82b88d1e22f4314eb0dcfd78a0904c0..8274680edaba3e64e358dff8030ca42eac3f2c65 100644
--- a/libphobos/src/std/digest/package.d
+++ b/libphobos/src/std/digest/package.d
@@ -1212,3 +1212,345 @@ if (isInputRange!R1 && isInputRange!R2 && !isInfinite!R1 && !isInfinite!R2 &&
         assert(!secureEqual(hex1, hex2));
     }
 }
+
+/**
+ * Validates a hex string.
+ *
+ * Checks whether all characters following an optional "0x" suffix
+ * are valid hexadecimal digits.
+ *
+ * Params:
+ *     hex = hexdecimal encoded byte array
+ * Returns:
+ *     true = if valid
+ */
+bool isHexString(String)(String hex) @safe pure nothrow @nogc
+if (isSomeString!String)
+{
+    import std.ascii : isHexDigit;
+
+    if ((hex.length >= 2) && (hex[0 .. 2] == "0x"))
+    {
+        hex = hex[2 .. $];
+    }
+
+    foreach (digit; hex)
+    {
+        if (!digit.isHexDigit)
+        {
+            return false;
+        }
+    }
+
+    return true;
+}
+
+///
+@safe unittest
+{
+    assert(isHexString("0x0123456789ABCDEFabcdef"));
+    assert(isHexString("0123456789ABCDEFabcdef"));
+    assert(!isHexString("g"));
+    assert(!isHexString("#"));
+}
+
+/**
+ * Converts a hex text string to a range of bytes.
+ *
+ * The input to this function MUST be valid.
+ * $(REF isHexString, std, digest) can be used to check for this if needed.
+ *
+ * Params:
+ *     hex = String representation of a hexdecimal-encoded byte array.
+ * Returns:
+ *     A forward range of bytes.
+ */
+auto fromHexStringAsRange(String)(String hex) @safe pure nothrow @nogc
+if (isSomeString!String)
+{
+    return HexStringDecoder!String(hex);
+}
+
+///
+@safe unittest
+{
+    import std.range.primitives : ElementType, isForwardRange;
+    import std.traits : ReturnType;
+
+    // The decoder implements a forward range.
+    static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!string)));
+    static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!wstring)));
+    static assert(isForwardRange!(ReturnType!(fromHexStringAsRange!dstring)));
+
+    // The element type of the range is always `ubyte`.
+    static assert(
+        is(ElementType!(ReturnType!(fromHexStringAsRange!string)) == ubyte)
+    );
+    static assert(
+        is(ElementType!(ReturnType!(fromHexStringAsRange!wstring)) == ubyte)
+    );
+    static assert(
+        is(ElementType!(ReturnType!(fromHexStringAsRange!dstring)) == ubyte)
+    );
+}
+
+@safe unittest
+{
+    import std.array : staticArray;
+
+    // `staticArray` consumes the range returned by `fromHexStringAsRange`.
+    assert("0x0000ff".fromHexStringAsRange.staticArray!3  == [0, 0, 0xFF]);
+    assert("0x0000ff"w.fromHexStringAsRange.staticArray!3 == [0, 0, 0xFF]);
+    assert("0x0000ff"d.fromHexStringAsRange.staticArray!3 == [0, 0, 0xFF]);
+    assert("0xff12ff".fromHexStringAsRange.staticArray!1  == [0xFF]);
+    assert("0x12ff".fromHexStringAsRange.staticArray!2    == [0x12, 255]);
+    assert(
+        "0x3AaAA".fromHexStringAsRange.staticArray!4 == [0x3, 0xAA, 0xAA, 0x00]
+    );
+}
+
+/**
+ * Converts a hex text string to a range of bytes.
+ *
+ * Params:
+ *     hex = String representation of a hexdecimal-encoded byte array.
+ * Returns:
+ *     An newly allocated array of bytes.
+ * Throws:
+ *     Exception on invalid input.
+ * Example:
+ * ---
+ * ubyte[] dby  = "0xBA".fromHexString;
+ * ---
+ * See_Also:
+ *     $(REF fromHexString, std, digest) for a range version of the function.
+ */
+ubyte[] fromHexString(String)(String hex) @safe pure
+if (isSomeString!String)
+{
+    // This function is trivial, yet necessary for consistency.
+    // It provides a similar API to its `toHexString` counterpart.
+
+    if (!hex.isHexString)
+    {
+        import std.conv : text;
+
+        throw new Exception(
+            "The provided character sequence `"
+                ~ hex.text
+                ~ "` is not a valid hex string."
+        );
+    }
+
+    if ((hex.length >= 2) && (hex[0 .. 2] == "0x"))
+    {
+        hex = hex[2 .. $];
+    }
+
+    auto decoder = HexStringDecoder!String(hex);
+    auto result = new ubyte[](decoder.length);
+
+    size_t idx = 0;
+    foreach (b; decoder)
+    {
+        result[idx++] = b;
+    }
+    return result;
+}
+
+///
+@safe unittest
+{
+    // Single byte
+    assert("0xff".fromHexString  == [255]);
+    assert("0xff"w.fromHexString == [255]);
+    assert("0xff"d.fromHexString == [255]);
+    assert("0xC0".fromHexString  == [192]);
+    assert("0x00".fromHexString  == [0]);
+
+    // Nothing
+    assert("".fromHexString  == []);
+    assert(""w.fromHexString == []);
+    assert(""d.fromHexString == []);
+
+    // Nothing but a prefix
+    assert("0x".fromHexString  == []);
+    assert("0x"w.fromHexString == []);
+    assert("0x"d.fromHexString == []);
+
+    // Half a byte
+    assert("0x1".fromHexString  == [0x01]);
+    assert("0x1"w.fromHexString == [0x01]);
+    assert("0x1"d.fromHexString == [0x01]);
+
+    // Mixed case is fine.
+    assert("0xAf".fromHexString == [0xAF]);
+    assert("0xaF".fromHexString == [0xAF]);
+
+    // Multiple bytes
+    assert("0xfff".fromHexString     == [0x0F, 0xFF]);
+    assert("0x123AaAa".fromHexString == [0x01, 0x23, 0xAA, 0xAA]);
+    assert("EBBBBF".fromHexString    == [0xEB, 0xBB, 0xBF]);
+
+    // md5 sum
+    assert("d41d8cd98f00b204e9800998ecf8427e".fromHexString == [
+        0xD4, 0x1D, 0x8C, 0xD9, 0x8F, 0x00, 0xB2, 0x04,
+        0xE9, 0x80, 0x09, 0x98, 0xEC, 0xF8, 0x42, 0x7E,
+    ]);
+}
+
+///
+@safe unittest
+{
+    // Cycle self-test
+    const ubyte[] initial = [0x00, 0x12, 0x34, 0xEB];
+    assert(initial == initial.toHexString().fromHexString());
+}
+
+private ubyte hexDigitToByte(dchar hexDigit) @safe pure nothrow @nogc
+{
+    static int hexDigitToByteImpl(dchar hexDigit)
+    {
+        if (hexDigit >= '0' && hexDigit <= '9')
+        {
+            return hexDigit - '0';
+        }
+        else if (hexDigit >= 'A' && hexDigit <= 'F')
+        {
+            return hexDigit - 'A' + 10;
+        }
+        else if (hexDigit >= 'a' && hexDigit <= 'f')
+        {
+            return hexDigit - 'a' + 10;
+        }
+
+        assert(false, "Cannot convert invalid hex digit.");
+    }
+
+    return hexDigitToByteImpl(hexDigit) & 0xFF;
+}
+
+@safe unittest
+{
+    assert(hexDigitToByte('0') == 0x0);
+    assert(hexDigitToByte('9') == 0x9);
+    assert(hexDigitToByte('a') == 0xA);
+    assert(hexDigitToByte('b') == 0xB);
+    assert(hexDigitToByte('A') == 0xA);
+    assert(hexDigitToByte('C') == 0xC);
+}
+
+private struct HexStringDecoder(String)
+if (isSomeString!String)
+{
+    String hex;
+    ubyte front;
+    bool empty;
+
+    this(String hex)
+    {
+        if ((hex.length >= 2) && (hex[0 .. 2] == "0x"))
+        {
+            hex = hex[2 .. $];
+        }
+
+        if (hex.length == 0)
+        {
+            empty = true;
+            return;
+        }
+
+        const oddInputLength = (hex.length % 2 == 1);
+
+        if (oddInputLength)
+        {
+            front = hexDigitToByte(hex[0]);
+            hex = hex[1 .. $];
+        }
+        else
+        {
+            front = cast(ubyte)(hexDigitToByte(hex[0]) << 4 | hexDigitToByte(hex[1]));
+            hex = hex[2 .. $];
+        }
+
+        this.hex = hex;
+    }
+
+    void popFront()
+    {
+        if (hex.length == 0)
+        {
+            empty = true;
+            return;
+        }
+
+        front = cast(ubyte)(hexDigitToByte(hex[0]) << 4 | hexDigitToByte(hex[1]));
+        hex = hex[2 .. $];
+    }
+
+    typeof(this) save()
+    {
+        return this;
+    }
+
+    size_t length() const
+    {
+        if (this.empty)
+        {
+            return 0;
+        }
+
+        // current front + remainder
+        return 1 + (hex.length >> 1);
+    }
+}
+
+@safe unittest
+{
+    auto decoder = HexStringDecoder!string("");
+    assert(decoder.empty);
+    assert(decoder.length == 0);
+
+    decoder = HexStringDecoder!string("0x");
+    assert(decoder.empty);
+    assert(decoder.length == 0);
+}
+
+@safe unittest
+{
+    auto decoder = HexStringDecoder!string("0x0077FF");
+    assert(!decoder.empty);
+    assert(decoder.length == 3);
+    assert(decoder.front == 0x00);
+
+    decoder.popFront();
+    assert(!decoder.empty);
+    assert(decoder.length == 2);
+    assert(decoder.front == 0x77);
+
+    decoder.popFront();
+    assert(!decoder.empty);
+    assert(decoder.length == 1);
+    assert(decoder.front == 0xFF);
+
+    decoder.popFront();
+    assert(decoder.length == 0);
+    assert(decoder.empty);
+}
+
+@safe unittest
+{
+    auto decoder = HexStringDecoder!string("0x7FF");
+    assert(!decoder.empty);
+    assert(decoder.length == 2);
+    assert(decoder.front == 0x07);
+
+    decoder.popFront();
+    assert(!decoder.empty);
+    assert(decoder.length == 1);
+    assert(decoder.front == 0xFF);
+
+    decoder.popFront();
+    assert(decoder.length == 0);
+    assert(decoder.empty);
+}
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 8b60565d8a17177b2bfd83da430d98dcb793e11f..6fd468d315e6172c84acd6b755461d3ca9f11db4 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -1839,24 +1839,26 @@ template hasToString(T, Char)
     else static if (is(typeof(
         (T val) {
             const FormatSpec!Char f;
-            static struct S {void put(scope Char s){}}
+            static struct S
+            {
+                @disable this(this);
+                void put(scope Char s){}
+            }
             S s;
             val.toString(s, f);
-            static assert(!__traits(compiles, val.toString(s, FormatSpec!Char())),
-                          "force toString to take parameters by ref");
-            static assert(!__traits(compiles, val.toString(S(), f)),
-                          "force toString to take parameters by ref");
         })))
     {
         enum hasToString = HasToStringResult.customPutWriterFormatSpec;
     }
     else static if (is(typeof(
         (T val) {
-            static struct S {void put(scope Char s){}}
+            static struct S
+            {
+                @disable this(this);
+                void put(scope Char s){}
+            }
             S s;
             val.toString(s);
-            static assert(!__traits(compiles, val.toString(S())),
-                          "force toString to take parameters by ref");
         })))
     {
         enum hasToString = HasToStringResult.customPutWriter;
@@ -1996,9 +1998,10 @@ template hasToString(T, Char)
         static assert(hasToString!(G, char) == customPutWriter);
         static assert(hasToString!(H, char) == customPutWriterFormatSpec);
         static assert(hasToString!(I, char) == customPutWriterFormatSpec);
-        static assert(hasToString!(J, char) == hasSomeToString);
+        static assert(hasToString!(J, char) == hasSomeToString
+            || hasToString!(J, char) == constCharSinkFormatSpec); // depends on -preview=rvaluerefparam
         static assert(hasToString!(K, char) == constCharSinkFormatSpec);
-        static assert(hasToString!(L, char) == none);
+        static assert(hasToString!(L, char) == customPutWriterFormatSpec);
         static if (hasPreviewIn)
         {
             static assert(hasToString!(M, char) == inCharSinkFormatSpec);
@@ -2105,9 +2108,10 @@ template hasToString(T, Char)
         static assert(hasToString!(G, char) == customPutWriter);
         static assert(hasToString!(H, char) == customPutWriterFormatSpec);
         static assert(hasToString!(I, char) == customPutWriterFormatSpec);
-        static assert(hasToString!(J, char) == hasSomeToString);
+        static assert(hasToString!(J, char) == hasSomeToString
+            || hasToString!(J, char) == constCharSinkFormatSpec); // depends on -preview=rvaluerefparam
         static assert(hasToString!(K, char) == constCharSinkFormatSpec);
-        static assert(hasToString!(L, char) == none);
+        static assert(hasToString!(L, char) == HasToStringResult.customPutWriterFormatSpec);
         static if (hasPreviewIn)
         {
             static assert(hasToString!(M, char) == inCharSinkFormatSpec);
@@ -2125,9 +2129,10 @@ template hasToString(T, Char)
         static assert(hasToString!(inout(G), char) == customPutWriter);
         static assert(hasToString!(inout(H), char) == customPutWriterFormatSpec);
         static assert(hasToString!(inout(I), char) == customPutWriterFormatSpec);
-        static assert(hasToString!(inout(J), char) == hasSomeToString);
+        static assert(hasToString!(inout(J), char) == hasSomeToString
+            || hasToString!(inout(J), char) == constCharSinkFormatSpec); // depends on -preview=rvaluerefparam
         static assert(hasToString!(inout(K), char) == constCharSinkFormatSpec);
-        static assert(hasToString!(inout(L), char) == none);
+        static assert(hasToString!(inout(L), char) == customPutWriterFormatSpec);
         static if (hasPreviewIn)
         {
             static assert(hasToString!(inout(M), char) == inCharSinkFormatSpec);
diff --git a/libphobos/src/std/format/read.d b/libphobos/src/std/format/read.d
index da9d0dc14db4337eb77c4d5cf31460098ff6b3ce..e2f9b944a18aeef57c5d7cd703d91b394348d417 100644
--- a/libphobos/src/std/format/read.d
+++ b/libphobos/src/std/format/read.d
@@ -198,7 +198,8 @@ module std.format.read;
 
 import std.format.spec : FormatSpec;
 import std.format.internal.read;
-import std.traits : isSomeString;
+import std.meta : allSatisfy;
+import std.traits : isSomeString, isType;
 
 /**
 Reads an input range according to a format string and stores the read
@@ -300,7 +301,7 @@ uint formattedRead(Range, Char, Args...)(auto ref Range r, const(Char)[] fmt, au
 
 /// ditto
 uint formattedRead(alias fmt, Range, Args...)(auto ref Range r, auto ref Args args)
-if (isSomeString!(typeof(fmt)))
+if (!isType!fmt && isSomeString!(typeof(fmt)))
 {
     import std.format : checkFormatException;
     import std.meta : staticMap;
@@ -692,6 +693,116 @@ if (isSomeString!(typeof(fmt)))
     assert(aa2 == ["hello":1, "world":2]);
 }
 
+/**
+Reads an input range according to a format string and returns a tuple of Args
+with the read values.
+
+Format specifiers with format character $(B 'd'), $(B 'u') and $(B
+'c') can take a $(B '*') parameter for skipping values.
+
+The second version of `formattedRead` takes the format string as
+template argument. In this case, it is checked for consistency at
+compile-time.
+
+Params:
+    Args = a variadic list of types of the arguments
+ */
+template formattedRead(Args...)
+if (Args.length && allSatisfy!(isType, Args))
+{
+    import std.typecons : Tuple;
+
+    /**
+    Params:
+        r = an $(REF_ALTTEXT input range, isInputRange, std, range, primitives),
+            where the formatted input is read from
+        fmt = a $(MREF_ALTTEXT format string, std,format)
+        Range = the type of the input range `r`
+        Char = the character type used for `fmt`
+
+    Returns:
+        A Tuple!Args with the elements filled.
+
+    Throws:
+        A $(REF_ALTTEXT FormatException, FormatException, std, format)
+        if reading did not succeed.
+    */
+    Tuple!Args formattedRead(Range, Char)(auto ref Range r, const(Char)[] fmt)
+    {
+        import core.lifetime : forward;
+        import std.format : enforceFmt;
+
+        Tuple!Args args;
+        const numArgsFilled = .formattedRead(forward!r, fmt, args.expand);
+        enforceFmt(numArgsFilled == Args.length, "Failed reading into all format arguments");
+        return args;
+    }
+}
+
+///
+@safe pure unittest
+{
+    import std.exception : assertThrown;
+    import std.format : FormatException;
+    import std.typecons : tuple;
+
+    auto complete = "hello!34.5:124".formattedRead!(string, double, int)("%s!%s:%s");
+    assert(complete == tuple("hello", 34.5, 124));
+
+    // reading ends early
+    assertThrown!FormatException("hello!34.5:".formattedRead!(string, double, int)("%s!%s:%s"));
+}
+
+/// Skipping values
+@safe pure unittest
+{
+    import std.format : FormatException;
+    import std.typecons : tuple;
+
+    auto result = "orange: (12%) 15.25".formattedRead!(string, double)("%s: (%*d%%) %f");
+    assert(result == tuple("orange", 15.25));
+}
+
+/// ditto
+template formattedRead(alias fmt, Args...)
+if (!isType!fmt && isSomeString!(typeof(fmt)) && Args.length && allSatisfy!(isType, Args))
+{
+    import std.typecons : Flag, Tuple, Yes;
+    Tuple!Args formattedRead(Range)(auto ref Range r)
+    {
+        import core.lifetime : forward;
+        import std.format : enforceFmt;
+
+        Tuple!Args args;
+        const numArgsFilled = .formattedRead!fmt(forward!r, args.expand);
+        enforceFmt(numArgsFilled == Args.length, "Failed reading into all format arguments");
+        return args;
+    }
+}
+
+/// The format string can be checked at compile-time
+@safe pure unittest
+{
+    import std.exception : assertThrown;
+    import std.format : FormatException;
+    import std.typecons : tuple;
+
+    auto expected = tuple("hello", 124, 34.5);
+    auto result = "hello!124:34.5".formattedRead!("%s!%s:%s", string, int, double);
+    assert(result == expected);
+
+    assertThrown!FormatException("hello!34.5:".formattedRead!("%s!%s:%s", string, double, int));
+}
+
+/// Compile-time consistency check
+@safe pure unittest
+{
+    import std.format : FormatException;
+    import std.typecons : tuple;
+
+    static assert(!__traits(compiles, "orange: (12%) 15.25".formattedRead!("%s: (%*d%%) %f", string, double)));
+}
+
 /**
 Reads a value from the given _input range and converts it according to a
 format specifier.
diff --git a/libphobos/src/std/logger/core.d b/libphobos/src/std/logger/core.d
index cc938d4fd34970d09bbbc9faeeb93b1317f4d86f..1e879fd6c56f7b1a85f61381cfb0d0eafec8ff85 100644
--- a/libphobos/src/std/logger/core.d
+++ b/libphobos/src/std/logger/core.d
@@ -1433,7 +1433,7 @@ logger by the user, the default logger's log level is LogLevel.info.
 
 Example:
 -------------
-sharedLog = new FileLogger(yourFile);
+sharedLog = new shared FileLogger(yourFile);
 -------------
 The example sets a new `FileLogger` as new `sharedLog`.
 
@@ -1450,7 +1450,7 @@ writing `sharedLog`.
 The default `Logger` is thread-safe.
 -------------
 if (sharedLog !is myLogger)
-    sharedLog = new myLogger;
+    sharedLog = new shared myLogger;
 -------------
 */
 @property shared(Logger) sharedLog() @safe
diff --git a/libphobos/src/std/logger/filelogger.d b/libphobos/src/std/logger/filelogger.d
index c662ca74e30059fa8fee82b14070ca729d826c4b..5ba167c7bdb368734caad9e1f4535dd066a73989 100644
--- a/libphobos/src/std/logger/filelogger.d
+++ b/libphobos/src/std/logger/filelogger.d
@@ -37,7 +37,7 @@ class FileLogger : Logger
     auto l3 = new FileLogger("logFile", LogLevel.fatal, CreateFolder.yes);
     -------------
     */
-    this(const string fn, const LogLevel lv = LogLevel.all) @safe
+    this(this This)(const string fn, const LogLevel lv = LogLevel.all)
     {
          this(fn, lv, CreateFolder.yes);
     }
@@ -63,7 +63,7 @@ class FileLogger : Logger
     auto l2 = new FileLogger(file, LogLevel.fatal);
     -------------
     */
-    this(const string fn, const LogLevel lv, CreateFolder createFileNameFolder) @safe
+    this(this This)(const string fn, const LogLevel lv, CreateFolder createFileNameFolder)
     {
         import std.file : exists, mkdirRecurse;
         import std.path : dirName;
@@ -80,7 +80,8 @@ class FileLogger : Logger
                                    " created in '", d,"' could not be created."));
         }
 
-        this.file_.open(this.filename, "a");
+        // Cast away `shared` when the constructor is inferred shared.
+        () @trusted { (cast() this.file_).open(this.filename, "a"); }();
     }
 
     /** A constructor for the `FileLogger` Logger that takes a reference to
@@ -270,3 +271,12 @@ class FileLogger : Logger
     assert(tl !is null);
     stdThreadLocalLog.logLevel = LogLevel.all;
 }
+
+@safe unittest
+{
+    // we don't need to actually run the code, only make sure
+    // it compiles
+    static _() {
+        auto l = new shared FileLogger("");
+    }
+}
diff --git a/libphobos/src/std/logger/package.d b/libphobos/src/std/logger/package.d
index 14a439486dba864361f613329eaa7ce790f89a4f..215ca20b8772d76bd94c6ade717cc8aac559d69b 100644
--- a/libphobos/src/std/logger/package.d
+++ b/libphobos/src/std/logger/package.d
@@ -64,7 +64,7 @@ using the property called `sharedLog`. This property is a reference to the
 current default `Logger`. This reference can be used to assign a new
 default `Logger`.
 -------------
-sharedLog = new FileLogger("New_Default_Log_File.log");
+sharedLog = new shared FileLogger("New_Default_Log_File.log");
 -------------
 
 Additional `Logger` can be created by creating a new instance of the
diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d
index 3fef8e4f1feaa9a5b08951886080575e38604124..9966b1ce77fcdf3d8cbcbd82ef05fca1320bb413 100644
--- a/libphobos/src/std/numeric.d
+++ b/libphobos/src/std/numeric.d
@@ -223,7 +223,7 @@ private:
     }
 
     // Convert the current value to signed exponent, normalized form
-    void toNormalized(T,U)(ref T sig, ref U exp)
+    void toNormalized(T,U)(ref T sig, ref U exp) const
     {
         sig = significand;
         auto shift = (T.sizeof*8) - precision;
@@ -490,7 +490,7 @@ public:
     }
 
     /// Returns: real part
-    @property CustomFloat re() { return this; }
+    @property CustomFloat re() const { return this; }
 
     /// Returns: imaginary part
     static @property CustomFloat im() { return CustomFloat(0.0f); }
@@ -546,7 +546,7 @@ public:
     }
 
     /// Fetches the stored value either as a `float`, `double` or `real`.
-    @property F get(F)()
+    @property F get(F)() const
     if (staticIndexOf!(immutable F, immutable float, immutable double, immutable real) >= 0)
     {
         import std.conv : text;
@@ -591,14 +591,14 @@ public:
     // Define an opBinary `CustomFloat op CustomFloat` so that those below
     // do not match equally, which is disallowed by the spec:
     // https://dlang.org/spec/operatoroverloading.html#binary
-    real opBinary(string op,T)(T b)
+    real opBinary(string op,T)(T b) const
     if (__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
     {
         return mixin(`get!real`~op~`b.get!real`);
     }
 
     /// ditto
-    real opBinary(string op,T)(T b)
+    real opBinary(string op,T)(T b) const
     if ( __traits(compiles, mixin(`get!real`~op~`b`)) &&
         !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
     {
@@ -606,7 +606,7 @@ public:
     }
 
     /// ditto
-    real opBinaryRight(string op,T)(T a)
+    real opBinaryRight(string op,T)(T a) const
     if ( __traits(compiles, mixin(`a`~op~`get!real`)) &&
         !__traits(compiles, mixin(`get!real`~op~`b`)) &&
         !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
@@ -615,7 +615,7 @@ public:
     }
 
     /// ditto
-    int opCmp(T)(auto ref T b)
+    int opCmp(T)(auto ref T b) const
     if (__traits(compiles, cast(real) b))
     {
         auto x = get!real;
@@ -949,6 +949,17 @@ public:
     assertThrown!AssertError(a = float.infinity);
 }
 
+@safe unittest
+{
+    const CustomFloat!16 x = CustomFloat!16(3);
+    assert(x.get!float == 3);
+    assert(x.re.get!float == 3);
+    assert(x + x == 6);
+    assert(x + 1 == 4);
+    assert(2 + x == 5);
+    assert(x < 4);
+}
+
 private bool isCorrectCustomFloat(uint precision, uint exponentWidth, CustomFloatFlags flags) @safe pure nothrow @nogc
 {
     // Restrictions from bitfield
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 4f593bd067fe4970fc4eee0ec7f9b02d5c43e0ce..2efbcaa84c8cd70e3e405529cc6f548c83faf889 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -4631,11 +4631,12 @@ else version (Posix)
         if (childpid == 0)
         {
             // Trusted because args and all entries are always zero-terminated
-            (() @trusted =>
-                core.sys.posix.unistd.execvp(args[0], &args[0]) ||
-                perror(args[0]) // failed to execute
-            )();
-            return;
+            (() @trusted {
+                core.sys.posix.unistd.execvp(args[0], &args[0]);
+                perror(args[0]);
+                core.sys.posix.unistd._exit(1);
+            })();
+            assert(0, "Child failed to exec");
         }
         if (browser)
             // Trusted because it's allocated via strdup above
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index 52fd33b1dd1e32e0b0ebf7c52ed9b2ee95b140fd..7fa9974189f66dd8d484e0faae7b838edff7adb8 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -54,6 +54,12 @@ version (Windows)
     enum socket_t : SOCKET { INVALID_SOCKET }
     private const int _SOCKET_ERROR = SOCKET_ERROR;
 
+    /**
+     * On Windows, there is no `SO_REUSEPORT`.
+     * However, `SO_REUSEADDR` is equivalent to `SO_REUSEPORT` there.
+     * $(LINK https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse)
+     */
+    private enum SO_REUSEPORT = SO_REUSEADDR;
 
     private int _lasterr() nothrow @nogc
     {
@@ -2589,6 +2595,22 @@ enum SocketOption: int
     DEBUG =                SO_DEBUG,            /// Record debugging information
     BROADCAST =            SO_BROADCAST,        /// Allow transmission of broadcast messages
     REUSEADDR =            SO_REUSEADDR,        /// Allow local reuse of address
+    /**
+     * Allow local reuse of port
+     *
+     * On Windows, this is equivalent to `SocketOption.REUSEADDR`.
+     * There is in fact no option named `REUSEPORT`.
+     * However, `SocketOption.REUSEADDR` matches the behavior of
+     * `SocketOption.REUSEPORT` on other platforms. Further details on this
+     * topic can be found here:
+     * $(LINK https://learn.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse)
+     *
+     * On Linux, this ensures fair distribution of incoming connections accross threads.
+     *
+     * See_Also:
+     *   https://lwn.net/Articles/542629/
+     */
+    REUSEPORT =            SO_REUSEPORT,
     LINGER =               SO_LINGER,           /// Linger on close if unsent data is present
     OOBINLINE =            SO_OOBINLINE,        /// Receive out-of-band data in band
     SNDBUF =               SO_SNDBUF,           /// Send buffer size
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 69c2a49dd7faed5b62c00e69ccb9eb6beaf78d62..ad2942873a650a0f0446cb6ceb975b7198d78df7 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -1860,88 +1860,65 @@ private template Iota(size_t n)
     assert(Iota!3 == AliasSeq!(0, 1, 2));
 }
 
-/* The number that the dim-th argument's tag is multiplied by when
- * converting TagTuples to and from case indices ("caseIds").
- *
- * Named by analogy to the stride that the dim-th index into a
- * multidimensional static array is multiplied by to calculate the
- * offset of a specific element.
- */
-private size_t stride(size_t dim, lengths...)()
-{
-    import core.checkedint : mulu;
-
-    size_t result = 1;
-    bool overflow = false;
-
-    static foreach (i; 0 .. dim)
-    {
-        result = mulu(result, lengths[i], overflow);
-    }
-
-    /* The largest number matchImpl uses, numCases, is calculated with
-     * stride!(SumTypes.length), so as long as this overflow check
-     * passes, we don't need to check for overflow anywhere else.
-     */
-    assert(!overflow, "Integer overflow");
-    return result;
-}
-
 private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
 {
     auto ref matchImpl(SumTypes...)(auto ref SumTypes args)
     if (allSatisfy!(isSumType, SumTypes) && args.length > 0)
     {
-        alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
-        alias TagTuple = .TagTuple!(SumTypes);
-
-        /*
-         * A list of arguments to be passed to a handler needed for the case
-         * labeled with `caseId`.
-         */
-        template handlerArgs(size_t caseId)
+        // Single dispatch (fast path)
+        static if (args.length == 1)
         {
-            enum tags = TagTuple.fromCaseId(caseId);
-            enum argsFrom(size_t i : tags.length) = "";
-            enum argsFrom(size_t i) = "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
-                ".Types[" ~ toCtString!(tags[i]) ~ "])(), " ~ argsFrom!(i + 1);
-            enum handlerArgs = argsFrom!0;
-        }
+            /* When there's only one argument, the caseId is just that
+             * argument's tag, so there's no need for TagTuple.
+             */
+            enum handlerArgs(size_t caseId) =
+                "args[0].get!(SumTypes[0].Types[" ~ toCtString!caseId ~ "])()";
 
-        /* An AliasSeq of the types of the member values in the argument list
-         * returned by `handlerArgs!caseId`.
-         *
-         * Note that these are the actual (that is, qualified) types of the
-         * member values, which may not be the same as the types listed in
-         * the arguments' `.Types` properties.
-         */
-        template valueTypes(size_t caseId)
+            alias valueTypes(size_t caseId) =
+                typeof(args[0].get!(SumTypes[0].Types[caseId])());
+
+            enum numCases = SumTypes[0].Types.length;
+        }
+        // Multiple dispatch (slow path)
+        else
         {
-            enum tags = TagTuple.fromCaseId(caseId);
+            alias typeCounts = Map!(typeCount, SumTypes);
+            alias stride(size_t i) = .stride!(i, typeCounts);
+            alias TagTuple = .TagTuple!typeCounts;
+
+            alias handlerArgs(size_t caseId) = .handlerArgs!(caseId, typeCounts);
 
-            template getType(size_t i)
+            /* An AliasSeq of the types of the member values in the argument list
+             * returned by `handlerArgs!caseId`.
+             *
+             * Note that these are the actual (that is, qualified) types of the
+             * member values, which may not be the same as the types listed in
+             * the arguments' `.Types` properties.
+             */
+            template valueTypes(size_t caseId)
             {
-                enum tid = tags[i];
-                alias T = SumTypes[i].Types[tid];
-                alias getType = typeof(args[i].get!T());
+                enum tags = TagTuple.fromCaseId(caseId);
+
+                template getType(size_t i)
+                {
+                    enum tid = tags[i];
+                    alias T = SumTypes[i].Types[tid];
+                    alias getType = typeof(args[i].get!T());
+                }
+
+                alias valueTypes = Map!(getType, Iota!(tags.length));
             }
 
-            alias valueTypes = Map!(getType, Iota!(tags.length));
+            /* The total number of cases is
+             *
+             *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
+             *
+             * Conveniently, this is equal to stride!(SumTypes.length), so we can
+             * use that function to compute it.
+             */
+            enum numCases = stride!(SumTypes.length);
         }
 
-        /* The total number of cases is
-         *
-         *   Π SumTypes[i].Types.length for 0 ≤ i < SumTypes.length
-         *
-         * Or, equivalently,
-         *
-         *   ubyte[SumTypes[0].Types.length]...[SumTypes[$-1].Types.length].sizeof
-         *
-         * Conveniently, this is equal to stride!(SumTypes.length), so we can
-         * use that function to compute it.
-         */
-        enum numCases = stride!(SumTypes.length);
-
         /* Guaranteed to never be a valid handler index, since
          * handlers.length <= size_t.max.
          */
@@ -1998,7 +1975,12 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
             mixin("alias ", handlerName!hid, " = handler;");
         }
 
-        immutable argsId = TagTuple(args).toCaseId;
+        // Single dispatch (fast path)
+        static if (args.length == 1)
+            immutable argsId = args[0].tag;
+        // Multiple dispatch (slow path)
+        else
+            immutable argsId = TagTuple(args).toCaseId;
 
         final switch (argsId)
         {
@@ -2029,10 +2011,11 @@ private template matchImpl(Flag!"exhaustive" exhaustive, handlers...)
     }
 }
 
+// Predicate for staticMap
 private enum typeCount(SumType) = SumType.Types.length;
 
-/* A TagTuple represents a single possible set of tags that `args`
- * could have at runtime.
+/* A TagTuple represents a single possible set of tags that the arguments to
+ * `matchImpl` could have at runtime.
  *
  * Because D does not allow a struct to be the controlling expression
  * of a switch statement, we cannot dispatch on the TagTuple directly.
@@ -2054,22 +2037,23 @@ private enum typeCount(SumType) = SumType.Types.length;
  * When there is only one argument, the caseId is equal to that
  * argument's tag.
  */
-private struct TagTuple(SumTypes...)
+private struct TagTuple(typeCounts...)
 {
-    size_t[SumTypes.length] tags;
+    size_t[typeCounts.length] tags;
     alias tags this;
 
-    alias stride(size_t i) = .stride!(i, Map!(typeCount, SumTypes));
+    alias stride(size_t i) = .stride!(i, typeCounts);
 
     invariant
     {
         static foreach (i; 0 .. tags.length)
         {
-            assert(tags[i] < SumTypes[i].Types.length, "Invalid tag");
+            assert(tags[i] < typeCounts[i], "Invalid tag");
         }
     }
 
-    this(ref const(SumTypes) args)
+    this(SumTypes...)(ref const SumTypes args)
+    if (allSatisfy!(isSumType, SumTypes) && args.length == typeCounts.length)
     {
         static foreach (i; 0 .. tags.length)
         {
@@ -2104,6 +2088,52 @@ private struct TagTuple(SumTypes...)
     }
 }
 
+/* The number that the dim-th argument's tag is multiplied by when
+ * converting TagTuples to and from case indices ("caseIds").
+ *
+ * Named by analogy to the stride that the dim-th index into a
+ * multidimensional static array is multiplied by to calculate the
+ * offset of a specific element.
+ */
+private size_t stride(size_t dim, lengths...)()
+{
+    import core.checkedint : mulu;
+
+    size_t result = 1;
+    bool overflow = false;
+
+    static foreach (i; 0 .. dim)
+    {
+        result = mulu(result, lengths[i], overflow);
+    }
+
+    /* The largest number matchImpl uses, numCases, is calculated with
+     * stride!(SumTypes.length), so as long as this overflow check
+     * passes, we don't need to check for overflow anywhere else.
+     */
+    assert(!overflow, "Integer overflow");
+    return result;
+}
+
+/* A list of arguments to be passed to a handler needed for the case
+ * labeled with `caseId`.
+ */
+private template handlerArgs(size_t caseId, typeCounts...)
+{
+    enum tags = TagTuple!typeCounts.fromCaseId(caseId);
+
+    alias handlerArgs = AliasSeq!();
+
+    static foreach (i; 0 .. tags.length)
+    {
+        handlerArgs = AliasSeq!(
+            handlerArgs,
+            "args[" ~ toCtString!i ~ "].get!(SumTypes[" ~ toCtString!i ~ "]" ~
+            ".Types[" ~ toCtString!(tags[i]) ~ "])(), "
+        );
+    }
+}
+
 // Matching
 @safe unittest
 {
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 69362c08695dd9d645a58232a705ad2db51f05ef..f230aa3b74e43a006243d3983ab705dd0aadc139 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -7251,16 +7251,21 @@ alias PointerTarget(T : T*) = T;
 /**
  * Detect whether type `T` is an aggregate type.
  */
-enum bool isAggregateType(T) = is(T == struct) || is(T == union) ||
-                               is(T == class) || is(T == interface);
+template isAggregateType(T)
+{
+    static if (is(T == enum))
+        enum isAggregateType = isAggregateType!(OriginalType!T);
+    else
+        enum isAggregateType = is(T == struct) || is(T == class) || is(T == interface) || is(T == union);
+}
 
 ///
 @safe unittest
 {
-    class C;
-    union U;
-    struct S;
-    interface I;
+    class C {}
+    union U {}
+    struct S {}
+    interface I {}
 
     static assert( isAggregateType!C);
     static assert( isAggregateType!U);
@@ -7271,6 +7276,16 @@ enum bool isAggregateType(T) = is(T == struct) || is(T == union) ||
     static assert(!isAggregateType!(int[]));
     static assert(!isAggregateType!(C[string]));
     static assert(!isAggregateType!(void delegate(int)));
+
+    enum ES : S { a = S.init }
+    enum EC : C { a = C.init }
+    enum EI : I { a = I.init }
+    enum EU : U { a = U.init }
+
+    static assert( isAggregateType!ES);
+    static assert( isAggregateType!EC);
+    static assert( isAggregateType!EI);
+    static assert( isAggregateType!EU);
 }
 
 /**
@@ -9238,12 +9253,16 @@ enum isCopyable(S) = __traits(isCopyable, S);
  * is the same as `T`. For pointer and slice types, it is `T` with the
  * outer-most layer of qualifiers dropped.
  */
-package(std) template DeducedParameterType(T)
+package(std) alias DeducedParameterType(T) = DeducedParameterTypeImpl!T;
+/// ditto
+package(std) alias DeducedParameterType(alias T) = DeducedParameterTypeImpl!T;
+
+private template DeducedParameterTypeImpl(T)
 {
     static if (is(T == U*, U) || is(T == U[], U))
-        alias DeducedParameterType = Unqual!T;
+        alias DeducedParameterTypeImpl = Unqual!T;
     else
-        alias DeducedParameterType = T;
+        alias DeducedParameterTypeImpl = T;
 }
 
 @safe unittest
@@ -9263,6 +9282,7 @@ package(std) template DeducedParameterType(T)
     }
 
     static assert(is(DeducedParameterType!NoCopy == NoCopy));
+    static assert(is(DeducedParameterType!(inout(NoCopy)) == inout(NoCopy)));
 }
 
 @safe unittest
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index c874c0ff81166b822773efbdcc046d6232b050fc..bd462f53a5b1c8119cfd9f9923bcb5ad27114f51 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3104,17 +3104,18 @@ private:
     {
         static if (useQualifierCast)
         {
-            this.data = cast() value;
+            static if (hasElaborateAssign!T)
+            {
+                import core.lifetime : copyEmplace;
+                copyEmplace(cast() value, this.data);
+            }
+            else
+                this.data = cast() value;
         }
         else
         {
-            // As we're escaping a copy of `value`, deliberately leak a copy:
-            static union DontCallDestructor
-            {
-                T value;
-            }
-            DontCallDestructor copy = DontCallDestructor(value);
-            this.data = *cast(Payload*) &copy;
+            import core.lifetime : copyEmplace;
+            copyEmplace(cast() value, cast() *cast(T*) &this.data);
         }
     }
 
@@ -3139,6 +3140,334 @@ package(std) Rebindable2!T rebindable2(T)(T value)
     return Rebindable2!T(value);
 }
 
+// Verify that the destructor is called properly if there is one.
+@system unittest
+{
+    {
+        bool destroyed;
+
+        struct S
+        {
+            int i;
+
+            this(int i) @safe
+            {
+                this.i = i;
+            }
+
+            ~this() @safe
+            {
+                destroyed = true;
+            }
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+
+            // Whether destruction has occurred here depends on whether the
+            // temporary gets moved or not, so we won't assume that it has or
+            // hasn't happened. What we care about here is that foo gets destroyed
+            // properly when it leaves the scope.
+            destroyed = false;
+        }
+        assert(destroyed);
+
+        {
+            auto foo = rebindable2(const S(42));
+            destroyed = false;
+        }
+        assert(destroyed);
+    }
+
+    // Test for double destruction with qualifer cast being used
+    {
+        static struct S
+        {
+            int i;
+            bool destroyed;
+
+            this(int i) @safe
+            {
+                this.i = i;
+            }
+
+            ~this() @safe
+            {
+                destroyed = true;
+            }
+
+            @safe invariant
+            {
+                assert(!destroyed);
+            }
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+            assert(typeof(foo).useQualifierCast);
+            assert(foo.data.i == 42);
+            assert(!foo.data.destroyed);
+        }
+        {
+            auto foo = rebindable2(S(42));
+            destroy(foo);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            assert(typeof(foo).useQualifierCast);
+            assert(foo.data.i == 42);
+            assert(!foo.data.destroyed);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            destroy(foo);
+        }
+    }
+
+    // Test for double destruction without qualifer cast being used
+    {
+        static struct S
+        {
+            int i;
+            bool destroyed;
+
+            this(int i) @safe
+            {
+                this.i = i;
+            }
+
+            ~this() @safe
+            {
+                destroyed = true;
+            }
+
+            @disable ref S opAssign()(auto ref S rhs);
+
+            @safe invariant
+            {
+                assert(!destroyed);
+            }
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+            assert(!typeof(foo).useQualifierCast);
+            assert((cast(S*)&(foo.data)).i == 42);
+            assert(!(cast(S*)&(foo.data)).destroyed);
+        }
+        {
+            auto foo = rebindable2(S(42));
+            destroy(foo);
+        }
+    }
+}
+
+// Verify that if there is an overloaded assignment operator, it's not assigned
+// to garbage.
+@safe unittest
+{
+    static struct S
+    {
+        int i;
+        bool destroyed;
+
+        this(int i) @safe
+        {
+            this.i = i;
+        }
+
+        ~this() @safe
+        {
+            destroyed = true;
+        }
+
+        ref opAssign()(auto ref S rhs)
+        {
+            assert(!this.destroyed);
+            this.i = rhs.i;
+            return this;
+        }
+    }
+
+    {
+        auto foo = rebindable2(S(42));
+        foo = S(99);
+        assert(foo.data.i == 99);
+    }
+    {
+        auto foo = rebindable2(S(42));
+        foo = const S(99);
+        assert(foo.data.i == 99);
+    }
+}
+
+// Verify that postblit or copy constructor is called properly if there is one.
+@system unittest
+{
+    // postblit with type qualifier cast
+    {
+        static struct S
+        {
+            int i;
+            static bool copied;
+
+            this(this) @safe
+            {
+                copied = true;
+            }
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+
+            // Whether a copy has occurred here depends on whether the
+            // temporary gets moved or not, so we won't assume that it has or
+            // hasn't happened. What we care about here is that foo gets copied
+            // properly when we copy it below.
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            assert(typeof(foo).useQualifierCast);
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+        }
+    }
+
+    // copy constructor with type qualifier cast
+    {
+        static struct S
+        {
+            int i;
+            static bool copied;
+
+            this(ref inout S rhs) @safe inout
+            {
+                this.i = i;
+                copied = true;
+            }
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+            assert(typeof(foo).useQualifierCast);
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+        }
+    }
+
+    // FIXME https://issues.dlang.org/show_bug.cgi?id=24829
+
+    // Making this work requires either reworking how the !useQualiferCast
+    // version works so that the compiler can correctly generate postblit
+    // constructors and copy constructors as appropriate, or an explicit
+    // postblit or copy constructor needs to be added for such cases, which
+    // gets pretty complicated if we want to correctly add the same attributes
+    // that T's postblit or copy constructor has.
+
+    /+
+    // postblit without type qualifier cast
+    {
+        static struct S
+        {
+            int* ptr;
+            static bool copied;
+
+            this(int i)
+            {
+                ptr = new int(i);
+            }
+
+            this(this) @safe
+            {
+                if (ptr !is null)
+                    ptr = new int(*ptr);
+                copied = true;
+            }
+
+            @disable ref S opAssign()(auto ref S rhs);
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+            assert(!typeof(foo).useQualifierCast);
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+            assert(*(cast(S*)&(foo.data)).ptr == *(cast(S*)&(bar.data)).ptr);
+            assert((cast(S*)&(foo.data)).ptr !is (cast(S*)&(bar.data)).ptr);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+            assert(*(cast(S*)&(foo.data)).ptr == *(cast(S*)&(bar.data)).ptr);
+            assert((cast(S*)&(foo.data)).ptr !is (cast(S*)&(bar.data)).ptr);
+        }
+    }
+
+    // copy constructor without type qualifier cast
+    {
+        static struct S
+        {
+            int* ptr;
+            static bool copied;
+
+            this(int i)
+            {
+                ptr = new int(i);
+            }
+
+            this(ref inout S rhs) @safe inout
+            {
+                if (rhs.ptr !is null)
+                    ptr = new inout int(*rhs.ptr);
+                copied = true;
+            }
+
+            @disable ref S opAssign()(auto ref S rhs);
+        }
+
+        {
+            auto foo = rebindable2(S(42));
+            assert(!typeof(foo).useQualifierCast);
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+            assert(*(cast(S*)&(foo.data)).ptr == *(cast(S*)&(bar.data)).ptr);
+            assert((cast(S*)&(foo.data)).ptr !is (cast(S*)&(bar.data)).ptr);
+        }
+        {
+            auto foo = rebindable2(const S(42));
+            S.copied = false;
+
+            auto bar = foo;
+            assert(S.copied);
+            assert(*(cast(S*)&(foo.data)).ptr == *(cast(S*)&(bar.data)).ptr);
+            assert((cast(S*)&(foo.data)).ptr !is (cast(S*)&(bar.data)).ptr);
+        }
+    }
+    +/
+}
+
 /**
     Similar to `Rebindable!(T)` but strips all qualifiers from the reference as
     opposed to just constness / immutability. Primary intended use case is with
diff --git a/libphobos/src/std/windows/syserror.d b/libphobos/src/std/windows/syserror.d
index 3d8c5e71cecc5fc977684052211433de690968d8..dadf0e8749e5b2e97e4d6a4850332be3b1576077 100644
--- a/libphobos/src/std/windows/syserror.d
+++ b/libphobos/src/std/windows/syserror.d
@@ -69,7 +69,6 @@ import core.sys.windows.winbase, core.sys.windows.winnt;
 import std.array : appender, Appender;
 import std.conv : to, toTextRange, text;
 import std.exception;
-import std.windows.charset;
 
 string sysErrorString(
     DWORD errCode,