diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index ae575cf465ed329146d7889a8f5a5e7103bedf71..f28761e4b37012e7b6292db11c7ff8962f7d61c4 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -88,7 +88,6 @@ D_FRONTEND_OBJS = \
 	d/ast_node.o \
 	d/astcodegen.o \
 	d/astenums.o \
-	d/basicmangle.o \
 	d/blockexit.o \
 	d/builtin.o \
 	d/canthrow.o \
@@ -104,7 +103,6 @@ D_FRONTEND_OBJS = \
 	d/cond.o \
 	d/constfold.o \
 	d/cparse.o \
-	d/cppmangle.o \
 	d/ctfeexpr.o \
 	d/ctorflow.o \
 	d/cxxfrontend.o \
@@ -117,7 +115,6 @@ D_FRONTEND_OBJS = \
 	d/dimport.o \
 	d/dinterpret.o \
 	d/dmacro.o \
-	d/dmangle.o \
 	d/dmodule.o \
 	d/doc.o \
 	d/dscope.o \
@@ -155,6 +152,9 @@ D_FRONTEND_OBJS = \
 	d/lambdacomp.o \
 	d/lexer.o \
 	d/location.o \
+        d/mangle-basic.o \
+	d/mangle-cpp.o \
+	d/mangle-package.o \
 	d/mtype.o \
 	d/mustuse.o \
 	d/nogc.o \
@@ -420,6 +420,10 @@ d/common-%.o: d/dmd/common/%.d
 	$(DCOMPILE) $(D_INCLUDES) $<
 	$(DPOSTCOMPILE)
 
+d/mangle-%.o: d/dmd/mangle/%.d
+	$(DCOMPILE) $(D_INCLUDES) $<
+	$(DPOSTCOMPILE)
+
 d/root-%.o: d/dmd/root/%.d
 	$(DCOMPILE) $(D_INCLUDES) $<
 	$(DPOSTCOMPILE)
diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 538600cd027841655ee00688b25126dc8eba5485..f7e7a801a00d1dadc80ce19d6a8ad6ff4cffb954 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -777,7 +777,7 @@ maybe_set_builtin_1 (Dsymbol *d)
   if (ad != NULL)
     {
       /* Recursively search through attribute decls.  */
-      Dsymbols *decls = ad->include (NULL);
+      Dsymbols *decls = dmd::include (ad, NULL);
       if (decls && decls->length)
 	{
 	  for (size_t i = 0; i < decls->length; i++)
diff --git a/gcc/d/d-diagnostic.cc b/gcc/d/d-diagnostic.cc
index b8c04dce303fa6c95e6c8c89c51ae7d26965c2d8..4749585d93054cbe311e0ee3c87b237f6f4f16af 100644
--- a/gcc/d/d-diagnostic.cc
+++ b/gcc/d/d-diagnostic.cc
@@ -241,7 +241,7 @@ verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
     }
   else if (kind == ErrorKind::warning)
     {
-      if (global.gag || global.params.warnings == DIAGNOSTICoff)
+      if (global.gag || global.params.useWarnings == DIAGNOSTICoff)
 	{
 	  if (global.gag)
 	    global.gaggedWarnings++;
@@ -250,7 +250,7 @@ verrorReport (const Loc& loc, const char *format, va_list ap, ErrorKind kind,
 	}
 
       /* Warnings don't count if not treated as errors.  */
-      if (global.params.warnings == DIAGNOSTICerror)
+      if (global.params.useWarnings == DIAGNOSTICerror)
 	global.warnings++;
 
       diag_kind = DK_WARNING;
@@ -314,7 +314,7 @@ verrorReportSupplemental (const Loc& loc, const char* format, va_list ap,
     }
   else if (kind == ErrorKind::warning)
     {
-      if (global.params.warnings == DIAGNOSTICoff || global.gag)
+      if (global.params.useWarnings == DIAGNOSTICoff || global.gag)
 	return;
     }
   else if (kind == ErrorKind::deprecation)
diff --git a/gcc/d/d-frontend.cc b/gcc/d/d-frontend.cc
index 90a22041bb0f19f0b0ccf78e438895aa5298fe85..587579d9f80433d0519cb75c077db76bbe4288ec 100644
--- a/gcc/d/d-frontend.cc
+++ b/gcc/d/d-frontend.cc
@@ -79,11 +79,11 @@ eval_builtin (const Loc &loc, FuncDeclaration *fd, Expressions *arguments)
 /* Build and return typeinfo type for TYPE.  */
 
 Type *
-getTypeInfoType (const Loc &loc, Type *type, Scope *sc, bool genObjCode)
+getTypeInfoType (const Loc &loc, Type *type, Scope *sc)
 {
   gcc_assert (type->ty != TY::Terror);
   check_typeinfo_type (loc, sc);
-  create_typeinfo (type, sc ? sc->_module->importedFrom : NULL, genObjCode);
+  create_typeinfo (type, sc ? sc->_module->importedFrom : NULL);
   return type->vtinfo->type;
 }
 
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index b6724c3afbcf364c704be9012b14de9204a3b850..467e886530417307a23b93d9f62a8c6ad3e39480 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -302,7 +302,7 @@ d_init_options (unsigned int, cl_decoded_option *decoded_options)
 
   /* Warnings and deprecations are disabled by default.  */
   global.params.useDeprecated = DIAGNOSTICinform;
-  global.params.warnings = DIAGNOSTICoff;
+  global.params.useWarnings = DIAGNOSTICoff;
   global.params.v.errorLimit = flag_max_errors;
   global.params.v.messageStyle = MessageStyle::gnu;
 
@@ -772,7 +772,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 
     case OPT_Wall:
       if (value)
-	global.params.warnings = DIAGNOSTICinform;
+	global.params.useWarnings = DIAGNOSTICinform;
       break;
 
     case OPT_Wdeprecated:
@@ -781,7 +781,7 @@ d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
 
     case OPT_Werror:
       if (value)
-	global.params.warnings = DIAGNOSTICerror;
+	global.params.useWarnings = DIAGNOSTICerror;
       break;
 
     case OPT_Wspeculative:
@@ -907,7 +907,7 @@ d_post_options (const char ** fn)
 
   /* Error about use of deprecated features.  */
   if (global.params.useDeprecated == DIAGNOSTICinform
-      && global.params.warnings == DIAGNOSTICerror)
+      && global.params.useWarnings == DIAGNOSTICerror)
     global.params.useDeprecated = DIAGNOSTICerror;
 
   if (flag_excess_precision == EXCESS_PRECISION_DEFAULT)
@@ -933,6 +933,7 @@ d_post_options (const char ** fn)
   /* The front-end parser only has access to `compileEnv', synchronize its
      fields with params.  */
   global.compileEnv.previewIn = global.params.previewIn;
+  global.compileEnv.transitionIn = global.params.v.vin;
   global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
   global.compileEnv.cCharLookupTable =
     IdentifierCharLookup::forTable (IdentifierTable::C11);
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index ed7158528b6fa9d259a7a356312a49fbffe80980..e5d7e2b183004a0d4aad9b003cfbd603aa5a1025 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -588,3 +588,23 @@ Target::preferPassByRef (Type *param_type)
 
   return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray);
 }
+
+/* Returns true if the specified bit-field FIELD contributes to the alignment
+   of the containing aggregate.  */
+
+bool
+TargetC::contributesToAggregateAlignment(BitFieldDeclaration *field)
+{
+  if (this->bitFieldStyle == TargetC::BitFieldStyle::MS)
+    return true;
+
+  if (PCC_BITFIELD_TYPE_MATTERS)
+    {
+      /* Named bit-fields contribute to alignment. Some targets also apply the
+	 same rules to unnamed bit-fields too.  */
+      if (!field->isAnonymous () || targetm.align_anon_bitfield ())
+	return true;
+    }
+
+  return false;
+}
diff --git a/gcc/d/d-tree.h b/gcc/d/d-tree.h
index 5a5a81c091e2097d32608b8988f28e1035d18f49..eeecef33e1dd4055dd6179e4c87367461b5127a6 100644
--- a/gcc/d/d-tree.h
+++ b/gcc/d/d-tree.h
@@ -703,7 +703,7 @@ extern tree get_classinfo_decl (ClassDeclaration *);
 extern void check_typeinfo_type (const Loc &, Scope *, Expression * = NULL);
 extern tree build_typeinfo (const Loc &, Type *, Expression * = NULL);
 extern tree build_typeinfo (Expression *, Type *);
-extern void create_typeinfo (Type *, Module *, bool = true);
+extern void create_typeinfo (Type *, Module *);
 extern void create_tinfo_types (Module *);
 extern void layout_cpp_typeinfo (ClassDeclaration *);
 extern tree get_cpp_typeinfo_decl (ClassDeclaration *);
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index af984968c64aa15fe639b1d6638373c8143dab6d..88dc5251bdafc982e504ade7cd103f3a764b20c3 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -350,7 +350,7 @@ public:
 
   void visit (AttribDeclaration *d) final override
   {
-    Dsymbols *ds = d->include (NULL);
+    Dsymbols *ds = dmd::include (d, NULL);
 
     if (!ds)
       return;
@@ -2416,7 +2416,7 @@ layout_struct_initializer (StructDeclaration *sd)
 {
   StructLiteralExp *sle = StructLiteralExp::create (sd->loc, sd, NULL);
 
-  if (!sd->fill (sd->loc, *sle->elements, true))
+  if (!dmd::fill (sd, sd->loc, *sle->elements, true))
     gcc_unreachable ();
 
   sle->type = sd->type;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index acb7d98123f83f1bc90324fe0616009d2eaffb88..f660884c3b9590a9f318b1d3025a5c9b36456315 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-4ccb01fde535c7ad6ad4bdae2516c99420751814
+2b89c2909de239bd603d6f36379658fe902667db
 
 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 a2c940fce01520fb15f827e529d0131271268400..1e96152d04a7ab9aa84a3de2103e9cfe40ccacc3 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -41,6 +41,7 @@ Note that these groups have no strict meaning, the category assignments are a bi
 | [frontend.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/frontend.d)   | An interface for using DMD as a library                               |
 | [errors.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errors.d)       | Error reporting implementation                                        |
 | [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface                                             |
+| [sarif.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/sarif.d)         | Generates SARIF reports for errors and warnings.                      |
 | [target.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/target.d)       | Manage target-specific parameters for cross-compiling (for LDC/GDC)   |
 | [compiler.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/compiler.d)   | Describe a back-end compiler and implements compiler-specific actions |
 | [deps.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/deps.d)           | Implement the `-deps` and `-makedeps` switches                        |
@@ -199,13 +200,13 @@ Note that these groups have no strict meaning, the category assignments are a bi
 
 | File                                                                          | Purpose                                              |
 |-------------------------------------------------------------------------------|------------------------------------------------------|
-| [lib.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib.d)               | Abstract library class                               |
-| [libelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libelf.d)         | Library in ELF format (Unix)                         |
-| [libmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmach.d)       | Library in Mach-O format (macOS)                     |
-| [libmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/libmscoff.d)   | Library in COFF format (32/64-bit Windows)           |
-| [scanelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanelf.d)       | Extract symbol names from a library in ELF format    |
-| [scanmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmach.d)     | Extract symbol names from a library in Mach-O format |
-| [scanmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/scanmscoff.d) | Extract symbol names from a library in COFF format   |
+| [lib/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/package.d)               | Abstract library class                               |
+| [lib/elf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/elf.d)         | Library in ELF format (Unix)                         |
+| [lib/mach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/mach.d)       | Library in Mach-O format (macOS)                     |
+| [lib/mscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/mscoff.d)   | Library in COFF format (32/64-bit Windows)           |
+| [lib/scanelf.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanelf.d)       | Extract symbol names from a library in ELF format    |
+| [lib/scanmach.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanmach.d)     | Extract symbol names from a library in Mach-O format |
+| [lib/scanmscoff.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/lib/scanmscoff.d) | Extract symbol names from a library in COFF format   |
 
 ### Code generation / back-end interfacing
 
@@ -233,10 +234,10 @@ Note that these groups have no strict meaning, the category assignments are a bi
 
 | File                                                                              | Purpose                                                          |
 |-----------------------------------------------------------------------------------|------------------------------------------------------------------|
-| [cppmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmangle.d)       | C++ name mangling                                                |
-| [cppmanglewin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/cppmanglewin.d) | C++ name mangling for Windows                                    |
-| [basicmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/basicmangle.d)   | D name mangling for basic types                                  |
-| [dmangle.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dmangle.d)           | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
+| [mangle/cpp.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/cpp.d)       | C++ name mangling                                                |
+| [mangle/cppwin.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/cppwin.d) | C++ name mangling for Windows                                    |
+| [mangle/basic.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/basic.d)   | D name mangling for basic types                                  |
+| [mangle/package.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/mangle/package.d)           | D [name mangling](https://dlang.org/spec/abi.html#name_mangling) |
 
 ### Linking
 
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index f29755bbfdf669f3cac51e3c171078e8bf370f48..e778ed92cae8149212567d6b063ee67acbbc40ae 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -22,6 +22,7 @@ import dmd.dstruct;
 import dmd.dsymbol;
 import dmd.errors;
 import dmd.expression;
+import dmd.funcsem : overloadApply;
 import dmd.location;
 import dmd.tokens;
 
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 78cb87f2fe7d9b772bc950c9aa0d0da733e9063a..25f54b57c91d29e0e94a4895576a8d0768275a30 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -25,7 +25,7 @@ import dmd.declaration;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, determineFields, search, determineSize, include;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
@@ -99,7 +99,7 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
     StorageClass storage_class; ///
     uint structsize;            /// size of struct
     uint alignsize;             /// size of struct for alignment purposes
-    VarDeclarations fields;     /// VarDeclaration fields
+    VarDeclarations fields;     /// VarDeclaration fields including flattened AnonDeclaration members
     Dsymbol deferred;           /// any deferred semantic2() or semantic3() symbol
 
     /// specifies whether this is a D, C++, Objective-C or anonymous struct/class/interface
@@ -187,70 +187,12 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         return fields.length - isNested() - (vthis2 !is null);
     }
 
-    /***************************************
-     * Collect all instance fields, then determine instance size.
-     * Returns:
-     *      false if failed to determine the size.
-     */
-    extern (D) final bool determineSize(const ref Loc loc)
-    {
-        //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
-
-        // The previous instance size finalizing had:
-        if (type.ty == Terror || errors)
-            return false;   // failed already
-        if (sizeok == Sizeok.done)
-            return true;    // succeeded
-
-        if (!members)
-        {
-            .error(loc, "%s `%s` unknown size", kind, toPrettyChars);
-            return false;
-        }
-
-        if (_scope)
-            dsymbolSemantic(this, null);
-
-        // Determine the instance size of base class first.
-        if (auto cd = isClassDeclaration())
-        {
-            cd = cd.baseClass;
-            if (cd && !cd.determineSize(loc))
-                goto Lfail;
-        }
-
-        // Determine instance fields when sizeok == Sizeok.none
-        if (!this.determineFields())
-            goto Lfail;
-        if (sizeok != Sizeok.done)
-            finalizeSize();
-
-        // this aggregate type has:
-        if (type.ty == Terror)
-            return false;   // marked as invalid during the finalizing.
-        if (sizeok == Sizeok.done)
-            return true;    // succeeded to calculate instance size.
-
-    Lfail:
-        // There's unresolvable forward reference.
-        if (type != Type.terror)
-            error(loc, "%s `%s` no size because of forward reference", kind, toPrettyChars);
-        // Don't cache errors from speculative semantic, might be resolvable later.
-        // https://issues.dlang.org/show_bug.cgi?id=16574
-        if (!global.gag)
-        {
-            type = Type.terror;
-            errors = true;
-        }
-        return false;
-    }
-
     abstract void finalizeSize();
 
     override final uinteger_t size(const ref Loc loc)
     {
         //printf("+AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
-        bool ok = determineSize(loc);
+        bool ok = determineSize(this, loc);
         //printf("-AggregateDeclaration::size() %s, scope = %p, sizeok = %d\n", toChars(), _scope, sizeok);
         return ok ? structsize : SIZE_INVALID;
     }
@@ -336,161 +278,6 @@ extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         return errors;
     }
 
-    /***************************************
-     * Fill out remainder of elements[] with default initializers for fields[].
-     * Params:
-     *      loc         = location
-     *      elements    = explicit arguments which given to construct object.
-     *      ctorinit    = true if the elements will be used for default initialization.
-     * Returns:
-     *      false if any errors occur.
-     *      Otherwise, returns true and the missing arguments will be pushed in elements[].
-     */
-    final bool fill(const ref Loc loc, ref Expressions elements, bool ctorinit)
-    {
-        //printf("AggregateDeclaration::fill() %s\n", toChars());
-        assert(sizeok == Sizeok.done);
-        const nfields = nonHiddenFields();
-        bool errors = false;
-
-        size_t dim = elements.length;
-        elements.setDim(nfields);
-        foreach (size_t i; dim .. nfields)
-            elements[i] = null;
-
-        // Fill in missing any elements with default initializers
-        foreach (i; 0 .. nfields)
-        {
-            if (elements[i])
-                continue;
-
-            auto vd = fields[i];
-            auto vx = vd;
-            if (vd._init && vd._init.isVoidInitializer())
-                vx = null;
-
-            // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
-            size_t fieldi = i;
-            foreach (j; 0 .. nfields)
-            {
-                if (i == j)
-                    continue;
-                auto v2 = fields[j];
-                if (!vd.isOverlappedWith(v2))
-                    continue;
-
-                if (elements[j])
-                {
-                    vx = null;
-                    break;
-                }
-                if (v2._init && v2._init.isVoidInitializer())
-                    continue;
-
-                version (all)
-                {
-                    /* Prefer first found non-void-initialized field
-                     * union U { int a; int b = 2; }
-                     * U u;    // Error: overlapping initialization for field a and b
-                     */
-                    if (!vx)
-                    {
-                        vx = v2;
-                        fieldi = j;
-                    }
-                    else if (v2._init)
-                    {
-                        .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
-                        errors = true;
-                    }
-                }
-                else
-                {
-                    // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
-
-                    /* Prefer explicitly initialized field
-                     * union U { int a; int b = 2; }
-                     * U u;    // OK (u.b == 2)
-                     */
-                    if (!vx || !vx._init && v2._init)
-                    {
-                        vx = v2;
-                        fieldi = j;
-                    }
-                    else if (vx != vd && !vx.isOverlappedWith(v2))
-                    {
-                        // Both vx and v2 fills vd, but vx and v2 does not overlap
-                    }
-                    else if (vx._init && v2._init)
-                    {
-                        .error(loc, "overlapping default initialization for field `%s` and `%s`",
-                            v2.toChars(), vd.toChars());
-                        errors = true;
-                    }
-                    else
-                        assert(vx._init || !vx._init && !v2._init);
-                }
-            }
-            if (vx)
-            {
-                Expression e;
-                if (vx.type.size() == 0)
-                {
-                    e = null;
-                }
-                else if (vx._init)
-                {
-                    assert(!vx._init.isVoidInitializer());
-                    if (vx.inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
-                    {
-                        .error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
-                        errors = true;
-                    }
-                    else
-                        e = vx.getConstInitializer(false);
-                }
-                else
-                {
-                    if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
-                    {
-                        .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
-                            type.toChars(), vx.toChars());
-                        errors = true;
-                    }
-                    /* https://issues.dlang.org/show_bug.cgi?id=12509
-                     * Get the element of static array type.
-                     */
-                    Type telem = vx.type;
-                    if (telem.ty == Tsarray)
-                    {
-                        /* We cannot use Type::baseElemOf() here.
-                         * If the bottom of the Tsarray is an enum type, baseElemOf()
-                         * will return the base of the enum, and its default initializer
-                         * would be different from the enum's.
-                         */
-                        TypeSArray tsa;
-                        while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
-                            telem = tsa.next;
-                        if (telem.ty == Tvoid)
-                            telem = Type.tuns8.addMod(telem.mod);
-                    }
-                    if (telem.needsNested() && ctorinit)
-                        e = telem.defaultInit(loc);
-                    else
-                        e = telem.defaultInitLiteral(loc);
-                }
-                elements[fieldi] = e;
-            }
-        }
-        foreach (e; elements)
-        {
-            if (e && e.op == EXP.error)
-                return false;
-        }
-
-        return !errors;
-    }
-
     override final Type getType()
     {
         /* Apply storage classes to forward references. (Issue 22254)
@@ -793,6 +580,7 @@ public uint alignmember(structalign_t alignment, uint memalignsize, uint offset)
 /****************************************
  * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
  * Params:
+ *    loc           = source location for error messages
  *    nextoffset    = location just past the end of the previous field in the aggregate.
  *                    Updated to be just past the end of this field to be placed, i.e. the future nextoffset
  *    memsize       = size of field
@@ -805,8 +593,8 @@ public uint alignmember(structalign_t alignment, uint memalignsize, uint offset)
  *    aligned offset to place field at
  *
  */
-public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
-    structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow
+public uint placeField(Loc loc, ref uint nextoffset, uint memsize, uint memalignsize,
+    structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @trusted nothrow
 {
     static if (0)
     {
@@ -829,7 +617,12 @@ public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
     bool overflow;
     const sz = addu(memsize, actualAlignment, overflow);
     addu(ofs, sz, overflow);
-    if (overflow) assert(0);
+    if (overflow)
+    {
+        error(loc, "max object size %u exceeded from adding field size %u + alignment adjustment %u + field offset %u when placing field in aggregate",
+                uint.max, memsize, actualAlignment, ofs);
+        return 0;
+    }
 
     // Skip no-op for noreturn without custom aligment
     if (memalignsize != 0 || !alignment.isDefault())
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index c972f0a6631ffba505e089e7b377fb07ed042ee4..8fd12e1d168ad494d97e43c3b8812d7a998e842e 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -45,6 +45,7 @@ namespace dmd
 {
     FuncDeclaration *search_toString(StructDeclaration *sd);
     void semanticTypeInfoMembers(StructDeclaration *sd);
+    bool fill(StructDeclaration* sd, const Loc &loc, Expressions &elements, bool ctorinit);
 }
 
 enum class ClassKind : uint8_t
@@ -119,7 +120,6 @@ public:
     virtual Scope *newScope(Scope *sc);
     virtual void finalizeSize() = 0;
     uinteger_t size(const Loc &loc) override final;
-    bool fill(const Loc &loc, Expressions &elements, bool ctorinit);
     Type *getType() override final;
     bool isDeprecated() const override final; // is aggregate deprecated?
     bool isNested() const;
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index db14f9a1cc3f2111c2f00f6524ad7a52510a0b45..0b5cd9d41c5d042ee15ef090ffaac2a87c166fab 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -32,8 +32,7 @@ import dmd.declaration;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
-import dmd.errors;
+import dmd.dsymbolsem : setScope, addMember, include;
 import dmd.expression;
 import dmd.func;
 import dmd.globals;
@@ -73,14 +72,6 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
         this.decl = decl;
     }
 
-    Dsymbols* include(Scope* sc)
-    {
-        if (errors)
-            return null;
-
-        return decl;
-    }
-
     /****************************************
      * Create a new scope if one or more given attributes
      * are different from the sc's.
@@ -113,21 +104,13 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
         return sc2;
     }
 
-    /****************************************
-     * A hook point to supply scope for members.
-     * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
-     */
-    Scope* newScope(Scope* sc)
-    {
-        return sc;
-    }
 
     override void addComment(const(char)* comment)
     {
         //printf("AttribDeclaration::addComment %s\n", comment);
         if (comment)
         {
-            include(null).foreachDsymbol( s => s.addComment(comment) );
+            this.include(null).foreachDsymbol( s => s.addComment(comment) );
         }
     }
 
@@ -138,23 +121,23 @@ extern (C++) abstract class AttribDeclaration : Dsymbol
 
     override bool oneMember(out Dsymbol ps, Identifier ident)
     {
-        Dsymbols* d = include(null);
+        Dsymbols* d = this.include(null);
         return Dsymbol.oneMembers(d, ps, ident);
     }
 
     override final bool hasPointers()
     {
-        return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
+        return this.include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
     }
 
     override final bool hasStaticCtorOrDtor()
     {
-        return include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
+        return this.include(null).foreachDsymbol( (s) { return s.hasStaticCtorOrDtor(); } ) != 0;
     }
 
     override final void checkCtorConstInit()
     {
-        include(null).foreachDsymbol( s => s.checkCtorConstInit() );
+        this.include(null).foreachDsymbol( s => s.checkCtorConstInit() );
     }
 
     /****************************************
@@ -202,28 +185,6 @@ extern (C++) class StorageClassDeclaration : AttribDeclaration
         return new StorageClassDeclaration(stc, Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        StorageClass scstc = sc.stc;
-        /* These sets of storage classes are mutually exclusive,
-         * so choose the innermost or most recent one.
-         */
-        if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
-            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
-        if (stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
-            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
-        if (stc & (STC.const_ | STC.immutable_ | STC.manifest))
-            scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
-        if (stc & (STC.gshared | STC.shared_))
-            scstc &= ~(STC.gshared | STC.shared_);
-        if (stc & (STC.safe | STC.trusted | STC.system))
-            scstc &= ~(STC.safe | STC.trusted | STC.system);
-        scstc |= stc;
-        //printf("scstc = x%llx\n", scstc);
-        return createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
-            sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
-    }
-
     override final bool oneMember(out Dsymbol ps, Identifier ident)
     {
         bool t = Dsymbol.oneMembers(decl, ps, ident);
@@ -286,25 +247,6 @@ extern (C++) final class DeprecatedDeclaration : StorageClassDeclaration
         return new DeprecatedDeclaration(msg.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl));
     }
 
-    /**
-     * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
-     *
-     * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
-     * in any function overriding `newScope`), then set the `Scope`'s depdecl.
-     *
-     * Returns:
-     *   Always a new scope, to use for this `DeprecatedDeclaration`'s members.
-     */
-    override Scope* newScope(Scope* sc)
-    {
-        auto scx = super.newScope(sc);
-        // The enclosing scope is deprecated as well
-        if (scx == sc)
-            scx = sc.push();
-        scx.depdecl = this;
-        return scx;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -339,11 +281,6 @@ extern (C++) final class LinkDeclaration : AttribDeclaration
         return new LinkDeclaration(loc, linkage, Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        return createNewScope(sc, sc.stc, this.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
-            sc.aligndecl, sc.inlining);
-    }
 
     override const(char)* toChars() const
     {
@@ -386,12 +323,6 @@ extern (C++) final class CPPMangleDeclaration : AttribDeclaration
         return new CPPMangleDeclaration(loc, cppmangle, Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        return createNewScope(sc, sc.stc, LINK.cpp, cppmangle, sc.visibility, sc.explicitVisibility,
-            sc.aligndecl, sc.inlining);
-    }
-
     override const(char)* toChars() const
     {
         return toString().ptr;
@@ -462,18 +393,6 @@ extern (C++) final class CPPNamespaceDeclaration : AttribDeclaration
             this.loc, this.ident, this.exp, Dsymbol.arraySyntaxCopy(this.decl), this.cppnamespace);
     }
 
-    /**
-     * Returns:
-     *   A copy of the parent scope, with `this` as `namespace` and C++ linkage
-     */
-    override Scope* newScope(Scope* sc)
-    {
-        auto scx = sc.copy();
-        scx.linkage = LINK.cpp;
-        scx.namespace = this;
-        return scx;
-    }
-
     override const(char)* toChars() const
     {
         return toString().ptr;
@@ -545,13 +464,6 @@ extern (C++) final class VisibilityDeclaration : AttribDeclaration
             return new VisibilityDeclaration(this.loc, visibility, Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        if (pkg_identifiers)
-            dsymbolSemantic(this, sc);
-        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
-    }
-
     override const(char)* kind() const
     {
         return "visibility attribute";
@@ -621,11 +533,6 @@ extern (C++) final class AlignDeclaration : AttribDeclaration
             Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, this, sc.inlining);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -694,17 +601,6 @@ extern (C++) final class PragmaDeclaration : AttribDeclaration
         return new PragmaDeclaration(loc, ident, Expression.arraySyntaxCopy(args), Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        if (ident == Id.Pinline)
-        {
-            // We keep track of this pragma inside scopes,
-            // then it's evaluated on demand in function semantic
-            return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, this);
-        }
-        return sc;
-    }
-
     override const(char)* kind() const
     {
         return "pragma";
@@ -757,18 +653,6 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
         }
     }
 
-    // Decide if 'then' or 'else' code should be included
-    override Dsymbols* include(Scope* sc)
-    {
-        //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
-
-        if (errors)
-            return null;
-
-        assert(condition);
-        return condition.include(_scope ? _scope : sc) ? decl : elsedecl;
-    }
-
     override final void addComment(const(char)* comment)
     {
         /* Because addComment is called by the parser, if we called
@@ -797,8 +681,8 @@ extern (C++) class ConditionalDeclaration : AttribDeclaration
 extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
 {
     ScopeDsymbol scopesym;          /// enclosing symbol (e.g. module) where symbols will be inserted
-    private bool addisdone = false; /// true if members have been added to scope
-    private bool onStack = false;   /// true if a call to `include` is currently active
+    bool addisdone = false; /// true if members have been added to scope
+    bool onStack = false;   /// true if a call to `include` is currently active
 
     extern (D) this(const ref Loc loc, Condition condition, Dsymbols* decl, Dsymbols* elsedecl) @safe
     {
@@ -812,42 +696,6 @@ extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
         return new StaticIfDeclaration(loc, condition.syntaxCopy(), Dsymbol.arraySyntaxCopy(decl), Dsymbol.arraySyntaxCopy(elsedecl));
     }
 
-    /****************************************
-     * Different from other AttribDeclaration subclasses, include() call requires
-     * the completion of addMember and setScope phases.
-     */
-    override Dsymbols* include(Scope* sc)
-    {
-        //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
-
-        if (errors || onStack)
-            return null;
-        onStack = true;
-        scope(exit) onStack = false;
-
-        if (sc && condition.inc == Include.notComputed)
-        {
-            assert(scopesym); // addMember is already done
-            assert(_scope); // setScope is already done
-            Dsymbols* d = ConditionalDeclaration.include(_scope);
-            if (d && !addisdone)
-            {
-                // Add members lazily.
-                d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
-
-                // Set the member scopes lazily.
-                d.foreachDsymbol( s => s.setScope(_scope) );
-
-                addisdone = true;
-            }
-            return d;
-        }
-        else
-        {
-            return ConditionalDeclaration.include(sc);
-        }
-    }
-
     override const(char)* kind() const
     {
         return "static if";
@@ -914,43 +762,6 @@ extern (C++) final class StaticForeachDeclaration : AttribDeclaration
         return false;
     }
 
-    override Dsymbols* include(Scope* sc)
-    {
-        if (errors || onStack)
-            return null;
-        if (cached)
-        {
-            assert(!onStack);
-            return cache;
-        }
-        onStack = true;
-        scope(exit) onStack = false;
-
-        if (_scope)
-        {
-            sfe.prepare(_scope); // lower static foreach aggregate
-        }
-        if (!sfe.ready())
-        {
-            return null; // TODO: ok?
-        }
-
-        // expand static foreach
-        import dmd.statementsem: makeTupleForeach;
-        Dsymbols* d = makeTupleForeach(_scope, true, true, sfe.aggrfe, decl, sfe.needExpansion).decl;
-        if (d) // process generated declarations
-        {
-            // Add members lazily.
-            d.foreachDsymbol( s => s.addMember(_scope, scopesym) );
-
-            // Set the member scopes lazily.
-            d.foreachDsymbol( s => s.setScope(_scope) );
-        }
-        cached = true;
-        cache = d;
-        return d;
-    }
-
     override void addComment(const(char)* comment)
     {
         // do nothing
@@ -1005,13 +816,6 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
         sym.symtab = new DsymbolTable();
     }
 
-    /**************************************
-     * Use the ForwardingScopeDsymbol as the parent symbol for members.
-     */
-    override Scope* newScope(Scope* sc)
-    {
-        return sc.push(sym);
-    }
 
     override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
     {
@@ -1024,7 +828,6 @@ extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
     }
 }
 
-
 /***********************************************************
  * Mixin declarations, like:
  *      mixin("int x");
@@ -1088,18 +891,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
         return new UserAttributeDeclaration(Expression.arraySyntaxCopy(this.atts), Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override Scope* newScope(Scope* sc)
-    {
-        Scope* sc2 = sc;
-        if (atts && atts.length)
-        {
-            // create new one for changes
-            sc2 = sc.copy();
-            sc2.userAttribDecl = this;
-        }
-        return sc2;
-    }
-
     extern (D) static Expressions* concat(Expressions* udas1, Expressions* udas2)
     {
         Expressions* udas;
@@ -1128,70 +919,6 @@ extern (C++) final class UserAttributeDeclaration : AttribDeclaration
     {
         v.visit(this);
     }
-
-    /**
-     * Check if the provided expression references `core.attribute.gnuAbiTag`
-     *
-     * This should be called after semantic has been run on the expression.
-     * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
-     *
-     * Params:
-     *   e = Expression to check (usually from `UserAttributeDeclaration.atts`)
-     *
-     * Returns:
-     *   `true` if the expression references the compiler-recognized `gnuAbiTag`
-     */
-    static bool isGNUABITag(Expression e)
-    {
-        if (global.params.cplusplus < CppStdRevision.cpp11)
-            return false;
-
-        auto ts = e.type ? e.type.isTypeStruct() : null;
-        if (!ts)
-            return false;
-        if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
-            return false;
-        // Can only be defined in druntime
-        Module m = ts.sym.parent.isModule();
-        if (!m || !m.isCoreModule(Id.attribute))
-            return false;
-        return true;
-    }
-
-    /**
-     * Called from a symbol's semantic to check if `gnuAbiTag` UDA
-     * can be applied to them
-     *
-     * Directly emits an error if the UDA doesn't work with this symbol
-     *
-     * Params:
-     *   sym = symbol to check for `gnuAbiTag`
-     *   linkage = Linkage of the symbol (Declaration.link or sc.link)
-     */
-    static void checkGNUABITag(Dsymbol sym, LINK linkage)
-    {
-        if (global.params.cplusplus < CppStdRevision.cpp11)
-            return;
-
-        foreachUdaNoSemantic(sym, (exp) {
-            if (isGNUABITag(exp))
-            {
-                if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
-                {
-                    .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
-                    sym.errors = true;
-                }
-                else if (linkage != LINK.cpp)
-                {
-                    .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
-                    sym.errors = true;
-                }
-                // Only one `@gnuAbiTag` is allowed by semantic2
-                return 1; // break
-            }
-            return 0; // continue
-        });
-    }
 }
 
 /**
@@ -1243,7 +970,6 @@ int foreachUdaNoSemantic(Dsymbol sym, int delegate(Expression) dg)
     return 0;
 }
 
-
 /**
  * Returns: true if the given expression is an enum from `core.attribute` named `id`
  */
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index d4c41ec94f36f3f3ebc61592cb3c5c7305ec7b06..d2d18dba18d94b5df014b794d0f2ff1aab247be0 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -28,9 +28,6 @@ class AttribDeclaration : public Dsymbol
 {
 public:
     Dsymbols *decl;     // array of Dsymbol's
-
-    virtual Dsymbols *include(Scope *sc);
-    virtual Scope *newScope(Scope *sc);
     void addComment(const utf8_t *comment) override;
     const char *kind() const override;
     bool oneMember(Dsymbol *&ps, Identifier *ident) override;
@@ -48,7 +45,6 @@ public:
     StorageClass stc;
 
     StorageClassDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     bool oneMember(Dsymbol *&ps, Identifier *ident) override final;
     StorageClassDeclaration *isStorageClassDeclaration() override { return this; }
 
@@ -62,7 +58,6 @@ public:
     const char *msgstr;
 
     DeprecatedDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -73,7 +68,6 @@ public:
 
     static LinkDeclaration *create(const Loc &loc, LINK p, Dsymbols *decl);
     LinkDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *toChars() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -84,7 +78,6 @@ public:
     CPPMANGLE cppmangle;
 
     CPPMangleDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *toChars() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -95,7 +88,6 @@ public:
     Expression *exp;
 
     CPPNamespaceDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *toChars() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -107,7 +99,6 @@ public:
     DArray<Identifier*> pkg_identifiers;
 
     VisibilityDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *kind() const override;
     const char *toPrettyChars(bool unused) override;
     VisibilityDeclaration *isVisibilityDeclaration() override { return this; }
@@ -121,7 +112,6 @@ public:
     structalign_t salign;
 
     AlignDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -146,7 +136,6 @@ public:
     Expressions *args;          // array of Expression's
 
     PragmaDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -159,7 +148,6 @@ public:
 
     ConditionalDeclaration *syntaxCopy(Dsymbol *s) override;
     bool oneMember(Dsymbol *&ps, Identifier *ident) override final;
-    Dsymbols *include(Scope *sc) override;
     void addComment(const utf8_t *comment) override final;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -172,7 +160,6 @@ public:
     d_bool onStack;
 
     StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
-    Dsymbols *include(Scope *sc) override;
     StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
@@ -189,7 +176,6 @@ public:
 
     StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
     bool oneMember(Dsymbol *&ps, Identifier *ident) override;
-    Dsymbols *include(Scope *sc) override;
     void addComment(const utf8_t *comment) override;
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
@@ -200,7 +186,6 @@ class ForwardingAttribDeclaration final : public AttribDeclaration
 public:
     ForwardingScopeDsymbol *sym;
 
-    Scope *newScope(Scope *sc) override;
     ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -230,7 +215,6 @@ public:
     Expressions *atts;
 
     UserAttributeDeclaration *syntaxCopy(Dsymbol *s) override;
-    Scope *newScope(Scope *sc) override;
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index 75293bce0fcde216cf2bffa600ba0810f4ca990b..dc3e379e8d4be878b7c76ef73d5e1fc1a651d01d 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -80,26 +80,25 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
         void visitExp(ExpStatement s)
         {
             result = BE.fallthru;
-            if (s.exp)
+            if (!s.exp)
+                return;
+
+            if (s.exp.op == EXP.halt)
             {
-                if (s.exp.op == EXP.halt)
+                result = BE.halt;
+                return;
+            }
+            if (AssertExp a = s.exp.isAssertExp())
+            {
+                if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
                 {
                     result = BE.halt;
                     return;
                 }
-                if (AssertExp a = s.exp.isAssertExp())
-                {
-                    if (a.e1.toBool().hasValue(false)) // if it's an assert(0)
-                    {
-                        result = BE.halt;
-                        return;
-                    }
-                }
-                if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
-                    result = BE.halt;
-
-                result |= canThrow(s.exp, func, eSink);
             }
+            if (s.exp.type && s.exp.type.toBasetype().isTypeNoreturn())
+                result = BE.halt;
+            result |= canThrow(s.exp, func, eSink);
         }
 
         void visitDtorExp(DtorExpStatement s)
@@ -120,39 +119,39 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
             Statement slast = null;
             foreach (s; *cs.statements)
             {
-                if (s)
+                if (!s)
+                    continue;
+
+                //printf("result = x%x\n", result);
+                //printf("s: %s\n", s.toChars());
+                if (result & BE.fallthru && slast)
                 {
-                    //printf("result = x%x\n", result);
-                    //printf("s: %s\n", s.toChars());
-                    if (result & BE.fallthru && slast)
+                    slast = slast.last();
+                    if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
                     {
-                        slast = slast.last();
-                        if (slast && (slast.isCaseStatement() || slast.isDefaultStatement()) && (s.isCaseStatement() || s.isDefaultStatement()))
+                        // Allow if last case/default was empty
+                        CaseStatement sc = slast.isCaseStatement();
+                        DefaultStatement sd = slast.isDefaultStatement();
+                        auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
+
+                        if (sl && (!sl.hasCode() || sl.isErrorStatement()))
                         {
-                            // Allow if last case/default was empty
-                            CaseStatement sc = slast.isCaseStatement();
-                            DefaultStatement sd = slast.isDefaultStatement();
-                            auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
-
-                            if (sl && (!sl.hasCode() || sl.isErrorStatement()))
-                            {
-                            }
-                            else if (func.getModule().filetype != FileType.c)
-                            {
-                                const(char)* gototype = s.isCaseStatement() ? "case" : "default";
-                                // https://issues.dlang.org/show_bug.cgi?id=22999
-                                global.errorSink.error(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype);
-                            }
+                        }
+                        else if (func.getModule().filetype != FileType.c)
+                        {
+                            const(char)* gototype = s.isCaseStatement() ? "case" : "default";
+                            // https://issues.dlang.org/show_bug.cgi?id=22999
+                            global.errorSink.error(s.loc, "switch case fallthrough - use 'goto %s;' if intended", gototype);
                         }
                     }
+                }
 
-                    if ((result & BE.fallthru) || s.comeFrom())
-                    {
-                        result &= ~BE.fallthru;
-                        result |= blockExit(s, func, eSink);
-                    }
-                    slast = s;
+                if ((result & BE.fallthru) || s.comeFrom())
+                {
+                    result &= ~BE.fallthru;
+                    result |= blockExit(s, func, eSink);
                 }
+                slast = s;
             }
         }
 
@@ -161,13 +160,12 @@ int blockExit(Statement s, FuncDeclaration func, ErrorSink eSink)
             result = BE.fallthru;
             foreach (s; *uls.statements)
             {
-                if (s)
-                {
-                    int r = blockExit(s, func, eSink);
-                    result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
-                    if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
-                        result &= ~BE.fallthru;
-                }
+                if (!s)
+                    continue;
+                int r = blockExit(s, func, eSink);
+                result |= r & ~(BE.break_ | BE.continue_ | BE.fallthru);
+                if ((r & (BE.fallthru | BE.continue_ | BE.break_)) == 0)
+                    result &= ~BE.fallthru;
             }
         }
 
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index dfc91e1c85285a6c4fc99532d17c1bc22fea6747..caf58a20634cc1853707bf937f9a7d67a8bb5475 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -20,8 +20,10 @@ import dmd.astenums;
 import dmd.blockexit : BE, checkThrow;
 import dmd.declaration;
 import dmd.dsymbol;
+import dmd.dsymbolsem : include;
 import dmd.errorsink;
 import dmd.expression;
+import dmd.expressionsem : errorSupplementalInferredAttr;
 import dmd.func;
 import dmd.globals;
 import dmd.init;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 8746baacd0ef6bd30ba721ee8f6d5c7210475a5e..bbfb1ee9f87d175e4aca052d4aeb25f4e3de74c0 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -51,7 +51,7 @@ import dmd.tokens;
  * Returns:
  *      merged storage class
  */
-StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
+StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure @safe
 {
     if (!f)
         return s1;
@@ -101,46 +101,45 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
  */
 FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc)
 {
-    if (Dsymbol assign = search_function(ad, Id.assign))
-    {
-        /* check identity opAssign exists
-         */
-        scope er = new NullExp(ad.loc, ad.type);    // dummy rvalue
-        scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
-        el.type = ad.type;
-        const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
-        sc = sc.push();
-        sc.tinst = null;
-        sc.minst = null;
+    Dsymbol assign = search_function(ad, Id.assign);
+    if (!assign)
+        return null;
 
-        auto a = new Expressions(1);
-        (*a)[0] = er;
-        auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
-        if (!f)
-        {
-            (*a)[0] = el;
-            f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
-        }
+    /* check identity opAssign exists
+     */
+    scope er = new NullExp(ad.loc, ad.type);    // dummy rvalue
+    scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+    el.type = ad.type;
+    const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it.
+    sc = sc.push();
+    sc.tinst = null;
+    sc.minst = null;
 
-        sc = sc.pop();
-        global.endGagging(errors);
-        if (f)
-        {
-            if (f.errors)
-                return null;
-            auto fparams = f.getParameterList();
-            if (fparams.length)
-            {
-                auto fparam0 = fparams[0];
-                if (fparam0.type.toDsymbol(null) != ad)
-                    f = null;
-            }
-        }
-        // BUGS: This detection mechanism cannot find some opAssign-s like follows:
-        // struct S { void opAssign(ref immutable S) const; }
-        return f;
+    auto a = new Expressions(1);
+    (*a)[0] = er;
+    auto f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
+    if (!f)
+    {
+        (*a)[0] = el;
+        f = resolveFuncCall(ad.loc, sc, assign, null, ad.type, ArgumentList(a), FuncResolveFlag.quiet);
     }
-    return null;
+
+    sc = sc.pop();
+    global.endGagging(errors);
+    if (!f)
+        return null;
+    if (f.errors)
+        return null;
+    auto fparams = f.getParameterList();
+    if (fparams.length)
+    {
+        auto fparam0 = fparams[0];
+        if (fparam0.type.toDsymbol(null) != ad)
+            f = null;
+    }
+    // BUGS: This detection mechanism cannot find some opAssign-s like follows:
+    // struct S { void opAssign(ref immutable S) const; }
+    return f;
 }
 
 /*******************************************
@@ -418,16 +417,26 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
  */
 bool needOpEquals(StructDeclaration sd)
 {
+    bool dontneed()
+    {
+        //printf("\tdontneed\n");
+        return false;
+    }
+    bool need()
+    {
+        //printf("\tneed\n");
+        return true;
+    }
     //printf("StructDeclaration::needOpEquals() %s\n", sd.toChars());
     if (sd.isUnionDeclaration())
     {
         /* If a union has only one field, treat it like a struct
          */
         if (sd.fields.length != 1)
-            goto Ldontneed;
+            return dontneed();
     }
     if (sd.hasIdentityEquals)
-        goto Lneed;
+        return need();
     /* If any of the fields has an opEquals, then we
      * need it too.
      */
@@ -444,28 +453,23 @@ bool needOpEquals(StructDeclaration sd)
             if (ts.sym.isUnionDeclaration() && ts.sym.fields.length != 1)
                 continue;
             if (needOpEquals(ts.sym))
-                goto Lneed;
+                return need();
         }
         if (tvbase.isFloating())
         {
             // This is necessray for:
             //  1. comparison of +0.0 and -0.0 should be true.
             //  2. comparison of NANs should be false always.
-            goto Lneed;
+            return need();
         }
         if (tvbase.ty == Tarray)
-            goto Lneed;
+            return need();
         if (tvbase.ty == Taarray)
-            goto Lneed;
+            return need();
         if (tvbase.ty == Tclass)
-            goto Lneed;
+            return need();
     }
-Ldontneed:
-    //printf("\tdontneed\n");
-    return false;
-Lneed:
-    //printf("\tneed\n");
-    return true;
+    return dontneed();
 }
 
 /*******************************************
@@ -478,48 +482,50 @@ Lneed:
 private FuncDeclaration hasIdentityOpEquals(AggregateDeclaration ad, Scope* sc)
 {
     FuncDeclaration f;
-    if (Dsymbol eq = search_function(ad, Id.eq))
+    Dsymbol eq = search_function(ad, Id.eq);
+    if (!eq)
+        return null;
+
+    /* check identity opEquals exists
+     */
+    scope er = new NullExp(ad.loc, null); // dummy rvalue
+    scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
+    auto a = new Expressions(1);
+
+    bool hasIt(Type tthis)
     {
-        /* check identity opEquals exists
-         */
-        scope er = new NullExp(ad.loc, null); // dummy rvalue
-        scope el = new IdentifierExp(ad.loc, Id.p); // dummy lvalue
-        auto a = new Expressions(1);
+        const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it
+        sc = sc.push();
+        sc.tinst = null;
+        sc.minst = null;
 
-        bool hasIt(Type tthis)
+        FuncDeclaration rfc(Expression e)
         {
-            const errors = global.startGagging(); // Do not report errors, even if the template opAssign fbody makes it
-            sc = sc.push();
-            sc.tinst = null;
-            sc.minst = null;
-
-            FuncDeclaration rfc(Expression e)
-            {
-                (*a)[0] = e;
-                (*a)[0].type = tthis;
-                return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet);
-            }
+            (*a)[0] = e;
+            (*a)[0].type = tthis;
+            return resolveFuncCall(ad.loc, sc, eq, null, tthis, ArgumentList(a), FuncResolveFlag.quiet);
+        }
 
-            f = rfc(er);
-            if (!f)
-                f = rfc(el);
+        f = rfc(er);
+        if (!f)
+            f = rfc(el);
 
-            sc = sc.pop();
-            global.endGagging(errors);
+        sc = sc.pop();
+        global.endGagging(errors);
 
-            return f !is null;
-        }
+        return f !is null;
+    }
 
-        if (hasIt(ad.type)               ||
-            hasIt(ad.type.constOf())     ||
-            hasIt(ad.type.immutableOf()) ||
-            hasIt(ad.type.sharedOf())    ||
-            hasIt(ad.type.sharedConstOf()))
-        {
-            if (f.errors)
-                return null;
-        }
+    if (hasIt(ad.type)               ||
+        hasIt(ad.type.constOf())     ||
+        hasIt(ad.type.immutableOf()) ||
+        hasIt(ad.type.sharedOf())    ||
+        hasIt(ad.type.sharedConstOf()))
+    {
+        if (f.errors)
+            return null;
     }
+
     return f;
 }
 
@@ -732,7 +738,7 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
     Expression e2 = new IdentifierExp(loc, Id.p);
     Expression e = new CallExp(loc, new DotIdExp(loc, e1, Id.cmp), e2);
     fop.fbody = new ReturnStatement(loc, e);
-    uint errors = global.startGagging(); // Do not report errors
+    const errors = global.startGagging(); // Do not report errors
     Scope* sc2 = sc.push();
     sc2.stc = 0;
     sc2.linkage = LINK.d;
@@ -757,11 +763,21 @@ FuncDeclaration buildXopCmp(StructDeclaration sd, Scope* sc)
  */
 private bool needToHash(StructDeclaration sd)
 {
+    bool dontneed()
+    {
+        //printf("\tdontneed\n");
+        return false;
+    }
+    bool need()
+    {
+        //printf("\tneed\n");
+        return true;
+    }
     //printf("StructDeclaration::needToHash() %s\n", sd.toChars());
     if (sd.isUnionDeclaration())
-        goto Ldontneed;
+        return dontneed();
     if (sd.xhash)
-        goto Lneed;
+        return need();
 
     /* If any of the fields has an toHash, then we
      * need it too.
@@ -779,28 +795,23 @@ private bool needToHash(StructDeclaration sd)
             if (ts.sym.isUnionDeclaration())
                 continue;
             if (needToHash(ts.sym))
-                goto Lneed;
+                return need();
         }
         if (tvbase.isFloating())
         {
             /* This is necessary because comparison of +0.0 and -0.0 should be true,
              * i.e. not a bit compare.
              */
-            goto Lneed;
+            return need();
         }
         if (tvbase.ty == Tarray)
-            goto Lneed;
+            return need();
         if (tvbase.ty == Taarray)
-            goto Lneed;
+            return need();
         if (tvbase.ty == Tclass)
-            goto Lneed;
+            return need();
     }
-Ldontneed:
-    //printf("\tdontneed\n");
-    return false;
-Lneed:
-    //printf("\tneed\n");
-    return true;
+    return dontneed();
 }
 
 /******************************************
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index f3801cb69cae2c00d4c163f83e8ee5579c711618..7e5c47409e36ac32980fb62fd7172fdc1482ade9 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -247,7 +247,7 @@ struct OutBuffer
     /**
      * Writes a 16 bit value, no reserve check.
      */
-    nothrow
+    nothrow @safe
     void write16n(int v)
     {
         auto x = cast(ushort) v;
@@ -367,7 +367,7 @@ struct OutBuffer
     }
 
     // Position buffer to accept the specified number of bytes at offset
-    void position(size_t where, size_t nbytes) nothrow
+    void position(size_t where, size_t nbytes) nothrow @safe
     {
         if (where + nbytes > data.length)
         {
@@ -785,10 +785,11 @@ struct OutBuffer
 
     Returns: `true` iff the operation succeeded.
     */
-    extern(D) bool moveToFile(const char* filename) @system
+    extern(D) bool moveToFile(const char[] filename) @system
     {
         bool result = true;
-        const bool identical = this[] == FileMapping!(const ubyte)(filename)[];
+        const filenameZ = (filename ~ "\0").ptr;
+        const bool identical = this[] == FileMapping!(const ubyte)(filenameZ)[];
 
         if (fileMapping && fileMapping.active)
         {
@@ -801,7 +802,7 @@ struct OutBuffer
             {
                 // Resize to fit to get rid of the slack bytes at the end
                 fileMapping.resize(offset);
-                result = fileMapping.moveToFile(filename);
+                result = fileMapping.moveToFile(filenameZ);
             }
             // Can't call destroy() here because the file mapping is already closed.
             data = null;
@@ -810,12 +811,12 @@ struct OutBuffer
         else
         {
             if (!identical)
-                writeFile(filename, this[]);
+                writeFile(filenameZ, this[]);
             destroy();
         }
 
         return identical
-            ? result && touchFile(filename)
+            ? result && touchFile(filenameZ)
             : result;
     }
 }
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 265492f1a62daffb43d65a4c89961bce3659adad..cffc412367d26ec5601130d9857004f653752998 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -24,7 +24,7 @@ import dmd.dscope;
 import dmd.dsymbol;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
+import dmd.expressionsem : expressionSemantic, evalStaticCondition, resolveProperties;
 import dmd.globals;
 import dmd.identifier;
 import dmd.location;
@@ -160,34 +160,33 @@ extern (C++) final class StaticForeach : RootObject
         sc = sc.endCTFE();
         el = el.optimize(WANTvalue);
         el = el.ctfeInterpret();
-        if (el.op == EXP.int64)
+        if (el.op != EXP.int64)
         {
-            Expressions *es = void;
-            if (auto ale = aggr.isArrayLiteralExp())
-            {
-                // Directly use the elements of the array for the TupleExp creation
-                es = ale.elements;
-            }
-            else
-            {
-                const length = cast(size_t)el.toInteger();
-                es = new Expressions(length);
-                foreach (i; 0 .. length)
-                {
-                    auto index = new IntegerExp(loc, i, Type.tsize_t);
-                    auto value = new IndexExp(aggr.loc, aggr, index);
-                    (*es)[i] = value;
-                }
-            }
-            aggrfe.aggr = new TupleExp(aggr.loc, es);
-            aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
-            aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
-            aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
+            aggrfe.aggr = ErrorExp.get();
+            return;
+        }
+
+        Expressions *es;
+        if (auto ale = aggr.isArrayLiteralExp())
+        {
+            // Directly use the elements of the array for the TupleExp creation
+            es = ale.elements;
         }
         else
         {
-            aggrfe.aggr = ErrorExp.get();
+            const length = cast(size_t)el.toInteger();
+            es = new Expressions(length);
+            foreach (i; 0 .. length)
+            {
+                auto index = new IntegerExp(loc, i, Type.tsize_t);
+                auto value = new IndexExp(aggr.loc, aggr, index);
+                (*es)[i] = value;
+            }
         }
+        aggrfe.aggr = new TupleExp(aggr.loc, es);
+        aggrfe.aggr = aggrfe.aggr.expressionSemantic(sc);
+        aggrfe.aggr = aggrfe.aggr.optimize(WANTvalue);
+        aggrfe.aggr = aggrfe.aggr.ctfeInterpret();
     }
 
     /*****************************************
@@ -383,7 +382,7 @@ extern (C++) final class StaticForeach : RootObject
 
         // Run 'typeof' gagged to avoid duplicate errors and if it fails just create
         // an empty foreach to expose them.
-        uint olderrors = global.startGagging();
+        const olderrors = global.startGagging();
         ety = ety.typeSemantic(aloc, sc);
         if (global.endGagging(olderrors))
             s2.push(createForeach(aloc, pparams[1], null));
@@ -571,31 +570,32 @@ extern (C++) final class DebugCondition : DVCondition
     override int include(Scope* sc)
     {
         //printf("DebugCondition::include() level = %d, debuglevel = %d\n", level, global.params.debuglevel);
-        if (inc == Include.notComputed)
+        if (inc != Include.notComputed)
         {
-            inc = Include.no;
-            bool definedInModule = false;
-            if (ident)
+            return inc == Include.yes;
+        }
+        inc = Include.no;
+        bool definedInModule = false;
+        if (ident)
+        {
+            if (mod.debugids && findCondition(*mod.debugids, ident))
             {
-                if (mod.debugids && findCondition(*mod.debugids, ident))
-                {
-                    inc = Include.yes;
-                    definedInModule = true;
-                }
-                else if (findCondition(global.debugids, ident))
-                    inc = Include.yes;
-                else
-                {
-                    if (!mod.debugidsNot)
-                        mod.debugidsNot = new Identifiers();
-                    mod.debugidsNot.push(ident);
-                }
+                inc = Include.yes;
+                definedInModule = true;
             }
-            else if (level <= global.params.debuglevel || level <= mod.debuglevel)
+            else if (findCondition(global.debugids, ident))
                 inc = Include.yes;
-            if (!definedInModule)
-                printDepsConditional(sc, this, "depsDebug ");
+            else
+            {
+                if (!mod.debugidsNot)
+                    mod.debugidsNot = new Identifiers();
+                mod.debugidsNot.push(ident);
+            }
         }
+        else if (level <= global.params.debuglevel || level <= mod.debuglevel)
+            inc = Include.yes;
+        if (!definedInModule)
+            printDepsConditional(sc, this, "depsDebug ");
         return (inc == Include.yes);
     }
 
@@ -852,34 +852,36 @@ extern (C++) final class VersionCondition : DVCondition
     {
         //printf("VersionCondition::include() level = %d, versionlevel = %d\n", level, global.params.versionlevel);
         //if (ident) printf("\tident = '%s'\n", ident.toChars());
-        if (inc == Include.notComputed)
+        if (inc != Include.notComputed)
         {
-            inc = Include.no;
-            bool definedInModule = false;
-            if (ident)
+            return inc == Include.yes;
+        }
+
+        inc = Include.no;
+        bool definedInModule = false;
+        if (ident)
+        {
+            if (mod.versionids && findCondition(*mod.versionids, ident))
             {
-                if (mod.versionids && findCondition(*mod.versionids, ident))
-                {
-                    inc = Include.yes;
-                    definedInModule = true;
-                }
-                else if (findCondition(global.versionids, ident))
-                    inc = Include.yes;
-                else
-                {
-                    if (!mod.versionidsNot)
-                        mod.versionidsNot = new Identifiers();
-                    mod.versionidsNot.push(ident);
-                }
+                inc = Include.yes;
+                definedInModule = true;
             }
-            else if (level <= global.params.versionlevel || level <= mod.versionlevel)
+            else if (findCondition(global.versionids, ident))
                 inc = Include.yes;
-            if (!definedInModule &&
-                (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
+            else
             {
-                printDepsConditional(sc, this, "depsVersion ");
+                if (!mod.versionidsNot)
+                    mod.versionidsNot = new Identifiers();
+                mod.versionidsNot.push(ident);
             }
         }
+        else if (level <= global.params.versionlevel || level <= mod.versionlevel)
+            inc = Include.yes;
+        if (!definedInModule &&
+            (!ident || (!isReserved(ident.toString()) && ident != Id._unittest && ident != Id._assert)))
+        {
+            printDepsConditional(sc, this, "depsVersion ");
+        }
         return (inc == Include.yes);
     }
 
@@ -927,31 +929,33 @@ extern (C++) final class StaticIfCondition : Condition
             return 0;
         }
 
-        if (inc == Include.notComputed)
+        if (inc != Include.notComputed)
         {
-            if (!sc)
-            {
-                error(loc, "`static if` conditional cannot be at global scope");
-                inc = Include.no;
-                return 0;
-            }
+            return inc == Include.yes;
+        }
 
-            import dmd.staticcond;
-            bool errors;
+        if (!sc)
+        {
+            error(loc, "`static if` conditional cannot be at global scope");
+            inc = Include.no;
+            return 0;
+        }
 
-            bool result = evalStaticCondition(sc, exp, exp, errors);
+        import dmd.staticcond;
+        bool errors;
 
-            // Prevent repeated condition evaluation.
-            // See: fail_compilation/fail7815.d
-            if (inc != Include.notComputed)
-                return (inc == Include.yes);
-            if (errors)
-                return errorReturn();
-            if (result)
-                inc = Include.yes;
-            else
-                inc = Include.no;
-        }
+        bool result = evalStaticCondition(sc, exp, exp, errors);
+
+        // Prevent repeated condition evaluation.
+        // See: fail_compilation/fail7815.d
+        if (inc != Include.notComputed)
+            return (inc == Include.yes);
+        if (errors)
+            return errorReturn();
+        if (result)
+            inc = Include.yes;
+        else
+            inc = Include.no;
         return (inc == Include.yes);
     }
 
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index 7cb4011e9203bcdd4aa0a280d873ae501a80b28f..b74b11b67341b7a8f2c31dfffea9568f365bdc06 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -45,24 +45,24 @@ Expressions* getAttributes(UserAttributeDeclaration a)
 }
 
 /***********************************************************
- * cppmangle.d
+ * mangle/cpp.d
  */
 const(char)* toCppMangleItanium(Dsymbol s)
 {
-    import dmd.cppmangle;
-    return dmd.cppmangle.toCppMangleItanium(s);
+    import dmd.mangle.cpp;
+    return dmd.mangle.cpp.toCppMangleItanium(s);
 }
 
 const(char)* cppTypeInfoMangleItanium(Dsymbol s)
 {
-    import dmd.cppmangle;
-    return dmd.cppmangle.cppTypeInfoMangleItanium(s);
+    import dmd.mangle.cpp;
+    return dmd.mangle.cpp.cppTypeInfoMangleItanium(s);
 }
 
 const(char)* cppThunkMangleItanium(FuncDeclaration fd, int offset)
 {
-    import dmd.cppmangle;
-    return dmd.cppmangle.cppThunkMangleItanium(fd, offset);
+    import dmd.mangle.cpp;
+    return dmd.mangle.cpp.cppThunkMangleItanium(fd, offset);
 }
 
 /***********************************************************
@@ -75,36 +75,36 @@ Expression ctfeInterpret(Expression e)
 }
 
 /***********************************************************
- * dmangle.d
+ * mangle/package.d
  */
 const(char)* mangleExact(FuncDeclaration fd)
 {
-    import dmd.dmangle;
-    return dmd.dmangle.mangleExact(fd);
+    import dmd.mangle;
+    return dmd.mangle.mangleExact(fd);
 }
 
 void mangleToBuffer(Type t, ref OutBuffer buf)
 {
-    import dmd.dmangle;
-    return dmd.dmangle.mangleToBuffer(t, buf);
+    import dmd.mangle;
+    return dmd.mangle.mangleToBuffer(t, buf);
 }
 
 void mangleToBuffer(Expression e, ref OutBuffer buf)
 {
-    import dmd.dmangle;
-    return dmd.dmangle.mangleToBuffer(e, buf);
+    import dmd.mangle;
+    return dmd.mangle.mangleToBuffer(e, buf);
 }
 
 void mangleToBuffer(Dsymbol s, ref OutBuffer buf)
 {
-    import dmd.dmangle;
-    return dmd.dmangle.mangleToBuffer(s, buf);
+    import dmd.mangle;
+    return dmd.mangle.mangleToBuffer(s, buf);
 }
 
 void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
 {
-    import dmd.dmangle;
-    return dmd.dmangle.mangleToBuffer(ti, buf);
+    import dmd.mangle;
+    return dmd.mangle.mangleToBuffer(ti, buf);
 }
 
 /***********************************************************
@@ -172,6 +172,12 @@ void importAll(Dsymbol d, Scope* sc)
     return dmd.dsymbolsem.importAll(d, sc);
 }
 
+Dsymbols* include(Dsymbol d, Scope* sc)
+{
+    import dmd.dsymbolsem;
+    return dmd.dsymbolsem.include(d, sc);
+}
+
 /***********************************************************
  * dtemplate.d
  */
@@ -250,6 +256,13 @@ Expression expressionSemantic(Expression e, Scope* sc)
     return dmd.expressionsem.expressionSemantic(e, sc);
 }
 
+bool fill(StructDeclaration sd, const ref Loc loc,
+          ref Expressions elements, bool ctorinit)
+{
+    import dmd.expressionsem;
+    return dmd.expressionsem.fill(sd, loc, elements, ctorinit);
+}
+
 /***********************************************************
  * funcsem.d
  */
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index ef84af9de5a31eacef05d3dc496e05d5752aecc9..34b120b3412566845bbe91dc98524d764474b930 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -46,6 +46,7 @@ import dmd.root.ctfloat;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.root.utf;
+import dmd.safe : setUnsafe;
 import dmd.tokens;
 import dmd.typesem;
 
@@ -704,7 +705,7 @@ MATCH implicitConvTo(Expression e, Type t)
                     return MATCH.nomatch;
                 m = MATCH.constant;
             }
-            if (e.hexString && tn.isIntegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
+            if (e.type != t && e.hexString && tn.isIntegral && (tn.size == e.sz || (!e.committed && (e.len % tn.size) == 0)))
             {
                 m = MATCH.convert;
                 return m;
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 74074d7078cda125859491ee5713ee4cdbe1ba27..c99d27559b22970ce251c497840aa98df2fe09d7 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -23,10 +23,9 @@ import dmd.gluelayer;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, addMember, search, setFieldOffset;
 import dmd.errors;
 import dmd.func;
-import dmd.funcsem;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
@@ -34,7 +33,7 @@ import dmd.mtype;
 import dmd.objc;
 import dmd.root.rmem;
 import dmd.target;
-import dmd.typesem;
+import dmd.typesem : covariant, immutableOf, sarrayOf;
 import dmd.visitor;
 
 /***********************************************************
@@ -616,6 +615,7 @@ extern (C++) class ClassDeclaration : AggregateDeclaration
 
     final bool isFuncHidden(FuncDeclaration fd)
     {
+        import dmd.funcsem : overloadApply;
         //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
         Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
         if (!s)
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 2d3592bf8eb4c3b7be76f76355cb5b9da16a90c7..995995400a55f0d78425f6a7e7a05d4290905a09 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -22,18 +22,18 @@ import dmd.delegatize;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, aliasSemantic;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
-import dmd.funcsem;
+import dmd.funcsem : overloadApply, getLevelAndCheck;
 import dmd.globals;
 import dmd.gluelayer;
 import dmd.id;
 import dmd.identifier;
 import dmd.init;
-import dmd.initsem;
+import dmd.initsem : initializerToExpression, initializerSemantic;
 import dmd.intrange;
 import dmd.location;
 import dmd.mtype;
@@ -42,177 +42,13 @@ import dmd.rootobject;
 import dmd.root.filename;
 import dmd.target;
 import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : toDsymbol, typeSemantic, size, hasPointers;
 import dmd.visitor;
 
 version (IN_GCC) {}
 else version (IN_LLVM) {}
 else version = MARS;
 
-/************************************
- * Check to see the aggregate type is nested and its context pointer is
- * accessible from the current scope.
- * Returns true if error occurs.
- */
-bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
-{
-    Dsymbol sparent = ad.toParentLocal();
-    Dsymbol sparent2 = ad.toParent2();
-    Dsymbol s = sc.func;
-    if (ad.isNested() && s)
-    {
-        //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
-        //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
-        //printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
-        if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
-        {
-            error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
-            return true;
-        }
-    }
-
-    bool result = false;
-    for (size_t i = iStart; i < ad.fields.length; i++)
-    {
-        VarDeclaration vd = ad.fields[i];
-        Type tb = vd.type.baseElemOf();
-        if (tb.ty == Tstruct)
-        {
-            result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym);
-        }
-    }
-    return result;
-}
-
-/***********************************************
- * Mark variable v as modified if it is inside a constructor that var
- * is a field in.
- * Also used to allow immutable globals to be initialized inside a static constructor.
- * Returns:
- *    true if it's an initialization of v
- */
-bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
-{
-    //printf("modifyFieldVar(var = %s)\n", var.toChars());
-    Dsymbol s = sc.func;
-    while (1)
-    {
-        FuncDeclaration fd = null;
-        if (s)
-            fd = s.isFuncDeclaration();
-        if (fd &&
-            ((fd.isCtorDeclaration() && var.isField()) ||
-             ((fd.isStaticCtorDeclaration() || fd.isCrtCtor) && !var.isField())) &&
-            fd.toParentDecl() == var.toParent2() &&
-            (!e1 || e1.op == EXP.this_))
-        {
-            bool result = true;
-
-            var.ctorinit = true;
-            //printf("setting ctorinit\n");
-
-            if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
-            {
-                assert(e1);
-                auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 ||
-                                 var.type.needsNested());
-
-                const dim = sc.ctorflow.fieldinit.length;
-                auto ad = fd.isMemberDecl();
-                assert(ad);
-                size_t i;
-                for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
-                {
-                    if (ad.fields[i] == var)
-                        break;
-                }
-                assert(i < dim);
-                auto fieldInit = &sc.ctorflow.fieldinit[i];
-                const fi = fieldInit.csx;
-
-                if (fi & CSX.this_ctor)
-                {
-                    if (var.type.isMutable() && e1.type.isMutable())
-                        result = false;
-                    else
-                    {
-                        const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
-                        .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars());
-                        .errorSupplemental(fieldInit.loc, "Previous initialization is here.");
-                    }
-                }
-                else if (sc.inLoop || (fi & CSX.label))
-                {
-                    if (!mustInit && var.type.isMutable() && e1.type.isMutable())
-                        result = false;
-                    else
-                    {
-                        const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
-                        .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars());
-                    }
-                }
-
-                fieldInit.csx |= CSX.this_ctor;
-                fieldInit.loc = e1.loc;
-                if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258
-                {
-                    foreach (j, v; ad.fields)
-                    {
-                        if (v is var || !var.isOverlappedWith(v))
-                            continue;
-                        v.ctorinit = true;
-                        sc.ctorflow.fieldinit[j].csx = CSX.this_ctor;
-                    }
-                }
-            }
-            else if (fd != sc.func)
-            {
-                if (var.type.isMutable())
-                    result = false;
-                else if (sc.func.fes)
-                {
-                    const(char)* p = var.isField() ? "field" : var.kind();
-                    .error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
-                        MODtoChars(var.type.mod), p, var.toChars());
-                }
-                else
-                {
-                    const(char)* p = var.isField() ? "field" : var.kind();
-                    .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
-                        MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
-                }
-            }
-            else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
-                     var.type.isImmutable())
-            {
-                .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
-                    MODtoChars(var.type.mod), var.kind(), var.toChars());
-                errorSupplemental(loc, "Use `shared static this` instead.");
-            }
-            else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
-                    var.type.isConst())
-            {
-                // @@@DEPRECATED_2.116@@@
-                // Turn this into an error, merging with the branch above
-                .deprecation(loc, "%s %s `%s` initialization is not allowed in `static this`",
-                    MODtoChars(var.type.mod), var.kind(), var.toChars());
-                deprecationSupplemental(loc, "Use `shared static this` instead.");
-            }
-            return result;
-        }
-        else
-        {
-            if (s)
-            {
-                s = s.toParentP(var.toParent2());
-                continue;
-            }
-        }
-        break;
-    }
-    return false;
-}
-
 /******************************************
  */
 void ObjectNotFound(Loc loc, Identifier id)
@@ -289,149 +125,6 @@ extern (C++) abstract class Declaration : Dsymbol
         return sz;
     }
 
-    /**
-     * Issue an error if an attempt to call a disabled method is made
-     *
-     * If the declaration is disabled but inside a disabled function,
-     * returns `true` but do not issue an error message.
-     *
-     * Params:
-     *   loc = Location information of the call
-     *   sc  = Scope in which the call occurs
-     *   isAliasedDeclaration = if `true` searches overload set
-     *
-     * Returns:
-     *   `true` if this `Declaration` is `@disable`d, `false` otherwise.
-     */
-    extern (D) final bool checkDisabled(Loc loc, Scope* sc, bool isAliasedDeclaration = false)
-    {
-        if (!(storage_class & STC.disable))
-            return false;
-
-        if (sc.func && sc.func.storage_class & STC.disable)
-            return true;
-
-        if (auto p = toParent())
-        {
-            if (auto postblit = isPostBlitDeclaration())
-            {
-                /* https://issues.dlang.org/show_bug.cgi?id=21885
-                 *
-                 * If the generated postblit is disabled, it
-                 * means that one of the fields has a disabled
-                 * postblit. Print the first field that has
-                 * a disabled postblit.
-                 */
-                if (postblit.isGenerated())
-                {
-                    auto sd = p.isStructDeclaration();
-                    assert(sd);
-                    for (size_t i = 0; i < sd.fields.length; i++)
-                    {
-                        auto structField = sd.fields[i];
-                        if (structField.overlapped)
-                            continue;
-                        Type tv = structField.type.baseElemOf();
-                        if (tv.ty != Tstruct)
-                            continue;
-                        auto sdv = (cast(TypeStruct)tv).sym;
-                        if (!sdv.postblit)
-                            continue;
-                        if (sdv.postblit.isDisabled())
-                        {
-                            .error(loc, "%s `%s` is not copyable because field `%s` is not copyable", p.kind, p.toPrettyChars, structField.toChars());
-                            return true;
-                        }
-                    }
-                }
-                .error(loc, "%s `%s` is not copyable because it has a disabled postblit", p.kind, p.toPrettyChars);
-                return true;
-            }
-        }
-
-        // if the function is @disabled, maybe there
-        // is an overload in the overload set that isn't
-        if (isAliasedDeclaration)
-        {
-            if (FuncDeclaration fd = isFuncDeclaration())
-            {
-                for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
-                    if (!(ovl.storage_class & STC.disable))
-                        return false;
-            }
-        }
-
-        if (auto ctor = isCtorDeclaration())
-        {
-            if (ctor.isCpCtor && ctor.isGenerated())
-            {
-                .error(loc, "generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", parent.toPrettyChars());
-                return true;
-            }
-        }
-        .error(loc, "%s `%s` cannot be used because it is annotated with `@disable`", kind, toPrettyChars);
-        return true;
-    }
-
-    /*************************************
-     * Check to see if declaration can be modified in this context (sc).
-     * Issue error if not.
-     * Params:
-     *  loc  = location for error messages
-     *  e1   = `null` or `this` expression when this declaration is a field
-     *  sc   = context
-     *  flag = if the first bit is set it means do not issue error message for
-     *         invalid modification; if the second bit is set, it means that
-               this declaration is a field and a subfield of it is modified.
-     * Returns:
-     *  Modifiable.yes or Modifiable.initialization
-     */
-    extern (D) final Modifiable checkModify(Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
-    {
-        VarDeclaration v = isVarDeclaration();
-        if (v && v.canassign)
-            return Modifiable.initialization;
-
-        if (isParameter() || isResult())
-        {
-            for (Scope* scx = sc; scx; scx = scx.enclosing)
-            {
-                if (scx.func == parent && scx.contract != Contract.none)
-                {
-                    const(char)* s = isParameter() && parent.ident != Id.ensure ? "parameter" : "result";
-                    if (!(flag & ModifyFlags.noError))
-                        error(loc, "%s `%s` cannot modify %s `%s` in contract", kind, toPrettyChars, s, toChars());
-                    return Modifiable.initialization; // do not report type related errors
-                }
-            }
-        }
-
-        if (e1 && e1.op == EXP.this_ && isField())
-        {
-            VarDeclaration vthis = e1.isThisExp().var;
-            for (Scope* scx = sc; scx; scx = scx.enclosing)
-            {
-                if (scx.func == vthis.parent && scx.contract != Contract.none)
-                {
-                    if (!(flag & ModifyFlags.noError))
-                        error(loc, "%s `%s` cannot modify parameter `this` in contract", kind, toPrettyChars);
-                    return Modifiable.initialization; // do not report type related errors
-                }
-            }
-        }
-
-        if (v && (v.isCtorinit() || isField()))
-        {
-            // It's only modifiable if inside the right constructor
-            if ((storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
-                return Modifiable.initialization;
-            if (flag & ModifyFlags.fieldAssign)
-                return Modifiable.yes;
-            return modifyFieldVar(loc, sc, v, e1) ? Modifiable.initialization : Modifiable.yes;
-        }
-        return Modifiable.yes;
-    }
-
     final bool isStatic() const pure nothrow @nogc @safe
     {
         return (storage_class & STC.static_) != 0;
@@ -923,6 +616,15 @@ extern (C++) final class AliasDeclaration : Declaration
         assert(this != aliassym);
         //static int count; if (++count == 10) *(char*)0=0;
 
+        Dsymbol err()
+        {
+            // Avoid breaking "recursive alias" state during errors gagged
+            if (global.gag)
+                return this;
+            aliassym = new AliasDeclaration(loc, ident, Type.terror);
+            type = Type.terror;
+            return aliassym;
+        }
         // Reading the AliasDeclaration
         if (!(adFlags & ignoreRead))
             adFlags |= wasRead;                 // can never assign to this AliasDeclaration again
@@ -930,16 +632,16 @@ extern (C++) final class AliasDeclaration : Declaration
         if (inuse == 1 && type && _scope)
         {
             inuse = 2;
-            uint olderrors = global.errors;
+            const olderrors = global.errors;
             Dsymbol s = type.toDsymbol(_scope);
             //printf("[%s] type = %s, s = %p, this = %p\n", loc.toChars(), type.toChars(), s, this);
             if (global.errors != olderrors)
-                goto Lerr;
+                return err();
             if (s)
             {
                 s = s.toAlias();
                 if (global.errors != olderrors)
-                    goto Lerr;
+                    return err();
                 aliassym = s;
                 inuse = 0;
             }
@@ -947,9 +649,9 @@ extern (C++) final class AliasDeclaration : Declaration
             {
                 Type t = type.typeSemantic(loc, _scope);
                 if (t.ty == Terror)
-                    goto Lerr;
+                    return err();
                 if (global.errors != olderrors)
-                    goto Lerr;
+                    return err();
                 //printf("t = %s\n", t.toChars());
                 inuse = 0;
             }
@@ -957,14 +659,7 @@ extern (C++) final class AliasDeclaration : Declaration
         if (inuse)
         {
             .error(loc, "%s `%s` recursive alias declaration", kind, toPrettyChars);
-
-        Lerr:
-            // Avoid breaking "recursive alias" state during errors gagged
-            if (global.gag)
-                return this;
-            aliassym = new AliasDeclaration(loc, ident, Type.terror);
-            type = Type.terror;
-            return aliassym;
+            return err();
         }
 
         if (semanticRun >= PASS.semanticdone)
@@ -1350,7 +1045,7 @@ extern (C++) class VarDeclaration : Declaration
         auto vbitoffset = v.offset * 8;
 
         // Bitsize of types are overridden by any bit-field widths.
-        ulong tbitsize = void;
+        ulong tbitsize;
         if (auto bf = isBitFieldDeclaration())
         {
             bitoffset += bf.bitOffset;
@@ -1359,7 +1054,7 @@ extern (C++) class VarDeclaration : Declaration
         else
             tbitsize = tsz * 8;
 
-        ulong vbitsize = void;
+        ulong vbitsize;
         if (auto vbf = v.isBitFieldDeclaration())
         {
             vbitoffset += vbf.bitOffset;
@@ -1395,118 +1090,6 @@ extern (C++) class VarDeclaration : Declaration
         return edtor && !(storage_class & STC.nodtor);
     }
 
-    /******************************************
-     * If a variable has a scope destructor call, return call for it.
-     * Otherwise, return NULL.
-     */
-    extern (D) final Expression callScopeDtor(Scope* sc)
-    {
-        //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
-
-        // Destruction of STC.field's is handled by buildDtor()
-        if (storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field))
-        {
-            return null;
-        }
-
-        if (iscatchvar)
-            return null;    // destructor is built by `void semantic(Catch c, Scope* sc)`, not here
-
-        Expression e = null;
-        // Destructors for structs and arrays of structs
-        Type tv = type.baseElemOf();
-        if (tv.ty == Tstruct)
-        {
-            StructDeclaration sd = (cast(TypeStruct)tv).sym;
-            if (!sd.dtor || sd.errors)
-                return null;
-
-            const sz = type.size();
-            assert(sz != SIZE_INVALID);
-            if (!sz)
-                return null;
-
-            if (type.toBasetype().ty == Tstruct)
-            {
-                // v.__xdtor()
-                e = new VarExp(loc, this);
-
-                /* This is a hack so we can call destructors on const/immutable objects.
-                 * Need to add things like "const ~this()" and "immutable ~this()" to
-                 * fix properly.
-                 */
-                e.type = e.type.mutableOf();
-
-                // Enable calling destructors on shared objects.
-                // The destructor is always a single, non-overloaded function,
-                // and must serve both shared and non-shared objects.
-                e.type = e.type.unSharedOf;
-
-                e = new DotVarExp(loc, e, sd.dtor, false);
-                e = new CallExp(loc, e);
-            }
-            else
-            {
-                // __ArrayDtor(v[0 .. n])
-                e = new VarExp(loc, this);
-
-                const sdsz = sd.type.size();
-                assert(sdsz != SIZE_INVALID && sdsz != 0);
-                const n = sz / sdsz;
-                SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
-                    new IntegerExp(loc, n, Type.tsize_t));
-
-                // Prevent redundant bounds check
-                se.upperIsInBounds = true;
-                se.lowerIsLessThanUpper = true;
-
-                // This is a hack so we can call destructors on const/immutable objects.
-                se.type = sd.type.arrayOf();
-
-                e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
-            }
-            return e;
-        }
-        // Destructors for classes
-        if (storage_class & (STC.auto_ | STC.scope_) && !(storage_class & STC.parameter))
-        {
-            for (ClassDeclaration cd = type.isClassHandle(); cd; cd = cd.baseClass)
-            {
-                /* We can do better if there's a way with onstack
-                 * classes to determine if there's no way the monitor
-                 * could be set.
-                 */
-                //if (cd.isInterfaceDeclaration())
-                //    error("interface `%s` cannot be scope", cd.toChars());
-
-                if (onstack) // if any destructors
-                {
-                    // delete'ing C++ classes crashes (and delete is deprecated anyway)
-                    if (cd.classKind == ClassKind.cpp)
-                    {
-                        // Don't call non-existant dtor
-                        if (!cd.dtor)
-                            break;
-
-                        e = new VarExp(loc, this);
-                        e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
-                        e = new DotVarExp(loc, e, cd.dtor, false);
-                        e = new CallExp(loc, e);
-                        break;
-                    }
-
-                    // delete this;
-                    Expression ec;
-                    ec = new VarExp(loc, this);
-                    e = new DeleteExp(loc, ec, true);
-                    e.type = Type.tvoid;
-                    break;
-                }
-            }
-        }
-        return e;
-    }
-
     /*******************************************
      * If variable has a constant expression initializer, get it.
      * Otherwise, return null.
@@ -1516,7 +1099,7 @@ extern (C++) class VarDeclaration : Declaration
         assert(type && _init);
 
         // Ungag errors when not speculative
-        uint oldgag = global.gag;
+        const oldgag = global.gag;
         if (global.gag)
         {
             Dsymbol sym = isMember();
@@ -1539,25 +1122,6 @@ extern (C++) class VarDeclaration : Declaration
         return e;
     }
 
-    /*******************************************
-     * Helper function for the expansion of manifest constant.
-     */
-    extern (D) final Expression expandInitializer(Loc loc)
-    {
-        assert((storage_class & STC.manifest) && _init);
-
-        auto e = getConstInitializer();
-        if (!e)
-        {
-            .error(loc, "cannot make expression out of initializer for `%s`", toChars());
-            return ErrorExp.get();
-        }
-
-        e = e.copy();
-        e.loc = loc;    // for better error message
-        return e;
-    }
-
     override final void checkCtorConstInit()
     {
         version (none)
@@ -1762,7 +1326,7 @@ extern (C++) final class SymbolDeclaration : Declaration
  */
 private Identifier getTypeInfoIdent(Type t)
 {
-    import dmd.dmangle;
+    import dmd.mangle;
     import core.stdc.stdlib;
     import dmd.root.rmem;
     // _init_10TypeInfo_%s
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index c19aa0692fa362df6f2e2021532db7c53c05881b..bdefd2d9f864cc5f029b7c5bc0bf181526ab78ea 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -590,13 +590,6 @@ public:
 
     // Things that should really go into Scope
 
-    // 1 if there's a return exp; statement
-    // 2 if there's a throw statement
-    // 4 if there's an assert(0)
-    // 8 if there's inline asm
-    // 16 if there are multiple return statements
-    int hasReturnExp;
-
     VarDeclaration *nrvo_var;           // variable to replace with shidden
     Symbol *shidden;                    // hidden pointer passed to function
 
@@ -679,6 +672,12 @@ public:
     bool dllImport(bool v);
     bool dllExport() const;
     bool dllExport(bool v);
+    bool hasReturnExp() const;
+    bool hasReturnExp(bool v);
+    bool hasInlineAsm() const;
+    bool hasInlineAsm(bool v);
+    bool hasMultipleReturnExp() const;
+    bool hasMultipleReturnExp(bool v);
 
     // Data for a function declaration that is needed for the Objective-C
     // integration.
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 4c4c063cbf2731fd72897a9e9873482b9c8b7380..96e821aea6af2c2f1454c97617e041324d998d12 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -14,7 +14,6 @@ module dmd.dimport;
 import dmd.arraytypes;
 import dmd.dmodule;
 import dmd.dsymbol;
-import dmd.errors;
 import dmd.identifier;
 import dmd.location;
 import dmd.visitor;
@@ -84,16 +83,6 @@ extern (C++) final class Import : Dsymbol
         this.visibility = Visibility.Kind.private_; // default to private
     }
 
-    extern (D) void addAlias(Identifier name, Identifier _alias)
-    {
-        if (isstatic)
-            .error(loc, "%s `%s` cannot have an import bind list", kind, toPrettyChars);
-        if (!aliasId)
-            this.ident = null; // make it an anonymous import
-        names.push(name);
-        aliases.push(_alias);
-    }
-
     override const(char)* kind() const
     {
         return isstatic ? "static import" : "import";
@@ -110,9 +99,13 @@ extern (C++) final class Import : Dsymbol
         assert(!s);
         auto si = new Import(loc, packages, id, aliasId, isstatic);
         si.comment = comment;
+        assert(!(isstatic && names.length));
+        if (names.length && !si.aliasId)
+            si.ident = null;
         for (size_t i = 0; i < names.length; i++)
         {
-            si.addAlias(names[i], aliases[i]);
+            si.names.push(names[i]);
+            si.aliases.push(aliases[i]);
         }
         return si;
     }
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index eda20a2141ad3b83a6224fc24bb5f7f7bc4fb036..7996d3441934ffe4bf9b106f98a0df84b20e4705 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -30,7 +30,7 @@ import dmd.dmacro;
 import dmd.doc;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, importAll, load, include;
 import dmd.errors;
 import dmd.errorsink;
 import dmd.expression;
@@ -632,7 +632,7 @@ extern (C++) final class Module : Package
         const name = srcfile.toString();
         if (FileName.equals(name, "object.d"))
         {
-            ObjectNotFound(loc, ident);
+            ObjectNotFound(Loc.initial, ident);
         }
         else if (FileName.ext(this.arg) || !loc.isValid())
         {
@@ -800,7 +800,6 @@ extern (C++) final class Module : Package
         {
             const bool doUnittests = global.params.parsingUnittestsRequired();
             scope p = new Parser!AST(this, buf, cast(bool) docfile, global.errorSink, &global.compileEnv, doUnittests);
-            p.transitionIn = global.params.v.vin;
             p.nextToken();
             p.parseModuleDeclaration();
             md = p.md;
@@ -1408,7 +1407,7 @@ private const(char)[] processSource (const(ubyte)[] src, Module mod)
 {
     enum SourceEncoding { utf16, utf32}
     enum Endian { little, big}
-    immutable loc = mod.getLoc();
+    immutable loc = mod.loc;
 
     /*
      * Convert a buffer from UTF32 to UTF8
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 84048af033796ab9a561732f2e830f6c1a15a301..21391dc1838877f04d12f718996264e49698164f 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -2274,10 +2274,9 @@ void removeBlankLineMacro(ref OutBuffer buf, ref size_t iAt, ref size_t i)
  *                thematic break. If the replacement is made `i` changes to
  *                point to the closing parenthesis of the `$(HR)` macro.
  *  iLineStart  = the index within `buf` that the thematic break's line starts at
- *  loc         = the current location within the file
  * Returns: whether a thematic break was replaced
  */
-bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart, const ref Loc loc)
+bool replaceMarkdownThematicBreak(ref OutBuffer buf, ref size_t i, size_t iLineStart)
 {
 
     const slice = buf[];
@@ -2378,11 +2377,10 @@ void removeAnyAtxHeadingSuffix(ref OutBuffer buf, size_t i)
  *  iEnd          = the index within `buf` of the character after the last
  *                  heading character. Is incremented by the length of the
  *                  inserted heading macro when this function ends.
- *  loc           = the location of the Ddoc within the file
  *  headingLevel  = the level (1-6) of heading to end. Is set to `0` when this
  *                  function ends.
  */
-void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, const ref Loc loc, ref int headingLevel)
+void endMarkdownHeading(ref OutBuffer buf, size_t iStart, ref size_t iEnd, ref int headingLevel)
 {
     char[5] heading = "$(H0 ";
     heading[3] = cast(char) ('0' + headingLevel);
@@ -2439,12 +2437,11 @@ size_t endAllListsAndQuotes(ref OutBuffer buf, ref size_t i, ref MarkdownList[]
  * e.g. `*very* **nice**` becomes `$(EM very) $(STRONG nice)`.
  * Params:
  *  buf               = an OutBuffer containing the DDoc
- *  loc               = the current location within the file
  *  inlineDelimiters  = the collection of delimiters found within a paragraph. When this function returns its length will be reduced to `downToLevel`.
  *  downToLevel       = the length within `inlineDelimiters`` to reduce emphasis to
  * Returns: the number of characters added to the buffer by the replacements
  */
-size_t replaceMarkdownEmphasis(ref OutBuffer buf, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0)
+size_t replaceMarkdownEmphasis(ref OutBuffer buf, ref MarkdownDelimiter[] inlineDelimiters, int downToLevel = 0)
 {
     size_t replaceEmphasisPair(ref MarkdownDelimiter start, ref MarkdownDelimiter end)
     {
@@ -2823,10 +2820,9 @@ struct MarkdownList
      *  i             = the index within `buf` of the list item. If this function succeeds `i` will be adjusted to fit the inserted macro.
      *  iPrecedingBlankLine = the index within `buf` of the preceeding blank line. If non-zero and a new list was started, the preceeding blank line is removed and this value is set to `0`.
      *  nestedLists   = a set of nested lists. If this function succeeds it may contain a new nested list.
-     *  loc           = the location of the Ddoc within the file
      * Returns: `true` if a list was created
      */
-    bool startItem(ref OutBuffer buf, ref size_t iLineStart, ref size_t i, ref size_t iPrecedingBlankLine, ref MarkdownList[] nestedLists, const ref Loc loc)
+    bool startItem(ref OutBuffer buf, ref size_t iLineStart, ref size_t i, ref size_t iPrecedingBlankLine, ref MarkdownList[] nestedLists)
     {
         buf.remove(iStart, iContentStart - iStart);
 
@@ -3001,14 +2997,13 @@ struct MarkdownLink
      *  buf               = an OutBuffer containing the DDoc
      *  i                 = the index within `buf` that points to the `]` character of the potential link.
      *                      If this function succeeds it will be adjusted to fit the inserted link macro.
-     *  loc               = the current location within the file
      *  inlineDelimiters  = previously parsed Markdown delimiters, including emphasis and link/image starts
      *  delimiterIndex    = the index within `inlineDelimiters` of the nearest link/image starting delimiter
      *  linkReferences    = previously parsed link references. When this function returns it may contain
      *                      additional previously unparsed references.
      * Returns: whether a reference link was found and replaced at `i`
      */
-    static bool replaceLink(ref OutBuffer buf, ref size_t i, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
+    static bool replaceLink(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
     {
         const delimiter = inlineDelimiters[delimiterIndex];
         MarkdownLink link;
@@ -3017,7 +3012,7 @@ struct MarkdownLink
         if (iEnd > i)
         {
             i = delimiter.iStart;
-            link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+            link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences);
             inlineDelimiters.length = delimiterIndex;
             return true;
         }
@@ -3029,7 +3024,7 @@ struct MarkdownLink
             if (iEnd > i)
             {
                 const label = link.label;
-                link = linkReferences.lookupReference(label, buf, i, loc);
+                link = linkReferences.lookupReference(label, buf, i);
                 // check rightFlanking to avoid replacing things like int[string]
                 if (!link.href.length && !delimiter.rightFlanking)
                     link = linkReferences.lookupSymbol(label);
@@ -3041,7 +3036,7 @@ struct MarkdownLink
         if (iEnd == i)
             return false;
 
-        immutable delta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, delimiterIndex);
+        immutable delta = replaceMarkdownEmphasis(buf, inlineDelimiters, delimiterIndex);
         iEnd += delta;
         i += delta;
         link.replaceLink(buf, i, iEnd, delimiter);
@@ -3058,10 +3053,9 @@ struct MarkdownLink
      *  delimiterIndex    = the index within `inlineDelimiters` of the nearest link/image starting delimiter
      *  linkReferences    = previously parsed link references. When this function returns it may contain
      *                      additional previously unparsed references.
-     *  loc               = the current location in the file
      * Returns: whether a reference link was found and replaced at `i`
      */
-    static bool replaceReferenceDefinition(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+    static bool replaceReferenceDefinition(ref OutBuffer buf, ref size_t i, ref MarkdownDelimiter[] inlineDelimiters, int delimiterIndex, ref MarkdownLinkReferences linkReferences)
     {
         const delimiter = inlineDelimiters[delimiterIndex];
         MarkdownLink link;
@@ -3070,7 +3064,7 @@ struct MarkdownLink
             return false;
 
         i = delimiter.iStart;
-        link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences, loc);
+        link.storeAndReplaceDefinition(buf, i, iEnd, linkReferences);
         inlineDelimiters.length = delimiterIndex;
         return true;
     }
@@ -3443,9 +3437,8 @@ struct MarkdownLink
      *  iEnd              = the index within `buf` that points just after the end of the definition
      *  linkReferences    = previously parsed link references. When this function returns it may contain
      *                      an additional reference.
-     *  loc               = the current location in the file
      */
-    private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences, const ref Loc loc)
+    private void storeAndReplaceDefinition(ref OutBuffer buf, ref size_t i, size_t iEnd, ref MarkdownLinkReferences linkReferences)
     {
         // Remove the definition and trailing whitespace
         iEnd = skipChars(buf, iEnd, " \t\r\n");
@@ -3578,14 +3571,13 @@ struct MarkdownLinkReferences
      *  label = the label to find the reference for
      *  buf   = an OutBuffer containing the DDoc
      *  i     = the index within `buf` to start searching for references at
-     *  loc   = the current location in the file
      * Returns: a link. If the `href` member has a value then the reference is valid.
      */
-    MarkdownLink lookupReference(string label, ref OutBuffer buf, size_t i, const ref Loc loc)
+    MarkdownLink lookupReference(string label, ref OutBuffer buf, size_t i)
     {
         const lowercaseLabel = label.toLowercase();
         if (lowercaseLabel !in references)
-            extractReferences(buf, i, loc);
+            extractReferences(buf, i);
 
         if (lowercaseLabel in references)
             return references[lowercaseLabel];
@@ -3633,10 +3625,9 @@ struct MarkdownLinkReferences
      * Params:
      *  buf   = an OutBuffer containing the DDoc
      *  i     = the index within `buf` to start looking at
-     *  loc   = the current location in the file
      * Returns: whether a reference was extracted
      */
-    private void extractReferences(ref OutBuffer buf, size_t i, const ref Loc loc)
+    private void extractReferences(ref OutBuffer buf, size_t i)
     {
         static bool isFollowedBySpace(ref OutBuffer buf, size_t i)
         {
@@ -3724,7 +3715,7 @@ struct MarkdownLinkReferences
                 break;
             case ']':
                 if (delimiters.length && !inCode &&
-                    MarkdownLink.replaceReferenceDefinition(buf, i, delimiters, cast(int) delimiters.length - 1, this, loc))
+                    MarkdownLink.replaceReferenceDefinition(buf, i, delimiters, cast(int) delimiters.length - 1, this))
                     --i;
                 break;
             default:
@@ -3897,19 +3888,18 @@ size_t parseTableDelimiterRow(ref OutBuffer buf, const size_t iStart, bool inQuo
  *  buf       = an OutBuffer containing the DDoc
  *  iStart    = the index within `buf` that the table header row starts at, inclusive
  *  iEnd      = the index within `buf` that the table header row ends at, exclusive
- *  loc       = the current location in the file
  *  inQuote   = whether the table is inside a quote
  *  inlineDelimiters = delimiters containing columns separators and any inline emphasis
  *  columnAlignments = the parsed alignments for each column
  * Returns: the number of characters added by starting the table, or `0` if unchanged
  */
-size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments)
+size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, bool inQuote, ref MarkdownDelimiter[] inlineDelimiters, out TableColumnAlignment[] columnAlignments)
 {
     const iDelimiterRowEnd = parseTableDelimiterRow(buf, iEnd + 1, inQuote, columnAlignments);
     if (iDelimiterRowEnd)
     {
         size_t delta;
-        if (replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, true, delta))
+        if (replaceTableRow(buf, iStart, iEnd, inlineDelimiters, columnAlignments, true, delta))
         {
             buf.remove(iEnd + delta, iDelimiterRowEnd - iEnd);
             buf.insert(iEnd + delta, "$(TBODY ");
@@ -3930,7 +3920,6 @@ size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc l
  *  buf       = an OutBuffer containing the DDoc
  *  iStart    = the index within `buf` that the table row starts at, inclusive
  *  iEnd      = the index within `buf` that the table row ends at, exclusive
- *  loc       = the current location in the file
  *  inlineDelimiters = delimiters containing columns separators and any inline emphasis
  *  columnAlignments = alignments for each column
  *  headerRow = if `true` then the number of columns will be enforced to match
@@ -3939,7 +3928,7 @@ size_t startTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc l
  *  delta     = the number of characters added by replacing the row, or `0` if unchanged
  * Returns: `true` if a table row was found and replaced
  */
-bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
+bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, ref MarkdownDelimiter[] inlineDelimiters, TableColumnAlignment[] columnAlignments, bool headerRow, out size_t delta)
 {
     delta = 0;
 
@@ -3965,7 +3954,7 @@ bool replaceTableRow(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Lo
 
     void replaceTableCell(size_t iCellStart, size_t iCellEnd, int cellIndex, int di)
     {
-        const eDelta = replaceMarkdownEmphasis(buf, loc, inlineDelimiters, di);
+        const eDelta = replaceMarkdownEmphasis(buf, inlineDelimiters, di);
         delta += eDelta;
         iCellEnd += eDelta;
 
@@ -4083,15 +4072,14 @@ size_t endTable(ref OutBuffer buf, size_t i, ref TableColumnAlignment[] columnAl
  *  buf       = an OutBuffer containing the DDoc
  *  iStart    = the index within `buf` that the table row starts at, inclusive
  *  iEnd      = the index within `buf` that the table row ends at, exclusive
- *  loc       = the current location in the file
  *  inlineDelimiters = delimiters containing columns separators and any inline emphasis
  *  columnAlignments = alignments for each column; upon return is set to length `0`
  * Returns: the number of characters added by replacing the row, or `0` if unchanged
  */
-size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, const ref Loc loc, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
+size_t endRowAndTable(ref OutBuffer buf, size_t iStart, size_t iEnd, ref MarkdownDelimiter[] inlineDelimiters, ref TableColumnAlignment[] columnAlignments)
 {
     size_t delta;
-    replaceTableRow(buf, iStart, iEnd, loc, inlineDelimiters, columnAlignments, false, delta);
+    replaceTableRow(buf, iStart, iEnd, inlineDelimiters, columnAlignments, false, delta);
     delta += endTable(buf, iEnd + delta, columnAlignments);
     return delta;
 }
@@ -4161,19 +4149,19 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
             }
             if (headingLevel)
             {
-                i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
-                endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+                i += replaceMarkdownEmphasis(buf, inlineDelimiters);
+                endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
                 removeBlankLineMacro(buf, iPrecedingBlankLine, i);
                 ++i;
                 iParagraphStart = skipChars(buf, i, " \t\r\n");
             }
 
             if (tableRowDetected && !columnAlignments.length)
-                i += startTable(buf, iLineStart, i, loc, lineQuoted, inlineDelimiters, columnAlignments);
+                i += startTable(buf, iLineStart, i, lineQuoted, inlineDelimiters, columnAlignments);
             else if (columnAlignments.length)
             {
                 size_t delta;
-                if (replaceTableRow(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments, false, delta))
+                if (replaceTableRow(buf, iLineStart, i, inlineDelimiters, columnAlignments, false, delta))
                     i += delta;
                 else
                     i += endTable(buf, i, columnAlignments);
@@ -4188,7 +4176,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                 i += endTable(buf, i, columnAlignments);
                 if (!lineQuoted && quoteLevel)
                     endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
-                i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+                i += replaceMarkdownEmphasis(buf, inlineDelimiters);
 
                 // if we don't already know about this paragraph break then
                 // insert a blank line and record the paragraph break
@@ -4304,7 +4292,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
 
                     if (quoteLevel < lineQuoteLevel)
                     {
-                        i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                        i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                         if (nestedLists.length)
                         {
                             const indent = getMarkdownIndent(buf, iLineStart, i);
@@ -4427,7 +4415,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                 if (!headingLevel)
                     break;
 
-                i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                 if (!lineQuoted && quoteLevel)
                     i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
 
@@ -4468,7 +4456,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                     const list = MarkdownList.parseItem(buf, iLineStart, i);
                     if (list.isValid)
                     {
-                        if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+                        if (replaceMarkdownThematicBreak(buf, i, iLineStart))
                         {
                             removeBlankLineMacro(buf, iPrecedingBlankLine, i);
                             iParagraphStart = skipChars(buf, i+1, " \t\r\n");
@@ -4592,7 +4580,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                 }
                 else
                 {
-                    i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                    i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                     if (!lineQuoted && quoteLevel)
                     {
                         const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
@@ -4624,9 +4612,9 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
 
         case '_':
         {
-            if (leadingBlank && !inCode && replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+            if (leadingBlank && !inCode && replaceMarkdownThematicBreak(buf, i, iLineStart))
             {
-                i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                 if (!lineQuoted && quoteLevel)
                     i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
                 removeBlankLineMacro(buf, iPrecedingBlankLine, i);
@@ -4654,7 +4642,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                         break;
                     }
 
-                    i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                    i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                     if (!lineQuoted && quoteLevel)
                     {
                         const delta = endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
@@ -4664,7 +4652,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                     }
 
                     list.macroLevel = macroLevel;
-                    list.startItem(buf, iLineStart, i, iPrecedingBlankLine, nestedLists, loc);
+                    list.startItem(buf, iLineStart, i, iPrecedingBlankLine, nestedLists);
                     break;
                 }
             }
@@ -4683,9 +4671,9 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
             if (leadingBlank)
             {
                 // Check for a thematic break
-                if (replaceMarkdownThematicBreak(buf, i, iLineStart, loc))
+                if (replaceMarkdownThematicBreak(buf, i, iLineStart))
                 {
-                    i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                    i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                     if (!lineQuoted && quoteLevel)
                         i += endAllListsAndQuotes(buf, iLineStart, nestedLists, quoteLevel, quoteMacroLevel);
                     removeBlankLineMacro(buf, iPrecedingBlankLine, i);
@@ -4764,7 +4752,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                 if (delimiter.type == '[' || delimiter.type == '!')
                 {
                     if (delimiter.isValid &&
-                        MarkdownLink.replaceLink(buf, i, loc, inlineDelimiters, d, linkReferences))
+                        MarkdownLink.replaceLink(buf, i, inlineDelimiters, d, linkReferences))
                     {
                         // if we removed a reference link then we're at line start
                         if (i <= delimiter.iStart)
@@ -4862,10 +4850,10 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                     --downToLevel;
                 if (headingLevel && headingMacroLevel >= macroLevel)
                 {
-                    endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+                    endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
                     removeBlankLineMacro(buf, iPrecedingBlankLine, i);
                 }
-                i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
+                i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
                 while (nestedLists.length && nestedLists[$-1].macroLevel >= macroLevel)
                 {
                     i = buf.insert(i, ")\n)");
@@ -4873,7 +4861,7 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
                 }
                 if (quoteLevel && quoteMacroLevel >= macroLevel)
                     i += endAllMarkdownQuotes(buf, i, quoteLevel);
-                i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters, downToLevel);
+                i += replaceMarkdownEmphasis(buf, inlineDelimiters, downToLevel);
 
                 --macroLevel;
                 quoteMacroLevel = 0;
@@ -4949,11 +4937,11 @@ void highlightText(Scope* sc, Dsymbols* a, Loc loc, ref OutBuffer buf, size_t of
     size_t i = buf.length;
     if (headingLevel)
     {
-        endMarkdownHeading(buf, iParagraphStart, i, loc, headingLevel);
+        endMarkdownHeading(buf, iParagraphStart, i, headingLevel);
         removeBlankLineMacro(buf, iPrecedingBlankLine, i);
     }
-    i += endRowAndTable(buf, iLineStart, i, loc, inlineDelimiters, columnAlignments);
-    i += replaceMarkdownEmphasis(buf, loc, inlineDelimiters);
+    i += endRowAndTable(buf, iLineStart, i, inlineDelimiters, columnAlignments);
+    i += replaceMarkdownEmphasis(buf, inlineDelimiters);
     endAllListsAndQuotes(buf, i, nestedLists, quoteLevel, quoteMacroLevel);
 }
 
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 7936086bdd06d392943a1a1d6403a7b8ae8af293..05cc8f156e11869336a0413da66b19ccc4aaf40d 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -253,13 +253,13 @@ extern (C++) struct Scope
     }
 
     /// Copy flags from scope `other`
-    extern(D) void copyFlagsFrom(Scope* other)
+    extern(D) void copyFlagsFrom(Scope* other) @safe
     {
         this.bitFields = other.bitFields;
     }
 
     /// Set all scope flags to their initial value
-    extern(D) void resetAllFlags()
+    extern(D) void resetAllFlags() @safe
     {
         this.bitFields = 0;
     }
@@ -353,24 +353,23 @@ extern (C++) struct Scope
             error(loc, "one path skips constructor");
 
         const fies = ctorflow.fieldinit;
-        if (this.ctorflow.fieldinit.length && fies.length)
+        if (!this.ctorflow.fieldinit.length || !fies.length)
+            return;
+        FuncDeclaration f = func;
+        if (fes)
+            f = fes.func;
+        auto ad = f.isMemberDecl();
+        assert(ad);
+        foreach (i, v; ad.fields)
         {
-            FuncDeclaration f = func;
-            if (fes)
-                f = fes.func;
-            auto ad = f.isMemberDecl();
-            assert(ad);
-            foreach (i, v; ad.fields)
+            bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
+            auto fieldInit = &this.ctorflow.fieldinit[i];
+            const fiesCurrent = fies[i];
+            if (fieldInit.loc is Loc.init)
+                fieldInit.loc = fiesCurrent.loc;
+            if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
             {
-                bool mustInit = (v.storage_class & STC.nodefaultctor || v.type.needsNested());
-                auto fieldInit = &this.ctorflow.fieldinit[i];
-                const fiesCurrent = fies[i];
-                if (fieldInit.loc is Loc.init)
-                    fieldInit.loc = fiesCurrent.loc;
-                if (!mergeFieldInit(this.ctorflow.fieldinit[i].csx, fiesCurrent.csx) && mustInit)
-                {
-                    error(loc, "one path skips field `%s`", v.toChars());
-                }
+                error(loc, "one path skips field `%s`", v.toChars());
             }
         }
     }
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 8b4ac7d88464b57e7f595b819b0b901f330d6a85..d7b1ace34f0a01c01166c9053f03a35944f60abd 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -23,7 +23,7 @@ import dmd.declaration;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : search, setFieldOffset;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
@@ -37,7 +37,7 @@ import dmd.mtype;
 import dmd.opover;
 import dmd.target;
 import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : isZeroInit, merge, size, hasPointers;
 import dmd.typinf;
 import dmd.visitor;
 
@@ -66,126 +66,6 @@ FuncDeclaration search_toString(StructDeclaration sd)
     return fd;
 }
 
-/***************************************
- * Request additional semantic analysis for TypeInfo generation.
- * Params:
- *      sc = context
- *      t = type that TypeInfo is being generated for
- */
-extern (D) void semanticTypeInfo(Scope* sc, Type t)
-{
-    if (sc)
-    {
-        if (sc.intypeof)
-            return;
-        if (!sc.needsCodegen())
-            return;
-    }
-
-    if (!t)
-        return;
-
-    void visitVector(TypeVector t)
-    {
-        semanticTypeInfo(sc, t.basetype);
-    }
-
-    void visitAArray(TypeAArray t)
-    {
-        semanticTypeInfo(sc, t.index);
-        semanticTypeInfo(sc, t.next);
-    }
-
-    void visitStruct(TypeStruct t)
-    {
-        //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
-        StructDeclaration sd = t.sym;
-
-        /* Step 1: create TypeInfoDeclaration
-         */
-        if (!sc) // inline may request TypeInfo.
-        {
-            Scope scx;
-            scx.eSink = global.errorSink;
-            scx._module = sd.getModule();
-            getTypeInfoType(sd.loc, t, &scx);
-            sd.requestTypeInfo = true;
-        }
-        else if (!sc.minst)
-        {
-            // don't yet have to generate TypeInfo instance if
-            // the typeid(T) expression exists in speculative scope.
-        }
-        else
-        {
-            getTypeInfoType(sd.loc, t, sc);
-            sd.requestTypeInfo = true;
-
-            // https://issues.dlang.org/show_bug.cgi?id=15149
-            // if the typeid operand type comes from a
-            // result of auto function, it may be yet speculative.
-            // unSpeculative(sc, sd);
-        }
-
-        /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
-         * This should be done even if typeid(T) exists in speculative scope.
-         * Because it may appear later in non-speculative scope.
-         */
-        if (!sd.members)
-            return; // opaque struct
-        if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
-            return; // none of TypeInfo-specific members
-
-        // If the struct is in a non-root module, run semantic3 to get
-        // correct symbols for the member function.
-        if (sd.semanticRun >= PASS.semantic3)
-        {
-            // semantic3 is already done
-        }
-        else if (TemplateInstance ti = sd.isInstantiated())
-        {
-            if (ti.minst && !ti.minst.isRoot())
-                Module.addDeferredSemantic3(sd);
-        }
-        else
-        {
-            if (sd.inNonRoot())
-            {
-                //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
-                Module.addDeferredSemantic3(sd);
-            }
-        }
-    }
-
-    void visitTuple(TypeTuple t)
-    {
-        if (t.arguments)
-        {
-            foreach (arg; *t.arguments)
-            {
-                semanticTypeInfo(sc, arg.type);
-            }
-        }
-    }
-
-    /* Note structural similarity of this Type walker to that in isSpeculativeType()
-     */
-
-    Type tb = t.toBasetype();
-    switch (tb.ty)
-    {
-        case Tvector:   visitVector(tb.isTypeVector()); break;
-        case Taarray:   visitAArray(tb.isTypeAArray()); break;
-        case Tstruct:   visitStruct(tb.isTypeStruct()); break;
-        case Ttuple:    visitTuple (tb.isTypeTuple());  break;
-
-        case Tclass:
-        case Tenum:     break;
-
-        default:        semanticTypeInfo(sc, tb.nextOf()); break;
-    }
-}
-
 enum StructFlags : int
 {
     none        = 0x0,
@@ -350,8 +230,18 @@ extern (C++) class StructDeclaration : AggregateDeclaration
 
         // Determine if struct is all zeros or not
         zeroInit = true;
+        auto lastOffset = -1;
         foreach (vd; fields)
         {
+            // First skip zero sized fields
+            if (vd.type.size(vd.loc) == 0)
+                continue;
+
+            // only consider first sized member of an (anonymous) union
+            if (vd.overlapped && vd.offset == lastOffset)
+                continue;
+            lastOffset = vd.offset;
+
             if (vd._init)
             {
                 if (vd._init.isVoidInitializer())
@@ -360,10 +250,6 @@ extern (C++) class StructDeclaration : AggregateDeclaration
                      */
                     continue;
 
-                // Zero size fields are zero initialized
-                if (vd.type.size(vd.loc) == 0)
-                    continue;
-
                 // Examine init to see if it is all 0s.
                 auto exp = vd.getConstInitializer();
                 if (!exp || !_isZeroInit(exp))
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index f5ec1ce1251c9afa60c71a6c76ecf64c26204c68..af32f7afa1e8d5305a31dcccb18a837531aa997d 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -275,13 +275,13 @@ extern (C++) class Dsymbol : ASTNode
     final extern (D) this() nothrow @safe
     {
         //printf("Dsymbol::Dsymbol(%p)\n", this);
-        loc = Loc(null, 0, 0);
+        loc = Loc.initial;
     }
 
     final extern (D) this(Identifier ident) nothrow @safe
     {
         //printf("Dsymbol::Dsymbol(%p, ident)\n", this);
-        this.loc = Loc(null, 0, 0);
+        this.loc = Loc.initial;
         this.ident = ident;
     }
 
@@ -344,19 +344,6 @@ extern (C++) class Dsymbol : ASTNode
         return toChars();
     }
 
-    final const(Loc) getLoc()
-    {
-        if (!loc.isValid()) // avoid bug 5861.
-            if (const m = getModule())
-                return Loc(m.srcfile.toChars(), 0, 0);
-        return loc;
-    }
-
-    final const(char)* locToChars()
-    {
-        return getLoc().toChars();
-    }
-
     override bool equals(const RootObject o) const
     {
         if (this == o)
@@ -618,7 +605,7 @@ extern (C++) class Dsymbol : ASTNode
 
     final Ungag ungagSpeculative() const
     {
-        uint oldgag = global.gag;
+        const oldgag = global.gag;
         if (global.gag && !isSpeculative() && !toParent2().isFuncDeclaration())
             global.gag = 0;
         return Ungag(oldgag);
@@ -1303,7 +1290,7 @@ public:
         }
         else
         {
-            .error(s1.loc, "%s `%s` conflicts with %s `%s` at %s", s1.kind, s1.toPrettyChars, s2.kind(), s2.toPrettyChars(), s2.locToChars());
+            .error(s1.loc, "%s `%s` conflicts with %s `%s` at %s", s1.kind, s1.toPrettyChars, s2.kind(), s2.toPrettyChars(), s2.loc.toChars());
         }
     }
 
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 2c5f0e579b3af7974373056a7a2cdf1c4e0b5e97..7b33ed2910bfe00da252e8813449f702433e28fb 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -139,20 +139,6 @@ enum class PASS : uint8_t
     obj             // toObjFile() run
 };
 
-enum
-{
-    PASSinit,           // initial state
-    PASSsemantic,       // semantic() started
-    PASSsemanticdone,   // semantic() done
-    PASSsemantic2,      // semantic2() started
-    PASSsemantic2done,  // semantic2() done
-    PASSsemantic3,      // semantic3() started
-    PASSsemantic3done,  // semantic3() done
-    PASSinline,         // inline started
-    PASSinlinedone,     // inline done
-    PASSobj             // toObjFile() run
-};
-
 /* Flags for symbol search
  */
 typedef unsigned SearchOptFlags;
@@ -209,8 +195,6 @@ public:
     CPPNamespaceDeclaration* cppnamespace(CPPNamespaceDeclaration* ns);
     UserAttributeDeclaration* userAttribDecl(UserAttributeDeclaration* uad);
     virtual const char *toPrettyCharsHelper(); // helper to print fully qualified (template) arguments
-    Loc getLoc();
-    const char *locToChars();
     bool equals(const RootObject * const o) const override;
     bool isAnonymous() const;
     Module *getModule();
@@ -446,6 +430,7 @@ namespace dmd
 {
     void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
     Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
+    Dsymbols *include(Dsymbol *d, Scope *sc);
     void setScope(Dsymbol *d, Scope *sc);
     void importAll(Dsymbol *d, Scope *sc);
 }
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 2958d955f4fa399136a1556d20616ccc164cbc48..173532af397c810c2b9dcd5df219c84b01fe82bd 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -67,6 +67,7 @@ import dmd.root.filename;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.rootobject;
+import dmd.safe;
 import dmd.semantic2;
 import dmd.semantic3;
 import dmd.sideeffect;
@@ -313,7 +314,7 @@ Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool find
             Loc loc = e.loc;
             Type tthis = (e.op == EXP.type ? e.type : null);
             const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
-            uint olderrors = gag ? global.startGagging() : 0;
+            const olderrors = gag ? global.startGagging() : 0;
             e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
             if (!e || findOnly)
                 return gag && global.endGagging(olderrors) ? null : e;
@@ -1434,7 +1435,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
                  */
                 if (!inferred)
                 {
-                    uint errors = global.errors;
+                    const errors = global.errors;
                     dsym.inuse++;
                     // Bug 20549. Don't try this on modules or packages, syntaxCopy
                     // could crash (inf. recursion) on a mod/pkg referencing itself
@@ -1831,7 +1832,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
     {
         //printf("MixinDeclaration::compileIt(loc = %d) %s\n", cd.loc.linnum, cd.exp.toChars());
         OutBuffer buf;
-        if (expressionsToString(buf, sc, cd.exps))
+        if (expressionsToString(buf, sc, cd.exps, cd.loc, null, true))
             return null;
 
         const errors = global.errors;
@@ -1841,7 +1842,6 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         const bool doUnittests = global.params.parsingUnittestsRequired();
         auto loc = adjustLocForMixin(str, cd.loc, global.params.mixinOut);
         scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
-        p.transitionIn = global.params.v.vin;
         p.nextToken();
 
         auto d = p.parseDeclDefs(0);
@@ -2214,7 +2214,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         tm.argsym.parent = scy.parent;
         Scope* argscope = scy.push(tm.argsym);
 
-        uint errorsave = global.errors;
+        const errorsave = global.errors;
 
         // Declare each template parameter as an alias for the argument type
         tm.declareParameters(argscope);
@@ -2359,7 +2359,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         ns.semanticRun = PASS.semantic;
         ns.parent = sc.parent;
         // Link does not matter here, if the UDA is present it will error
-        UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+        checkGNUABITag(ns, LINK.cpp);
 
         if (!ns.members)
         {
@@ -2842,7 +2842,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (sd.semanticRun >= PASS.semanticdone)
             return;
-        int errors = global.errors;
+        const errors = global.errors;
 
         //printf("+StructDeclaration::semantic(this=%p, '%s', sizeok = %d)\n", sd, sd.toPrettyChars(), sd.sizeok);
         Scope* scx = null;
@@ -2909,7 +2909,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return;
 
         sd.semanticRun = PASS.semantic;
-        UserAttributeDeclaration.checkGNUABITag(sd, sc.linkage);
+        checkGNUABITag(sd, sc.linkage);
 
         if (!sd.members) // if opaque declaration
         {
@@ -3004,7 +3004,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             Dsymbol scall = sd.search(Loc.initial, Id.call);
             if (scall)
             {
-                uint xerrors = global.startGagging();
+                const xerrors = global.startGagging();
                 sc = sc.push();
                 sc.tinst = null;
                 sc.minst = null;
@@ -3089,7 +3089,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         if (cldec.semanticRun >= PASS.semanticdone)
             return;
-        int errors = global.errors;
+        const errors = global.errors;
 
         //printf("+ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
 
@@ -3149,7 +3149,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return;
         }
         cldec.semanticRun = PASS.semantic;
-        UserAttributeDeclaration.checkGNUABITag(cldec, sc.linkage);
+        checkGNUABITag(cldec, sc.linkage);
         checkMustUseReserved(cldec);
 
         if (cldec.baseok < Baseok.done)
@@ -3752,7 +3752,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
         //printf("InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
         if (idec.semanticRun >= PASS.semanticdone)
             return;
-        int errors = global.errors;
+        const errors = global.errors;
 
         //printf("+InterfaceDeclaration.dsymbolSemantic(%s), type = %p\n", toChars(), type);
 
@@ -3861,7 +3861,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor
             if (!idec.baseclasses.length && sc.linkage == LINK.cpp)
                 idec.classKind = ClassKind.cpp;
             idec.cppnamespace = sc.namespace;
-            UserAttributeDeclaration.checkGNUABITag(idec, sc.linkage);
+            checkGNUABITag(idec, sc.linkage);
             checkMustUseReserved(idec);
 
             if (sc.linkage == LINK.objc)
@@ -4082,7 +4082,7 @@ private extern(C++) class AddMemberVisitor : Visitor
     Scope* sc;
     ScopeDsymbol sds;
 
-    this(Scope* sc, ScopeDsymbol sds)
+    this(Scope* sc, ScopeDsymbol sds) @safe
     {
         this.sc = sc;
         this.sds = sds;
@@ -4715,6 +4715,15 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
                     visit(cast(Dsymbol)sds);
                 }
 
+                override void visit(StructDeclaration sd)
+                {
+                    // need to visit auto-generated methods as well
+                    if (sd.xeq) visit(sd.xeq);
+                    if (sd.xcmp) visit(sd.xcmp);
+                    if (sd.xhash) visit(sd.xhash);
+                    visit(cast(ScopeDsymbol)sd);
+                }
+
                 override void visit(AttribDeclaration ad)
                 {
                     ad.include(null).foreachDsymbol( s => s.accept(this) );
@@ -4762,7 +4771,7 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
         printf("\timplement template instance %s '%s'\n", tempdecl.parent.toChars(), tempinst.toChars());
         printf("\ttempdecl %s\n", tempdecl.toChars());
     }
-    uint errorsave = global.errors;
+    const errorsave = global.errors;
 
     tempinst.inst = tempinst;
     tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent;
@@ -5927,67 +5936,6 @@ private void writeMixin(const(char)[] s, ref const Loc loc, ref int lines, ref O
     ++lines;
 }
 
-/**
- * Check signature of `pragma(printf)` function, print error if invalid.
- *
- * printf/scanf-like functions must be of the form:
- *    extern (C/C++) T printf([parameters...], const(char)* format, ...);
- * or:
- *    extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
- *
- * Params:
- *      funcdecl = function to check
- *      f = function type
- *      sc = scope
- */
-void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc)
-{
-    static bool isPointerToChar(Parameter p)
-    {
-        if (auto tptr = p.type.isTypePointer())
-        {
-            return tptr.next.ty == Tchar;
-        }
-        return false;
-    }
-
-    bool isVa_list(Parameter p)
-    {
-        return p.type.equals(target.va_listType(funcdecl.loc, sc));
-    }
-
-    const nparams = f.parameterList.length;
-    const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars();
-    if (!(f.linkage == LINK.c || f.linkage == LINK.cpp))
-    {
-        .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage,"
-            ~" not `extern(%s)`",
-            p, funcdecl.toChars(), f.linkage.linkageToChars());
-    }
-    if (f.parameterList.varargs == VarArg.variadic)
-    {
-        if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1])))
-        {
-            .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"
-                ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`",
-                p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars());
-        }
-    }
-    else if (f.parameterList.varargs == VarArg.none)
-    {
-        if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) &&
-            isVa_list(f.parameterList[nparams - 1])))
-            .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~
-                " signature `%s %s([parameters...], const(char)*, va_list)`",
-                p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars());
-    }
-    else
-    {
-        .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter",
-            p, funcdecl.toChars());
-    }
-}
-
 /*********************************************
  * Search for ident as member of d.
  * Params:
@@ -6045,7 +5993,7 @@ private extern(C++) class SearchVisitor : Visitor
     SearchOptFlags flags;
     Dsymbol result;
 
-    this(const ref Loc loc, Identifier ident, SearchOptFlags flags)
+    this(const ref Loc loc, Identifier ident, SearchOptFlags flags) @safe
     {
         this.loc = loc;
         this.ident = ident;
@@ -6522,7 +6470,7 @@ private extern(C++) class SearchVisitor : Visitor
             return setResult(m.searchCacheSymbol);
         }
 
-        uint errors = global.errors;
+        const errors = global.errors;
 
         m.insearch = true;
         visit(cast(ScopeDsymbol)m);
@@ -6651,7 +6599,7 @@ private extern(C++) class SetScopeVisitor : Visitor
     alias visit = typeof(super).visit;
     Scope* sc;
 
-    this(Scope* sc)
+    this(Scope* sc) @safe
     {
         this.sc = sc;
     }
@@ -6794,7 +6742,7 @@ extern(C++) class ImportAllVisitor : Visitor
     alias visit = typeof(super).visit;
     Scope* sc;
 
-    this(Scope* sc)
+    this(Scope* sc) @safe
     {
         this.sc = sc;
     }
@@ -6873,7 +6821,7 @@ extern(C++) class ImportAllVisitor : Visitor
              (*m.members)[0].ident != Id.object ||
              (*m.members)[0].isImport() is null))
         {
-            auto im = new Import(Loc.initial, null, Id.object, null, 0);
+            auto im = new Import(m.loc, null, Id.object, null, 0);
             m.members.shift(im);
         }
         if (!m.symtab)
@@ -6960,7 +6908,7 @@ extern (D) bool load(Import imp, Scope* sc)
             {
                 if (p.isPkgMod == PKG.unknown)
                 {
-                    uint preverrors = global.errors;
+                    const preverrors = global.errors;
                     imp.mod = Module.load(imp.loc, imp.packages, imp.id);
                     if (!imp.mod)
                         p.isPkgMod = PKG.package_;
@@ -7037,7 +6985,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
     FieldState* fieldState;
     bool isunion;
 
-    this(AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+    this(AggregateDeclaration ad, FieldState* fieldState, bool isunion) @safe
     {
         this.ad = ad;
         this.fieldState = fieldState;
@@ -7126,7 +7074,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
         assert(sz != SIZE_INVALID && sz < uint.max);
         uint memsize = cast(uint)sz;                // size of member
         uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
-        vd.offset = placeField(
+        vd.offset = placeField(vd.loc,
             fieldState.offset,
             memsize, memalignsize, vd.alignment,
             ad.structsize, ad.alignsize,
@@ -7173,12 +7121,19 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth);
 
         const style = target.c.bitFieldStyle;
+        if (style != TargetC.BitFieldStyle.MS && style != TargetC.BitFieldStyle.Gcc_Clang)
+            assert(0, "unsupported bit-field style");
+
+        const isMicrosoftStyle = style == TargetC.BitFieldStyle.MS;
+        const contributesToAggregateAlignment = target.c.contributesToAggregateAlignment(bfd);
 
         void startNewField()
         {
             if (log) printf("startNewField()\n");
             uint alignsize;
-            if (style == TargetC.BitFieldStyle.Gcc_Clang)
+            if (isMicrosoftStyle)
+               alignsize = memsize; // not memalignsize
+            else
             {
                 if (bfd.fieldWidth > 32)
                     alignsize = memalignsize;
@@ -7189,15 +7144,13 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
                 else
                     alignsize = 1;
             }
-            else
-                alignsize = memsize; // not memalignsize
 
             uint dummy;
-            bfd.offset = placeField(
+            bfd.offset = placeField(bfd.loc,
                 fieldState.offset,
                 memsize, alignsize, bfd.alignment,
                 ad.structsize,
-                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
+                contributesToAggregateAlignment ? ad.alignsize : dummy,
                 isunion);
 
             fieldState.inFlight = true;
@@ -7206,45 +7159,30 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             fieldState.fieldSize = memsize;
         }
 
-        if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        if (ad.alignsize == 0)
+            ad.alignsize = 1;
+        if (!isMicrosoftStyle && contributesToAggregateAlignment && ad.alignsize < memalignsize)
+            ad.alignsize = memalignsize;
+
+        if (bfd.fieldWidth == 0)
         {
-            if (bfd.fieldWidth == 0)
+            if (!isMicrosoftStyle && !isunion)
             {
-                if (!isunion)
-                {
-                    // Use type of zero width field to align to next field
-                    fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
-                    ad.structsize = fieldState.offset;
-                }
-
-                fieldState.inFlight = false;
-                return;
+                // Use type of zero width field to align to next field
+                fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+                ad.structsize = fieldState.offset;
             }
-
-            if (ad.alignsize == 0)
-                ad.alignsize = 1;
-            if (!anon &&
-                  ad.alignsize < memalignsize)
-                ad.alignsize = memalignsize;
-        }
-        else if (style == TargetC.BitFieldStyle.MS)
-        {
-            if (ad.alignsize == 0)
-                ad.alignsize = 1;
-            if (bfd.fieldWidth == 0)
+            else if (isMicrosoftStyle && fieldState.inFlight && !isunion)
             {
-                if (fieldState.inFlight && !isunion)
-                {
-                    // documentation says align to next int
-                    //const alsz = cast(uint)Type.tint32.size();
-                    const alsz = memsize; // but it really does this
-                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
-                    ad.structsize = fieldState.offset;
-                }
-
-                fieldState.inFlight = false;
-                return;
+                // documentation says align to next int
+                //const alsz = cast(uint)Type.tint32.size();
+                const alsz = memsize; // but it really does this
+                fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+                ad.structsize = fieldState.offset;
             }
+
+            fieldState.inFlight = false;
+            return;
         }
 
         if (!fieldState.inFlight)
@@ -7252,7 +7190,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             //printf("not in flight\n");
             startNewField();
         }
-        else if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        else if (!isMicrosoftStyle)
         {
             // If the bit-field spans more units of alignment than its type
             // and is at the alignment boundary, start a new field at the
@@ -7277,7 +7215,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
                 }
             }
         }
-        else if (style == TargetC.BitFieldStyle.MS)
+        else
         {
             if (memsize != fieldState.fieldSize ||
                 fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8)
@@ -7286,14 +7224,14 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
                 startNewField();
             }
         }
-        else
-            assert(0);
 
         bfd.offset = fieldState.fieldOffset;
         bfd.bitOffset = fieldState.bitOffset;
 
         const pastField = bfd.bitOffset + bfd.fieldWidth;
-        if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        if (isMicrosoftStyle)
+            fieldState.fieldSize = memsize;
+        else
         {
             auto size = (pastField + 7) / 8;
             fieldState.fieldSize = size;
@@ -7307,8 +7245,6 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             else
                 ad.structsize = bfd.offset + size;
         }
-        else
-            fieldState.fieldSize = memsize;
         //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
         //print(fieldState);
 
@@ -7395,7 +7331,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             /* Given the anon 'member's size and alignment,
              * go ahead and place it.
              */
-            anond.anonoffset = placeField(
+            anond.anonoffset = placeField(anond.loc,
                 fieldState.offset,
                 anond.anonstructsize, anond.anonalignsize, alignment,
                 ad.structsize, ad.alignsize,
@@ -7412,3 +7348,500 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
         }
     }
 }
+
+extern(D) Scope* newScope(Dsymbol d, Scope* sc)
+{
+    scope nsv = new NewScopeVisitor(sc);
+    d.accept(nsv);
+    return nsv.sc;
+}
+
+private extern(C++) class NewScopeVisitor : Visitor
+{
+    alias visit = typeof(super).visit;
+    Scope* sc;
+    this(Scope* sc)
+    {
+        this.sc = sc;
+    }
+
+    /****************************************
+     * A hook point to supply scope for members.
+     * addMember, setScope, importAll, semantic, semantic2 and semantic3 will use this.
+     */
+    override void visit(AttribDeclaration dc){}
+
+    override void visit(StorageClassDeclaration swt)
+    {
+        StorageClass scstc = sc.stc;
+        /* These sets of storage classes are mutually exclusive,
+         * so choose the innermost or most recent one.
+         */
+        if (swt.stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest))
+            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.manifest);
+        if (swt.stc & (STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared))
+            scstc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.manifest | STC.gshared);
+        if (swt.stc & (STC.const_ | STC.immutable_ | STC.manifest))
+            scstc &= ~(STC.const_ | STC.immutable_ | STC.manifest);
+        if (swt.stc & (STC.gshared | STC.shared_))
+            scstc &= ~(STC.gshared | STC.shared_);
+        if (swt.stc & (STC.safe | STC.trusted | STC.system))
+            scstc &= ~(STC.safe | STC.trusted | STC.system);
+        scstc |= swt.stc;
+        //printf("scstc = x%llx\n", scstc);
+        sc = swt.createNewScope(sc, scstc, sc.linkage, sc.cppmangle,
+        sc.visibility, sc.explicitVisibility, sc.aligndecl, sc.inlining);
+    }
+
+    /**
+     * Provides a new scope with `STC.deprecated_` and `Scope.depdecl` set
+     *
+     * Calls `StorageClassDeclaration.newScope` (as it must be called or copied
+     * in any function overriding `newScope`), then set the `Scope`'s depdecl.
+     *
+     * Returns:
+     *   Always a new scope, to use for this `DeprecatedDeclaration`'s members.
+     */
+    override void visit(DeprecatedDeclaration dpd)
+    {
+        auto oldsc = sc;
+        visit((cast(StorageClassDeclaration)dpd));
+        auto scx = sc;
+        sc = oldsc;
+        // The enclosing scope is deprecated as well
+        if (scx == sc)
+            scx = sc.push();
+        scx.depdecl = dpd;
+        sc = scx;
+    }
+
+    override void visit(LinkDeclaration  lid)
+    {
+        sc= lid.createNewScope(sc, sc.stc, lid.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility,
+        sc.aligndecl, sc.inlining);
+    }
+
+    override void visit(CPPMangleDeclaration cpmd)
+    {
+        sc = cpmd.createNewScope(sc, sc.stc, LINK.cpp, cpmd.cppmangle, sc.visibility, sc.explicitVisibility,
+        sc.aligndecl, sc.inlining);
+    }
+
+    /**
+     * Returns:
+     *   A copy of the parent scope, with `this` as `namespace` and C++ linkage
+     *///override Scope* visit(Scope* sc)
+    override void visit(CPPNamespaceDeclaration scd)
+    {
+        auto scx = sc.copy();
+        scx.linkage = LINK.cpp;
+        scx.namespace = scd;
+        sc = scx;
+    }
+
+    override void visit(VisibilityDeclaration atbd)
+    {
+        if (atbd.pkg_identifiers)
+            dsymbolSemantic(atbd, sc);
+
+       sc = atbd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, atbd.visibility, 1, sc.aligndecl, sc.inlining);
+    }
+
+    override void visit(AlignDeclaration visd)
+    {
+        sc = visd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility,
+        sc.explicitVisibility, visd, sc.inlining);
+    }
+
+    override void visit(PragmaDeclaration prd)
+    {
+        if (prd.ident == Id.Pinline)
+        {
+            // We keep track of this pragma inside scopes,
+            // then it's evaluated on demand in function semantic
+            sc = prd.createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, sc.visibility, sc.explicitVisibility, sc.aligndecl, prd); // @suppress(dscanner.style.long_line)
+        }
+    }
+
+    /**************************************
+     * Use the ForwardingScopeDsymbol as the parent symbol for members.
+     */
+    override void visit(ForwardingAttribDeclaration  fad)
+    {
+        sc = sc.push(fad.sym);
+    }
+
+    override void visit(UserAttributeDeclaration uac)
+    {
+        Scope* sc2 = sc;
+        if (uac.atts && uac.atts.length)
+        {
+            // create new one for changes
+            sc2 = sc.copy();
+            sc2.userAttribDecl = uac;
+        }
+        sc = sc2;
+    }
+}
+
+
+extern(C++) Dsymbols* include(Dsymbol d, Scope* sc)
+{
+    scope icv = new IncludeVisitor(sc);
+    d.accept(icv);
+    return icv.symbols;
+}
+
+extern(C++) class IncludeVisitor : Visitor
+{
+    alias visit = typeof(super).visit;
+    Scope* sc;
+    Dsymbols* symbols;
+    this(Scope* sc)
+    {
+        this.sc = sc;
+    }
+
+    override void visit(AttribDeclaration ad)
+    {
+        if (ad.errors)
+        {
+            symbols = null;
+            return;
+        }
+        symbols = ad.decl;
+        return;
+    }
+
+// Decide if 'then' or 'else' code should be included
+    override void visit(ConditionalDeclaration cdc)
+    {
+        //printf("ConditionalDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
+
+        if (cdc.errors)
+        {
+            symbols = null;
+            return;
+        }
+        assert(cdc.condition);
+        symbols = cdc.condition.include(cdc._scope ? cdc._scope : sc) ? cdc.decl : cdc.elsedecl;
+    }
+
+    override void visit(StaticIfDeclaration sif)
+    {
+    /****************************************
+     * Different from other AttribDeclaration subclasses, include() call requires
+     * the completion of addMember and setScope phases.
+     */
+        //printf("StaticIfDeclaration::include(sc = %p) scope = %p\n", sc, _scope);
+        if (sif.errors || sif.onStack)
+        {
+            symbols = null;
+            return;
+        }
+        sif.onStack = true;
+        scope(exit) sif.onStack = false;
+
+        if (sc && sif.condition.inc == Include.notComputed)
+        {
+            assert(sif.scopesym); // addMember is already done
+            assert(sif._scope); // setScope is already done
+
+            Scope* saved_scope = sc;
+            sc = sif._scope;
+            visit(cast(ConditionalDeclaration) sif);
+            Dsymbols* d = symbols;
+            sc = saved_scope;
+
+            if (d && !sif.addisdone)
+            {
+                // Add members lazily.
+                d.foreachDsymbol( s => s.addMember(sif._scope, sif.scopesym) );
+
+                // Set the member scopes lazily.
+                d.foreachDsymbol( s => s.setScope(sif._scope) );
+
+                sif.addisdone = true;
+            }
+            symbols = d;
+            return;
+        }
+        else
+        {
+            visit(cast(ConditionalDeclaration)sif);
+        }
+    }
+
+    override void visit(StaticForeachDeclaration sfd)
+    {
+        if (sfd.errors || sfd.onStack)
+        {
+            symbols = null;
+            return;
+        }
+        if (sfd.cached)
+        {
+            assert(!sfd.onStack);
+            symbols = sfd.cache;
+            return;
+        }
+        sfd.onStack = true;
+        scope(exit) sfd.onStack = false;
+
+        if (sfd._scope)
+        {
+            sfd.sfe.prepare(sfd._scope); // lower static foreach aggregate
+        }
+        if (!sfd.sfe.ready())
+        {
+            symbols = null;// TODO: ok?
+            return;
+        }
+
+        // expand static foreach
+        import dmd.statementsem: makeTupleForeach;
+        Dsymbols* d = makeTupleForeach(sfd._scope, true, true, sfd.sfe.aggrfe, sfd.decl, sfd.sfe.needExpansion).decl;
+        if (d) // process generated declarations
+        {
+            // Add members lazily.
+            d.foreachDsymbol( s => s.addMember(sfd._scope, sfd.scopesym) );
+
+            // Set the member scopes lazily.
+            d.foreachDsymbol( s => s.setScope(sfd._scope) );
+        }
+        sfd.cached = true;
+        sfd.cache = d;
+        symbols = d;
+    }
+}
+
+/**
+ * Called from a symbol's semantic to check if `gnuAbiTag` UDA
+ * can be applied to them
+ *
+ * Directly emits an error if the UDA doesn't work with this symbol
+ *
+ * Params:
+ *   sym = symbol to check for `gnuAbiTag`
+ *   linkage = Linkage of the symbol (Declaration.link or sc.link)
+ */
+void checkGNUABITag(Dsymbol sym, LINK linkage)
+{
+    if (global.params.cplusplus < CppStdRevision.cpp11)
+        return;
+
+    foreachUdaNoSemantic(sym, (exp) {
+        if (!isGNUABITag(exp))
+            return 0; // continue
+        if (sym.isCPPNamespaceDeclaration() || sym.isNspace())
+        {
+            .error(exp.loc, "`@%s` cannot be applied to namespaces", Id.udaGNUAbiTag.toChars());
+            sym.errors = true;
+        }
+        else if (linkage != LINK.cpp)
+        {
+            .error(exp.loc, "`@%s` can only apply to C++ symbols", Id.udaGNUAbiTag.toChars());
+            sym.errors = true;
+        }
+        // Only one `@gnuAbiTag` is allowed by semantic2
+        return 1; // break
+    });
+}
+
+/**
+ * Check if the provided expression references `core.attribute.gnuAbiTag`
+ *
+ * This should be called after semantic has been run on the expression.
+ * Semantic on UDA happens in semantic2 (see `dmd.semantic2`).
+ *
+ * Params:
+ *   e = Expression to check (usually from `UserAttributeDeclaration.atts`)
+ *
+ * Returns:
+ *   `true` if the expression references the compiler-recognized `gnuAbiTag`
+ */
+bool isGNUABITag(Expression e)
+{
+    if (global.params.cplusplus < CppStdRevision.cpp11)
+        return false;
+
+    auto ts = e.type ? e.type.isTypeStruct() : null;
+    if (!ts)
+        return false;
+    if (ts.sym.ident != Id.udaGNUAbiTag || !ts.sym.parent)
+        return false;
+    // Can only be defined in druntime
+    Module m = ts.sym.parent.isModule();
+    if (!m || !m.isCoreModule(Id.attribute))
+        return false;
+    return true;
+}
+
+/******************************************
+ * If a variable has a scope destructor call, return call for it.
+ * Otherwise, return NULL.
+ */
+private Expression callScopeDtor(VarDeclaration vd, Scope* sc)
+{
+    //printf("VarDeclaration::callScopeDtor() %s\n", toChars());
+
+    // Destruction of STC.field's is handled by buildDtor()
+    if (vd.storage_class & (STC.nodtor | STC.ref_ | STC.out_ | STC.field))
+    {
+        return null;
+    }
+
+    if (vd.iscatchvar)
+        return null;    // destructor is built by `void semantic(Catch c, Scope* sc)`, not here
+
+    Expression e = null;
+    // Destructors for structs and arrays of structs
+    Type tv = vd.type.baseElemOf();
+    if (tv.ty == Tstruct)
+    {
+        StructDeclaration sd = (cast(TypeStruct)tv).sym;
+        if (!sd.dtor || sd.errors)
+            return null;
+
+        const sz = vd.type.size();
+        assert(sz != SIZE_INVALID);
+        if (!sz)
+            return null;
+
+        if (vd.type.toBasetype().ty == Tstruct)
+        {
+            // v.__xdtor()
+            e = new VarExp(vd.loc, vd);
+
+            /* This is a hack so we can call destructors on const/immutable objects.
+             * Need to add things like "const ~this()" and "immutable ~this()" to
+             * fix properly.
+             */
+            e.type = e.type.mutableOf();
+
+            // Enable calling destructors on shared objects.
+            // The destructor is always a single, non-overloaded function,
+            // and must serve both shared and non-shared objects.
+            e.type = e.type.unSharedOf;
+
+            e = new DotVarExp(vd.loc, e, sd.dtor, false);
+            e = new CallExp(vd.loc, e);
+        }
+        else
+        {
+            // __ArrayDtor(v[0 .. n])
+            e = new VarExp(vd.loc, vd);
+
+            const sdsz = sd.type.size();
+            assert(sdsz != SIZE_INVALID && sdsz != 0);
+            const n = sz / sdsz;
+            SliceExp se = new SliceExp(vd.loc, e, new IntegerExp(vd.loc, 0, Type.tsize_t),
+                new IntegerExp(vd.loc, n, Type.tsize_t));
+
+            // Prevent redundant bounds check
+            se.upperIsInBounds = true;
+            se.lowerIsLessThanUpper = true;
+
+            // This is a hack so we can call destructors on const/immutable objects.
+            se.type = sd.type.arrayOf();
+
+            e = new CallExp(vd.loc, new IdentifierExp(vd.loc, Id.__ArrayDtor), se);
+        }
+        return e;
+    }
+    // Destructors for classes
+    if (!(vd.storage_class & (STC.auto_ | STC.scope_) && !(vd.storage_class & STC.parameter)))
+        return null;
+
+    for (ClassDeclaration cd = vd.type.isClassHandle(); cd; cd = cd.baseClass)
+    {
+        /* We can do better if there's a way with onstack
+         * classes to determine if there's no way the monitor
+         * could be set.
+         */
+        //if (cd.isInterfaceDeclaration())
+        //    error("interface `%s` cannot be scope", cd.toChars());
+
+        if (!vd.onstack) // if any destructors
+            continue;
+        // delete'ing C++ classes crashes (and delete is deprecated anyway)
+        if (cd.classKind == ClassKind.cpp)
+        {
+            // Don't call non-existant dtor
+            if (!cd.dtor)
+                break;
+
+            e = new VarExp(vd.loc, vd);
+            e.type = e.type.mutableOf().unSharedOf(); // Hack for mutable ctor on immutable instances
+            e = new DotVarExp(vd.loc, e, cd.dtor, false);
+            e = new CallExp(vd.loc, e);
+            break;
+        }
+
+        // delete this;
+        Expression ec;
+        ec = new VarExp(vd.loc, vd);
+        e = new DeleteExp(vd.loc, ec, true);
+        e.type = Type.tvoid;
+        break;
+    }
+    return e;
+}
+
+/***************************************
+ * Collect all instance fields, then determine instance size.
+ * Returns:
+ *      false if failed to determine the size.
+ */
+bool determineSize(AggregateDeclaration ad, const ref Loc loc)
+{
+    //printf("AggregateDeclaration::determineSize() %s, sizeok = %d\n", toChars(), sizeok);
+
+    // The previous instance size finalizing had:
+    if (ad.type.ty == Terror || ad.errors)
+        return false;   // failed already
+    if (ad.sizeok == Sizeok.done)
+        return true;    // succeeded
+
+    if (!ad.members)
+    {
+        .error(loc, "%s `%s` unknown size", ad.kind, ad.toPrettyChars);
+        return false;
+    }
+
+    if (ad._scope)
+        dsymbolSemantic(ad, null);
+
+    // Determine the instance size of base class first.
+    if (auto cd = ad.isClassDeclaration())
+    {
+        cd = cd.baseClass;
+        if (cd && !cd.determineSize(loc))
+            goto Lfail;
+    }
+
+    // Determine instance fields when sizeok == Sizeok.none
+    if (!ad.determineFields())
+        goto Lfail;
+    if (ad.sizeok != Sizeok.done)
+        ad.finalizeSize();
+
+    // this aggregate type has:
+    if (ad.type.ty == Terror)
+        return false;   // marked as invalid during the finalizing.
+    if (ad.sizeok == Sizeok.done)
+        return true;    // succeeded to calculate instance size.
+
+Lfail:
+    // There's unresolvable forward reference.
+    if (ad.type != Type.terror)
+        error(loc, "%s `%s` no size because of forward reference", ad.kind, ad.toPrettyChars);
+    // Don't cache errors from speculative semantic, might be resolvable later.
+    // https://issues.dlang.org/show_bug.cgi?id=16574
+    if (!global.gag)
+    {
+        ad.type = Type.terror;
+        ad.errors = true;
+    }
+    return false;
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index fe601207408fba8181a5616d3a482ca2cd70597c..d46e4661a0874a82cd5e28867d6073f1e144549c 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -50,36 +50,36 @@ import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
+import dmd.dsymbolsem : dsymbolSemantic, checkDeprecated, aliasSemantic, search, search_correct, setScope, importAll, include;
 import dmd.errors;
 import dmd.errorsink;
 import dmd.expression;
-import dmd.expressionsem;
+import dmd.expressionsem : resolveLoc, expressionSemantic, resolveProperties;
 import dmd.func;
-import dmd.funcsem;
+import dmd.funcsem : functionSemantic, leastAsSpecialized, overloadApply;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.impcnvtab;
 import dmd.init;
-import dmd.initsem;
 import dmd.location;
+import dmd.mangle;
 import dmd.mtype;
 import dmd.opover;
 import dmd.optimize;
 import dmd.root.array;
 import dmd.common.outbuffer;
 import dmd.rootobject;
-import dmd.semantic2;
-import dmd.semantic3;
-import dmd.templatesem;
+import dmd.semantic3 : semantic3;
+import dmd.templatesem : matchWithInstance, formatParamsWithTiargs, leastAsSpecialized, declareParameter;
 import dmd.tokens;
-import dmd.typesem;
+import dmd.typesem : hasPointers, typeSemantic, merge, merge2, resolve, toDsymbol,
+                     addStorageClass, isBaseOf, equivalent, sarrayOf, constOf, mutableOf, unSharedOf,
+                     unqualify, aliasthisOf, castMod, substWildTo, addMod;
 import dmd.visitor;
 
 import dmd.templateparamsem;
@@ -1695,7 +1695,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
                     edim = s ? getValue(s) : getValue(e);
                 }
             }
-            if (tp && tp.matchArg(sc, t.dim, i, &parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
+            if ((tp && tp.matchArg(sc, t.dim, i, &parameters, dedtypes, null)) ||
+                (edim && edim.isIntegerExp() && edim.toInteger() == t.dim.toInteger())
+            )
             {
                 result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
                 return;
@@ -3235,10 +3237,6 @@ extern (C++) class TemplateParameter : ASTNode
         return DYNCAST.templateparameter;
     }
 
-    /* Create dummy argument based on parameter.
-     */
-    abstract RootObject dummyArg();
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3319,19 +3317,6 @@ extern (C++) class TemplateTypeParameter : TemplateParameter
         return defaultType !is null;
     }
 
-    override final RootObject dummyArg()
-    {
-        Type t = specType;
-        if (!t)
-        {
-            // Use this for alias-parameter's too (?)
-            if (!tdummy)
-                tdummy = new TypeIdentifier(loc, ident);
-            t = tdummy;
-        }
-        return t;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3439,34 +3424,35 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
     override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         Expression e = defaultValue;
-        if (e)
-        {
-            e = e.syntaxCopy();
-            Scope* sc2 = sc.push();
-            sc2.inDefaultArg = true;
-            e = e.expressionSemantic(sc2);
-            sc2.pop();
-            if (e is null)
-                return null;
-            if (auto te = e.isTemplateExp())
+        if (!e)
+            return null;
+
+        e = e.syntaxCopy();
+        Scope* sc2 = sc.push();
+        sc2.inDefaultArg = true;
+        e = e.expressionSemantic(sc2);
+        sc2.pop();
+        if (e is null)
+            return null;
+        if (auto te = e.isTemplateExp())
+        {
+            assert(sc && sc.tinst);
+            if (te.td == sc.tinst.tempdecl)
             {
-                assert(sc && sc.tinst);
-                if (te.td == sc.tinst.tempdecl)
-                {
-                    // defaultValue is a reference to its template declaration
-                    // i.e: `template T(int arg = T)`
-                    // Raise error now before calling resolveProperties otherwise we'll
-                    // start looping on the expansion of the template instance.
-                    auto td = sc.tinst.tempdecl;
-                    .error(td.loc, "%s `%s` recursive template expansion", td.kind, td.toPrettyChars);
-                    return ErrorExp.get();
-                }
+                // defaultValue is a reference to its template declaration
+                // i.e: `template T(int arg = T)`
+                // Raise error now before calling resolveProperties otherwise we'll
+                // start looping on the expansion of the template instance.
+                auto td = sc.tinst.tempdecl;
+                .error(td.loc, "%s `%s` recursive template expansion", td.kind, td.toPrettyChars);
+                return ErrorExp.get();
             }
-            if ((e = resolveProperties(sc, e)) is null)
-                return null;
-            e = e.resolveLoc(instLoc, sc); // use the instantiated loc
-            e = e.optimize(WANTvalue);
         }
+        if ((e = resolveProperties(sc, e)) is null)
+            return null;
+        e = e.resolveLoc(instLoc, sc); // use the instantiated loc
+        e = e.optimize(WANTvalue);
+
         return e;
     }
 
@@ -3475,24 +3461,6 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
         return defaultValue !is null;
     }
 
-    override RootObject dummyArg()
-    {
-        Expression e = specValue;
-        if (!e)
-        {
-            // Create a dummy value
-            auto pe = cast(void*)valType in edummies;
-            if (!pe)
-            {
-                e = valType.defaultInit(Loc.initial);
-                edummies[cast(void*)valType] = e;
-            }
-            else
-                e = *pe;
-        }
-        return e;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3578,18 +3546,6 @@ extern (C++) final class TemplateAliasParameter : TemplateParameter
         return defaultAlias !is null;
     }
 
-    override RootObject dummyArg()
-    {
-        RootObject s = specAlias;
-        if (!s)
-        {
-            if (!sdummy)
-                sdummy = new Dsymbol();
-            s = sdummy;
-        }
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3667,11 +3623,6 @@ extern (C++) final class TemplateTupleParameter : TemplateParameter
         return false;
     }
 
-    override RootObject dummyArg()
-    {
-        return null;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3704,7 +3655,22 @@ extern (C++) class TemplateInstance : ScopeDsymbol
     Dsymbol tempdecl;           // referenced by foo.bar.abc
     Dsymbol enclosing;          // if referencing local symbols, this is the context
     Dsymbol aliasdecl;          // !=null if instance is an alias for its sole member
-    TemplateInstance inst;      // refer to existing instance
+
+    /**
+    If this is not null and it has a value that is not the current object,
+     then this field points to an existing template instance
+     and that object has been duplicated into us.
+
+    If this object is a duplicate,
+     the ``memberOf`` field will be set to a root module (passed on CLI).
+
+    This information is useful to deduplicate analysis that may occur
+     after semantic 3 has completed.
+
+    See_Also: memberOf
+    */
+    TemplateInstance inst;
+
     ScopeDsymbol argsym;        // argument symbol table
     size_t hash;                // cached result of toHash()
 
@@ -3716,7 +3682,15 @@ extern (C++) class TemplateInstance : ScopeDsymbol
 
     TemplateInstances* deferred;
 
-    Module memberOf;            // if !null, then this TemplateInstance appears in memberOf.members[]
+    /**
+    If this is not null then this template instance appears in a root module's members.
+
+    Note:   This is not useful for determining duplication status of this template instance.
+            Use the field ``inst`` for determining if a template instance has been duplicated into this object.
+
+    See_Also: inst
+    */
+    Module memberOf;
 
     // Used to determine the instance needs code generation.
     // Note that these are inaccurate until semantic analysis phase completed.
@@ -3914,7 +3888,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             // Set error here as we don't want it to depend on the number of
             // entries that are being printed.
             if (cl == Classification.error ||
-                (cl == Classification.warning && global.params.warnings == DiagnosticReporting.error) ||
+                (cl == Classification.warning && global.params.useWarnings == DiagnosticReporting.error) ||
                 (cl == Classification.deprecation && global.params.useDeprecated == DiagnosticReporting.error))
                 cur.errors = true;
 
@@ -3998,66 +3972,63 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         if (enclosing != ti.enclosing)
         {
             //printf("test2 enclosing %s ti.enclosing %s\n", enclosing ? enclosing.toChars() : "", ti.enclosing ? ti.enclosing.toChars() : "");
-            goto Lnotequals;
+            return false;
         }
         //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
 
         if (!arrayObjectMatch(tdtypes, ti.tdtypes))
-            goto Lnotequals;
+            return false;
 
         /* Template functions may have different instantiations based on
          * "auto ref" parameters.
          */
-        if (auto fd = ti.toAlias().isFuncDeclaration())
-        {
-            if (!fd.errors)
-            {
-                auto resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
-                    ArgumentList(this.fargs, this.fnames), null);
+        auto fd = ti.toAlias().isFuncDeclaration();
+        if (!fd)
+            return true;
+        if (fd.errors)
+            return true;
 
-                // resolvedArgs can be null when there's an error: fail_compilation/fail14669.d
-                // In that case, equalsx returns true to prevent endless template instantiations
-                // However, it can also mean the function was explicitly instantiated
-                // without function arguments: fail_compilation/fail14669
-                // Hence the following check:
-                if (this.fargs && !resolvedArgs)
-                    return true;
+        auto resolvedArgs = fd.type.isTypeFunction().resolveNamedArgs(
+            ArgumentList(this.fargs, this.fnames), null);
 
-                Expression[] args = resolvedArgs ? (*resolvedArgs)[] : [];
+        // resolvedArgs can be null when there's an error: fail_compilation/fail14669.d
+        // In that case, equalsx returns true to prevent endless template instantiations
+        // However, it can also mean the function was explicitly instantiated
+        // without function arguments: fail_compilation/fail14669
+        // Hence the following check:
+        if (this.fargs && !resolvedArgs)
+            return true;
 
-                auto fparameters = fd.getParameterList();
-                size_t nfparams = fparameters.length;   // Num function parameters
-                for (size_t j = 0; j < nfparams; j++)
-                {
-                    Parameter fparam = fparameters[j];
-                    if (fparam.storageClass & STC.autoref)       // if "auto ref"
-                    {
-                        Expression farg = (j < args.length) ? args[j] : fparam.defaultArg;
-                        // resolveNamedArgs strips trailing nulls / default params
-                        // when it doesn't anymore, the ternary can be replaced with:
-                        // assert(j < resolvedArgs.length);
-                        if (!farg)
-                            farg = fparam.defaultArg;
-                        if (!farg)
-                            goto Lnotequals;
-                        if (farg.isLvalue())
-                        {
-                            if (!(fparam.storageClass & STC.ref_))
-                                goto Lnotequals; // auto ref's don't match
-                        }
-                        else
-                        {
-                            if (fparam.storageClass & STC.ref_)
-                                goto Lnotequals; // auto ref's don't match
-                        }
-                    }
-                }
+        Expression[] args = resolvedArgs ? (*resolvedArgs)[] : [];
+
+        auto fparameters = fd.getParameterList();
+        size_t nfparams = fparameters.length;   // Num function parameters
+        for (size_t j = 0; j < nfparams; j++)
+        {
+            Parameter fparam = fparameters[j];
+            if (!(fparam.storageClass & STC.autoref) )      // if "auto ref"
+                continue;
+
+            Expression farg = (j < args.length) ? args[j] : fparam.defaultArg;
+            // resolveNamedArgs strips trailing nulls / default params
+            // when it doesn't anymore, the ternary can be replaced with:
+            // assert(j < resolvedArgs.length);
+            if (!farg)
+                farg = fparam.defaultArg;
+            if (!farg)
+                return false;
+            if (farg.isLvalue())
+            {
+                if (!(fparam.storageClass & STC.ref_))
+                    return false; // auto ref's don't match
+            }
+            else
+            {
+                if (fparam.storageClass & STC.ref_)
+                    return false; // auto ref's don't match
             }
         }
         return true;
-
-    Lnotequals:
-        return false;
     }
 
     extern (D) final size_t toHash()
@@ -4209,77 +4180,75 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             // Elide codegen because there's no instantiation from any root modules.
             return false;
         }
-        else
-        {
-            // Prefer instantiations from non-root modules, to minimize object code size.
 
-            /* If a TemplateInstance is ever instantiated from a non-root module,
-             * we do not have to generate code for it,
-             * because it will be generated when the non-root module is compiled.
-             *
-             * But, if the non-root 'minst' imports any root modules, it might still need codegen.
-             *
-             * The problem is if A imports B, and B imports A, and both A
-             * and B instantiate the same template, does the compilation of A
-             * or the compilation of B do the actual instantiation?
-             *
-             * See https://issues.dlang.org/show_bug.cgi?id=2500.
-             *
-             * => Elide codegen if there is at least one instantiation from a non-root module
-             *    which doesn't import any root modules.
-             */
-            static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
+        // Prefer instantiations from non-root modules, to minimize object code size.
+
+        /* If a TemplateInstance is ever instantiated from a non-root module,
+         * we do not have to generate code for it,
+         * because it will be generated when the non-root module is compiled.
+         *
+         * But, if the non-root 'minst' imports any root modules, it might still need codegen.
+         *
+         * The problem is if A imports B, and B imports A, and both A
+         * and B instantiate the same template, does the compilation of A
+         * or the compilation of B do the actual instantiation?
+         *
+         * See https://issues.dlang.org/show_bug.cgi?id=2500.
+         *
+         * => Elide codegen if there is at least one instantiation from a non-root module
+         *    which doesn't import any root modules.
+         */
+        static ThreeState needsCodegenRootOnly(TemplateInstance tithis, TemplateInstance tinst)
+        {
+            // If the ancestor isn't speculative,
+            // 1. do codegen if the ancestor needs it
+            // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
+            if (tinst && tinst.inst)
             {
-                // If the ancestor isn't speculative,
-                // 1. do codegen if the ancestor needs it
-                // 2. elide codegen if the ancestor doesn't need it (non-root instantiation of ancestor incl. subtree)
-                if (tinst && tinst.inst)
+                tinst = tinst.inst;
+                const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
+                if (tinst.minst) // not speculative
                 {
-                    tinst = tinst.inst;
-                    const needsCodegen = tinst.needsCodegen(); // sets tinst.minst
-                    if (tinst.minst) // not speculative
-                    {
-                        tithis.minst = tinst.minst; // cache result
-                        return needsCodegen ? ThreeState.yes : ThreeState.no;
-                    }
+                    tithis.minst = tinst.minst; // cache result
+                    return needsCodegen ? ThreeState.yes : ThreeState.no;
                 }
+            }
 
-                // Elide codegen if `this` doesn't need it.
-                if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
-                    return ThreeState.no;
+            // Elide codegen if `this` doesn't need it.
+            if (tithis.minst && !tithis.minst.isRoot() && !tithis.minst.rootImports())
+                return ThreeState.no;
 
-                return ThreeState.none;
-            }
+            return ThreeState.none;
+        }
 
-            if (const needsCodegen = needsCodegenRootOnly(this, tinst))
-                return needsCodegen == ThreeState.yes ? true : false;
+        if (const needsCodegen = needsCodegenRootOnly(this, tinst))
+            return needsCodegen == ThreeState.yes ? true : false;
 
-            // Elide codegen if a (non-speculative) sibling doesn't need it.
-            for (; tnext; tnext = tnext.tnext)
+        // Elide codegen if a (non-speculative) sibling doesn't need it.
+        for (; tnext; tnext = tnext.tnext)
+        {
+            const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
+            if (tnext.minst) // not speculative
             {
-                const needsCodegen = needsCodegenRootOnly(tnext, tnext.tinst); // sets tnext.minst
-                if (tnext.minst) // not speculative
+                if (needsCodegen == ThreeState.no)
                 {
-                    if (needsCodegen == ThreeState.no)
-                    {
-                        minst = tnext.minst; // cache result
-                        assert(!minst.isRoot() && !minst.rootImports());
-                        return false;
-                    }
-                    else if (!minst)
-                    {
-                        minst = tnext.minst; // cache result from non-speculative sibling
-                        // continue searching
-                    }
-                    else if (needsCodegen != ThreeState.none)
-                        break;
+                    minst = tnext.minst; // cache result
+                    assert(!minst.isRoot() && !minst.rootImports());
+                    return false;
+                }
+                else if (!minst)
+                {
+                    minst = tnext.minst; // cache result from non-speculative sibling
+                    // continue searching
                 }
+                else if (needsCodegen != ThreeState.none)
+                    break;
             }
-
-            // Unless `this` is still speculative (=> all further siblings speculative too),
-            // do codegen because we found no guaranteed-codegen'd non-root instantiation.
-            return minst !is null;
         }
+
+        // Unless `this` is still speculative (=> all further siblings speculative too),
+        // do codegen because we found no guaranteed-codegen'd non-root instantiation.
+        return minst !is null;
     }
 
     /**********************************************
@@ -4538,9 +4507,13 @@ extern (C++) class TemplateInstance : ScopeDsymbol
 
         // The arguments are not treated as part of a default argument,
         // because they are evaluated at compile time.
+        const inCondition = sc.condition;
         sc = sc.push();
         sc.inDefaultArg = false;
 
+        // https://issues.dlang.org/show_bug.cgi?id=24699
+        sc.condition = inCondition;
+
         for (size_t j = 0; j < tiargs.length; j++)
         {
             RootObject o = (*tiargs)[j];
@@ -4634,7 +4607,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                     {
                         if (ea.checkValue()) // check void expression
                             ea = ErrorExp.get();
-                        uint olderrs = global.errors;
+                        const olderrs = global.errors;
                         ea = ea.ctfeInterpret();
                         if (global.errors != olderrs)
                             ea = ErrorExp.get();
@@ -4846,7 +4819,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             printf("TemplateInstance.findBestMatch()\n");
         }
 
-        uint errs = global.errors;
+        const errs = global.errors;
         TemplateDeclaration td_last = null;
         Objects dedtypes;
 
@@ -5061,135 +5034,6 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         return (errs == global.errors);
     }
 
-    /*****************************************************
-     * Determine if template instance is really a template function,
-     * and that template function needs to infer types from the function
-     * arguments.
-     *
-     * Like findBestMatch, iterate possible template candidates,
-     * but just looks only the necessity of type inference.
-     */
-    extern (D) final bool needsTypeInference(Scope* sc, int flag = 0)
-    {
-        //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
-        if (semanticRun != PASS.initial)
-            return false;
-
-        uint olderrs = global.errors;
-        Objects dedtypes;
-        size_t count = 0;
-
-        auto tovers = tempdecl.isOverloadSet();
-        foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
-        {
-            Dsymbol dstart = tovers ? tovers.a[oi] : tempdecl;
-            int r = overloadApply(dstart, (Dsymbol s)
-            {
-                auto td = s.isTemplateDeclaration();
-                if (!td)
-                    return 0;
-
-                /* If any of the overloaded template declarations need inference,
-                 * then return true
-                 */
-                if (!td.onemember)
-                    return 0;
-                if (auto td2 = td.onemember.isTemplateDeclaration())
-                {
-                    if (!td2.onemember || !td2.onemember.isFuncDeclaration())
-                        return 0;
-                    if (tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
-                        return 0;
-                    return 1;
-                }
-                auto fd = td.onemember.isFuncDeclaration();
-                if (!fd || fd.type.ty != Tfunction)
-                    return 0;
-
-                foreach (tp; *td.parameters)
-                {
-                    if (tp.isTemplateThisParameter())
-                        return 1;
-                }
-
-                /* Determine if the instance arguments, tiargs, are all that is necessary
-                 * to instantiate the template.
-                 */
-                //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
-                auto tf = fd.type.isTypeFunction();
-                if (tf.parameterList.length)
-                {
-                    auto tp = td.isVariadic();
-                    if (tp && td.parameters.length > 1)
-                        return 1;
-
-                    if (!tp && tiargs.length < td.parameters.length)
-                    {
-                        // Can remain tiargs be filled by default arguments?
-                        foreach (size_t i; tiargs.length .. td.parameters.length)
-                        {
-                            if (!(*td.parameters)[i].hasDefaultArg())
-                                return 1;
-                        }
-                    }
-
-                    foreach (i, fparam; tf.parameterList)
-                    {
-                        // 'auto ref' needs inference.
-                        if (fparam.storageClass & STC.auto_)
-                            return 1;
-                    }
-                }
-
-                if (!flag)
-                {
-                    /* Calculate the need for overload resolution.
-                     * When only one template can match with tiargs, inference is not necessary.
-                     */
-                    dedtypes.setDim(td.parameters.length);
-                    dedtypes.zero();
-                    if (td.semanticRun == PASS.initial)
-                    {
-                        if (td._scope)
-                        {
-                            // Try to fix forward reference. Ungag errors while doing so.
-                            Ungag ungag = td.ungagSpeculative();
-                            td.dsymbolSemantic(td._scope);
-                        }
-                        if (td.semanticRun == PASS.initial)
-                        {
-                            .error(loc, "%s `%s` `%s` forward references template declaration `%s`", kind, toPrettyChars, toChars(), td.toChars());
-                            return 1;
-                        }
-                    }
-                    MATCH m = matchWithInstance(sc, td, this, dedtypes, ArgumentList(), 0);
-                    if (m == MATCH.nomatch)
-                        return 0;
-                }
-
-                /* If there is more than one function template which matches, we may
-                 * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
-                 */
-                return ++count > 1 ? 1 : 0;
-            });
-            if (r)
-                return true;
-        }
-
-        if (olderrs != global.errors)
-        {
-            if (!global.gag)
-            {
-                errorSupplemental(loc, "while looking for match for `%s`", toChars());
-                semanticRun = PASS.semanticdone;
-                inst = this;
-            }
-            errors = true;
-        }
-        //printf("false\n");
-        return false;
-    }
-
     /*****************************************
      * Determines if a TemplateInstance will need a nested
      * generation of the TemplateDeclaration.
@@ -6012,7 +5856,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
             /* If a function is really property-like, and then
              * it's CTFEable, ei will be a literal expression.
              */
-            uint olderrors = global.startGagging();
+            const olderrors = global.startGagging();
             ei = resolveProperties(sc, ei);
             ei = ei.ctfeInterpret();
             if (global.endGagging(olderrors) || ei.op == EXP.error)
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 6d39464d57118081ce5d2fca095f1beeb0c40203..296e13c63d51aaeea36bae93fe7a0ab6782e5925 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -512,7 +512,7 @@ public:
             }
         }
 
-        if (global.params.warnings != DiagnosticReporting.off || canFix)
+        if (global.params.useWarnings != DiagnosticReporting.off || canFix)
         {
             // Warn about identifiers that are keywords in C++.
             if (auto kc = keywordClass(ident))
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index 2e3b35264dbe2f4e0ddfd25d92c9d69f69ac164f..36e9cf80189dce0acd9aa4df56337baa7fc97be2 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -20,7 +20,6 @@ import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
 import dmd.dsymbolsem;
-import dmd.errors;
 import dmd.globals;
 import dmd.identifier;
 import dmd.location;
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
index f2eb34c83f91fd231752d01291cfac29cec9c50e..99211e4985484381d9eda6360783726da27a24cc 100644
--- a/gcc/d/dmd/enumsem.d
+++ b/gcc/d/dmd/enumsem.d
@@ -30,7 +30,6 @@ import dmd.declaration;
 import dmd.denum;
 import dmd.dimport;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dstruct;
@@ -119,7 +118,7 @@ void enumSemantic(Scope* sc, EnumDeclaration ed)
     ed.cppnamespace = sc.namespace;
 
     ed.semanticRun = PASS.semantic;
-    UserAttributeDeclaration.checkGNUABITag(ed, sc.linkage);
+    checkGNUABITag(ed, sc.linkage);
     checkMustUseReserved(ed);
 
     if (!ed.members && !ed.memtype) // enum ident;
diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h
index 7a9683b9e67e19123546d6a4be5b561a3f9352b2..448a4f674a8546d7a39c4ae706ffc99bff9b0530 100644
--- a/gcc/d/dmd/errors.h
+++ b/gcc/d/dmd/errors.h
@@ -42,9 +42,6 @@ D_ATTRIBUTE_FORMAT(1, 2) void message(const char *format, ...);
 D_ATTRIBUTE_FORMAT(2, 3) void message(const Loc& loc, const char *format, ...);
 D_ATTRIBUTE_FORMAT(1, 2) void tip(const char *format, ...);
 
-D_ATTRIBUTE_FORMAT(2, 0) void verrorReport(const Loc& loc, const char *format, va_list ap, ErrorKind kind, const char *p1 = nullptr, const char *p2 = nullptr);
-D_ATTRIBUTE_FORMAT(2, 0) void verrorReportSupplemental(const Loc& loc, const char* format, va_list ap, ErrorKind kind);
-
 #if defined(__GNUC__) || defined(__clang__)
 #define D_ATTRIBUTE_NORETURN __attribute__((noreturn))
 #elif _MSC_VER
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index fb3fb9b96457a757b12e9747a69f4e48995fe2da..e1b2ef791a7f113ed6df88788e443387a6c8c504 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -34,6 +34,7 @@ import dmd.location;
 import dmd.mtype;
 import dmd.printast;
 import dmd.rootobject;
+import dmd.safe;
 import dmd.tokens;
 import dmd.typesem : hasPointers, parameterStorageClass;
 import dmd.visitor;
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index a72df72adb4e2ab06e81acbe720e6088a93a75db..3c79b02caa026586eda134010582f14224aed1ba 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -54,29 +54,6 @@ import dmd.visitor;
 
 enum LOGSEMANTIC = false;
 
-/// Return value for `checkModifiable`
-enum Modifiable
-{
-    /// Not modifiable
-    no,
-    /// Modifiable (the type is mutable)
-    yes,
-    /// Modifiable because it is initialization
-    initialization,
-}
-/**
- * Specifies how the checkModify deals with certain situations
- */
-enum ModifyFlags
-{
-    /// Issue error messages on invalid modifications of the variable
-    none,
-    /// No errors are emitted for invalid modifications
-    noError = 0x1,
-    /// The modification occurs for a subfield of the current variable
-    fieldAssign = 0x2,
-}
-
 /****************************************
  * Find the last non-comma expression.
  * Params:
@@ -478,7 +455,7 @@ extern (C++) abstract class Expression : ASTNode
     dinteger_t toInteger()
     {
         //printf("Expression %s\n", EXPtoString(op).ptr);
-        if (!type.isTypeError())
+        if (!type || !type.isTypeError())
             error(loc, "integer constant expression expected instead of `%s`", toChars());
         return 0;
     }
@@ -1880,7 +1857,7 @@ extern (C++) final class InterpExp : Expression
 
     enum char NoPostfix = 0;
 
-    extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope
+    extern (D) this(const ref Loc loc, InterpolatedSet* set, char postfix = NoPostfix) scope @safe
     {
         super(loc, EXP.interpolated);
         this.interpolatedSet = set;
@@ -4575,7 +4552,7 @@ extern (C++) class CatAssignExp : BinAssignExp
 {
     Expression lowering;    // lowered druntime hook `_d_arrayappend{cTX,T}`
 
-    extern (D) this(const ref Loc loc, Expression e1, Expression e2)
+    extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
     {
         super(loc, EXP.concatenateAssign, e1, e2);
     }
@@ -5286,7 +5263,7 @@ extern (C++) final class ObjcClassReferenceExp : Expression
 {
     ClassDeclaration classDeclaration;
 
-    extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration)
+    extern (D) this(const ref Loc loc, ClassDeclaration classDeclaration) @safe
     {
         super(loc, EXP.objcClassReference);
         this.classDeclaration = classDeclaration;
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index ad792817c1b91257ed525bc4e9506d78f1ae5cbe..c353a191a662067ef7652e9285a23747ee2b1bec 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -71,19 +71,6 @@ enum
 #define WANTvalue  0 // default
 #define WANTexpand 1 // expand const/immutable variables if possible
 
-/**
- * Specifies how the checkModify deals with certain situations
- */
-enum class ModifyFlags
-{
-    /// Issue error messages on invalid modifications of the variable
-    none,
-    /// No errors are emitted for invalid modifications
-    noError = 0x1,
-    /// The modification occurs for a subfield of the current variable
-    fieldAssign = 0x2,
-};
-
 class Expression : public ASTNode
 {
 public:
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 57336987764b7c1ad9497ead3e13dc9274baf7c7..b26ce2380f9a2995bdeb92867dcdedc8ecefcf75 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -36,7 +36,6 @@ import dmd.denum;
 import dmd.deps;
 import dmd.dimport;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dstruct;
 import dmd.dsymbolsem;
@@ -60,6 +59,7 @@ import dmd.initsem;
 import dmd.inline;
 import dmd.intrange;
 import dmd.location;
+import dmd.mangle;
 import dmd.mtype;
 import dmd.mustuse;
 import dmd.nspace;
@@ -81,6 +81,7 @@ import dmd.semantic3;
 import dmd.sideeffect;
 import dmd.safe;
 import dmd.target;
+import dmd.templatesem : matchWithInstance;
 import dmd.tokens;
 import dmd.traits;
 import dmd.typesem;
@@ -139,16 +140,26 @@ private bool isNeedThisScope(Scope* sc, Declaration d)
  *      buf = append generated string to buffer
  *      sc = context
  *      exps = array of Expressions
+ *      loc = location of the pragma / mixin where this conversion was requested, for supplemental error
+ *      fmt = format string for supplemental error. May contain 1 `%s` which prints the faulty expression
+ *      expandTuples = whether tuples should be expanded rather than printed as tuple syntax
  * Returns:
  *      true on error
  */
-bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
+bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps,
+    Loc loc, const(char)* fmt, bool expandTuples)
 {
     if (!exps)
         return false;
 
     foreach (ex; *exps)
     {
+        bool error()
+        {
+            if (loc != Loc.initial && fmt)
+                errorSupplemental(loc, fmt, ex.toChars());
+            return true;
+        }
         if (!ex)
             continue;
         auto sc2 = sc.startCTFE();
@@ -161,15 +172,16 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
         // allowed to contain types as well as expressions
         auto e4 = ctfeInterpretForPragmaMsg(e3);
         if (!e4 || e4.op == EXP.error)
-            return true;
+            return error();
 
         // expand tuple
-        if (auto te = e4.isTupleExp())
-        {
-            if (expressionsToString(buf, sc, te.exps))
-                return true;
-            continue;
-        }
+        if (expandTuples)
+            if (auto te = e4.isTupleExp())
+            {
+                if (expressionsToString(buf, sc, te.exps, loc, fmt, true))
+                    return error();
+                continue;
+            }
         // char literals exp `.toStringExp` return `null` but we cant override it
         // because in most contexts we don't want the conversion to succeed.
         IntegerExp ie = e4.isIntegerExp();
@@ -180,9 +192,11 @@ bool expressionsToString(ref OutBuffer buf, Scope* sc, Expressions* exps)
             e4 = new ArrayLiteralExp(ex.loc, tsa, ie);
         }
 
-        if (StringExp se = e4.toStringExp())
+        StringExp se = e4.toStringExp();
+
+        if (se && se.type.nextOf().ty.isSomeChar)
             buf.writestring(se.toUTF8(sc).peekString());
-        else
+        else if (!(se && se.len == 0)) // don't print empty array literal `[]`
             buf.writestring(e4.toString());
     }
     return false;
@@ -313,14 +327,11 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
             return null;
     }
 
-    auto se = e.toStringExp();
-    if (!se)
-    {
-        error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
-            s, exp.toChars(), exp.type.toChars());
-        return null;
-    }
-    return se;
+    if (auto se = e.toStringExp())
+        return se;
+    error(exp.loc, "`string` expected for %s, not `(%s)` of type `%s`",
+          s, exp.toChars(), exp.type.toChars());
+    return null;
 }
 
 /****************************************
@@ -328,17 +339,16 @@ StringExp semanticString(Scope *sc, Expression exp, const char* s)
  */
 StringExp toUTF8(StringExp se, Scope* sc)
 {
-    if (se.sz != 1)
-    {
-        // Convert to UTF-8 string
-        se.committed = false;
-        Expression e = castTo(se, sc, Type.tchar.arrayOf());
-        e = e.optimize(WANTvalue);
-        auto result = e.isStringExp();
-        assert(result.sz == 1);
-        return result;
-    }
-    return se;
+    if (se.sz == 1)
+        return se;
+    // Convert to UTF-8 string
+    se.committed = false;
+    Expression e = castTo(se, sc, Type.tchar.arrayOf());
+    e = e.optimize(WANTvalue);
+    auto result = e.isStringExp();
+    assert(result);
+    assert(result.sz == 1);
+    return result;
 }
 /********************************
  * The type for a unary expression is incompatible.
@@ -346,7 +356,7 @@ StringExp toUTF8(StringExp se, Scope* sc)
  * Returns:
  *  ErrorExp
  */
-extern (D) Expression incompatibleTypes(UnaExp e)
+private Expression incompatibleTypes(UnaExp e)
 {
     if (e.e1.type.toBasetype() == Type.terror)
         return e.e1;
@@ -508,82 +518,76 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
             e2 = e2.castTo(sc, t1);
         }
     }
-    if (op == EXP.mulAssign)
+    if (op == EXP.mulAssign && t2.isFloating())
     {
-        if (t2.isFloating())
+        if (t1.isReal())
         {
-            if (t1.isReal())
-            {
-                if (t2.isImaginary() || t2.isComplex())
-                {
-                    e2 = e2.castTo(sc, t1);
-                }
-            }
-            else if (t1.isImaginary())
+            if (t2.isImaginary() || t2.isComplex())
             {
-                if (t2.isImaginary() || t2.isComplex())
-                {
-                    switch (t1.ty)
-                    {
-                    case Timaginary32:
-                        t2 = Type.tfloat32;
-                        break;
-
-                    case Timaginary64:
-                        t2 = Type.tfloat64;
-                        break;
-
-                    case Timaginary80:
-                        t2 = Type.tfloat80;
-                        break;
-
-                    default:
-                        assert(0);
-                    }
-                    e2 = e2.castTo(sc, t2);
-                }
+                e2 = e2.castTo(sc, t1);
             }
         }
-    }
-    else if (op == EXP.divAssign)
-    {
-        if (t2.isImaginary())
+        else if (t1.isImaginary())
         {
-            if (t1.isReal())
-            {
-                // x/iv = i(-x/v)
-                // Therefore, the result is 0
-                e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
-                e2.type = t1;
-                Expression e = new AssignExp(loc, e1, e2);
-                e.type = t1;
-                return e;
-            }
-            else if (t1.isImaginary())
+            if (t2.isImaginary() || t2.isComplex())
             {
-                Type t3;
                 switch (t1.ty)
                 {
                 case Timaginary32:
-                    t3 = Type.tfloat32;
+                    t2 = Type.tfloat32;
                     break;
 
                 case Timaginary64:
-                    t3 = Type.tfloat64;
+                    t2 = Type.tfloat64;
                     break;
 
                 case Timaginary80:
-                    t3 = Type.tfloat80;
+                    t2 = Type.tfloat80;
                     break;
 
                 default:
                     assert(0);
                 }
-                e2 = e2.castTo(sc, t3);
-                Expression e = new AssignExp(loc, e1, e2);
-                e.type = t1;
-                return e;
+                e2 = e2.castTo(sc, t2);
+            }
+        }
+    }
+    else if (op == EXP.divAssign && t2.isImaginary())
+    {
+        if (t1.isReal())
+        {
+            // x/iv = i(-x/v)
+            // Therefore, the result is 0
+            e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
+            e2.type = t1;
+            Expression e = new AssignExp(loc, e1, e2);
+            e.type = t1;
+            return e;
+        }
+        else if (t1.isImaginary())
+        {
+            Type t3;
+            switch (t1.ty)
+            {
+            case Timaginary32:
+                t3 = Type.tfloat32;
+                break;
+
+            case Timaginary64:
+                t3 = Type.tfloat64;
+                break;
+
+            case Timaginary80:
+                t3 = Type.tfloat80;
+                break;
+
+            default:
+                assert(0);
             }
+            e2 = e2.castTo(sc, t3);
+            Expression e = new AssignExp(loc, e1, e2);
+            e.type = t1;
+            return e;
         }
     }
     else if (op == EXP.modAssign)
@@ -710,7 +714,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, Expression* pe0)
             (*fargs)[0] = ie.lwr;
             (*fargs)[1] = ie.upr;
 
-            uint xerrors = global.startGagging();
+            const xerrors = global.startGagging();
             sc = sc.push();
             FuncDeclaration fslice = resolveFuncCall(ae.loc, sc, slice, tiargs, ae.e1.type, ArgumentList(fargs), FuncResolveFlag.quiet);
             sc = sc.pop();
@@ -1210,7 +1214,7 @@ private Expression resolveUFCS(Scope* sc, CallExp ce)
                     // check them for issues.
                     Expressions* originalArguments = Expression.arraySyntaxCopy(ce.arguments);
 
-                    uint errors = global.startGagging();
+                    const errors = global.startGagging();
                     e = ce.expressionSemantic(sc);
                     if (!global.endGagging(errors))
                         return e;
@@ -2014,6 +2018,71 @@ 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)
+{
+    auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
+
+    AttributeViolation* s;
+    const(char)* attr;
+    if (stc & STC.safe)
+    {
+        s = fd.safetyViolation;
+        attr = "@safe";
+    }
+    else if (stc & STC.pure_)
+    {
+        s = fd.pureViolation;
+        attr = "pure";
+    }
+    else if (stc & STC.nothrow_)
+    {
+        s = fd.nothrowViolation;
+        attr = "nothrow";
+    }
+    else if (stc & STC.nogc)
+    {
+        s = fd.nogcViolation;
+        attr = "@nogc";
+    }
+
+    if (!s)
+        return;
+
+    if (s.fmtStr)
+    {
+        errorFunc(s.loc, deprecation ?
+            "which wouldn't be `%s` because of:" :
+            "which wasn't inferred `%s` because of:", attr);
+        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() : "");
+        }
+        else
+        {
+            errorFunc(s.loc, s.fmtStr,
+                s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
+        }
+    }
+    else if (auto sa = s.arg0.isDsymbol())
+    {
+        if (FuncDeclaration fd2 = sa.isFuncDeclaration())
+        {
+            if (maxDepth > 0)
+            {
+                errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
+                errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
+            }
+        }
+    }
+}
+
 /*******************************************
  * Accessing variable v.
  * Check for purity and safety violations.
@@ -2102,23 +2171,21 @@ private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
             FuncDeclaration ff = s.isFuncDeclaration();
             if (!ff)
                 break;
-            if (ff.isNested() || ff.isThis())
-            {
-                if (ff.type.isImmutable() ||
-                    ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
-                {
-                    OutBuffer ffbuf;
-                    OutBuffer vbuf;
-                    MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
-                    MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
-                    error(loc, "%s%s `%s` cannot access %sdata `%s`",
-                        ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
-                    err = true;
-                    break;
-                }
-                continue;
+            if (!ff.isNested() && !ff.isThis())
+                break;
+            if (ff.type.isImmutable() ||
+                ff.type.isShared() && !MODimplicitConv(ff.type.mod, v.type.mod))
+            {
+                OutBuffer ffbuf;
+                OutBuffer vbuf;
+                MODMatchToBuffer(&ffbuf, ff.type.mod, v.type.mod);
+                MODMatchToBuffer(&vbuf, v.type.mod, ff.type.mod);
+                error(loc, "%s%s `%s` cannot access %sdata `%s`",
+                    ffbuf.peekChars(), ff.kind(), ff.toPrettyChars(), vbuf.peekChars(), v.toChars());
+                err = true;
+                break;
             }
-            break;
+            continue;
         }
     }
 
@@ -2246,30 +2313,28 @@ private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
     if (f.isNogc())
         return false;
 
-    if (isRootTraitsCompilesScope(sc) ? sc.func.isNogcBypassingInference() : sc.func.setGCCall(f))
-    {
-        if (loc.linnum == 0) // e.g. implicitly generated dtor
-            loc = sc.func.loc;
-
-        // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
-        // so don't print anything to avoid double error messages.
-        if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
-            || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
-            || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
-        {
-            error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
-                sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
+    if (isRootTraitsCompilesScope(sc) ? !sc.func.isNogcBypassingInference() : !sc.func.setGCCall(f))
+        return false;
 
-            if (!f.isDtorDeclaration)
-                f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
-        }
+    if (loc.linnum == 0) // e.g. implicitly generated dtor
+        loc = sc.func.loc;
 
-        f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isNogc, "non-@nogc");
+    // Lowered non-@nogc'd hooks will print their own error message inside of nogc.d (NOGCVisitor.visit(CallExp e)),
+    // so don't print anything to avoid double error messages.
+    if (!(f.ident == Id._d_HookTraceImpl || f.ident == Id._d_arraysetlengthT
+        || f.ident == Id._d_arrayappendT || f.ident == Id._d_arrayappendcTX
+        || f.ident == Id._d_arraycatnTX || f.ident == Id._d_newclassT))
+    {
+        error(loc, "`@nogc` %s `%s` cannot call non-@nogc %s `%s`",
+            sc.func.kind(), sc.func.toPrettyChars(), f.kind(), f.toPrettyChars());
 
-        return true;
+        if (!f.isDtorDeclaration)
+            f.errorSupplementalInferredAttr(/*max depth*/ 10, /*deprecation*/ false, STC.nogc);
     }
 
-    return false;
+    f.checkOverriddenDtor(sc, loc, dd => dd.type.toTypeFunction().isNogc, "non-@nogc");
+
+    return true;
 }
 
 /********************************************
@@ -2361,37 +2426,35 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                 return e.expressionSemantic(sc);
             }
         }
+        for (size_t i = 0; i < os.a.length; i++)
         {
-            for (size_t i = 0; i < os.a.length; i++)
+            FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
+            if (!f)
+                continue;
+            if (f.errors)
+                return ErrorExp.get();
+            fd = f;
+            assert(fd.type.ty == Tfunction);
+            auto tf = fd.type.isTypeFunction();
+            if (!tf.isRef && e2)
             {
-                if (FuncDeclaration f = resolveFuncCall(loc, sc, os.a[i], tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet))
-                {
-                    if (f.errors)
-                        return ErrorExp.get();
-                    fd = f;
-                    assert(fd.type.ty == Tfunction);
-                    auto tf = fd.type.isTypeFunction();
-                    if (!tf.isRef && e2)
-                    {
-                        error(loc, "%s is not an lvalue", e1.toChars());
-                        return ErrorExp.get();
-                    }
-                }
+                error(loc, "%s is not an lvalue", e1.toChars());
+                return ErrorExp.get();
             }
-            if (fd)
+        }
+        if (fd)
+        {
+            Expression e = new CallExp(loc, e1);
+            if (e2)
             {
-                Expression e = new CallExp(loc, e1);
-                if (e2)
+                e = new AssignExp(loc, e, e2);
+                if (saveAtts)
                 {
-                    e = new AssignExp(loc, e, e2);
-                    if (saveAtts)
-                    {
-                        (cast(BinExp)e).att1 = saveAtts.att1;
-                        (cast(BinExp)e).att2 = saveAtts.att2;
-                    }
+                    (cast(BinExp)e).att1 = saveAtts.att1;
+                    (cast(BinExp)e).att2 = saveAtts.att2;
                 }
-                return e.expressionSemantic(sc);
             }
+            return e.expressionSemantic(sc);
         }
         if (e2)
             goto Leprop;
@@ -2479,33 +2542,31 @@ private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
                 return e.expressionSemantic(sc);
             }
         }
+        FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
+        if (fd && fd.type)
         {
-            FuncDeclaration fd = resolveFuncCall(loc, sc, s, tiargs, tthis, ArgumentList(), FuncResolveFlag.quiet);
-            if (fd && fd.type)
+            if (fd.errors)
+                return ErrorExp.get();
+            TypeFunction tf = fd.type.isTypeFunction();
+            if (!e2 || tf.isRef)
             {
-                if (fd.errors)
-                    return ErrorExp.get();
-                TypeFunction tf = fd.type.isTypeFunction();
-                if (!e2 || tf.isRef)
+                Expression e = new CallExp(loc, e1);
+                if (e2)
                 {
-                    Expression e = new CallExp(loc, e1);
-                    if (e2)
+                    e = new AssignExp(loc, e, e2);
+                    if (saveAtts)
                     {
-                        e = new AssignExp(loc, e, e2);
-                        if (saveAtts)
-                        {
-                            (cast(BinExp)e).att1 = saveAtts.att1;
-                            (cast(BinExp)e).att2 = saveAtts.att2;
-                        }
+                        (cast(BinExp)e).att1 = saveAtts.att1;
+                        (cast(BinExp)e).att2 = saveAtts.att2;
                     }
-                    return e.expressionSemantic(sc);
                 }
+                return e.expressionSemantic(sc);
             }
         }
-        if (FuncDeclaration fd = s.isFuncDeclaration())
+        if (FuncDeclaration fd2 = s.isFuncDeclaration())
         {
             // Keep better diagnostic message for invalid property usage of functions
-            assert(fd.type.ty == Tfunction);
+            assert(fd2.type.ty == Tfunction);
             Expression e = new CallExp(loc, e1, e2);
             return e.expressionSemantic(sc);
         }
@@ -2564,20 +2625,19 @@ private bool checkRightThis(Expression e, Scope* sc)
 {
     if (e.op == EXP.error)
         return true;
-    if (e.op == EXP.variable && e.type.ty != Terror)
-    {
-        VarExp ve = cast(VarExp)e;
-        if (isNeedThisScope(sc, ve.var))
-        {
-            //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
-            //        sc.intypeof, sc.getStructClassScope(), func, fdthis);
-            auto t = ve.var.isThis();
-            assert(t);
-            error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
-            return true;
-        }
-    }
-    return false;
+    if (e.op != EXP.variable || e.type.ty == Terror)
+        return false;
+
+    VarExp ve = cast(VarExp)e;
+    if (!isNeedThisScope(sc, ve.var))
+        return false;
+
+    //printf("checkRightThis sc.intypeof = %d, ad = %p, func = %p, fdthis = %p\n",
+    //        sc.intypeof, sc.getStructClassScope(), func, fdthis);
+    auto t = ve.var.isThis();
+    assert(t);
+    error(e.loc, "accessing non-static variable `%s` requires an instance of `%s`", ve.var.toChars(), t.toChars());
+    return true;
 }
 
 Expression resolveProperties(Scope* sc, Expression e)
@@ -2998,29 +3058,22 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
             else
                 (*arguments)[i] = arg;
         }
-        else
+        else if (arg.isDefaultInitExp())
         {
-            if (arg.isDefaultInitExp())
-            {
-                arg = arg.resolveLoc(loc, sc);
-                (*arguments)[i] = arg;
-            }
+            arg = arg.resolveLoc(loc, sc);
+            (*arguments)[i] = arg;
         }
 
-
         if (tf.parameterList.varargs == VarArg.typesafe && i + 1 == nparams) // https://dlang.org/spec/function.html#variadic
         {
             //printf("\t\tvarargs == 2, p.type = '%s'\n", p.type.toChars());
+            if (MATCH m = arg.implicitConvTo(p.type))
             {
-                MATCH m;
-                if ((m = arg.implicitConvTo(p.type)) > MATCH.nomatch)
-                {
-                    if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
-                        goto L2;
-                    else if (nargs != nparams)
-                        return errorArgs();
-                    goto L1;
-                }
+                if (p.type.nextOf() && arg.implicitConvTo(p.type.nextOf()) >= m)
+                    goto L2;
+                else if (nargs != nparams)
+                    return errorArgs();
+                goto L1;
             }
         L2:
             Type tb = p.type.toBasetype();
@@ -3783,37 +3836,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
     {
         if (!e.type)
             e.type = Type.tfloat64;
-        else if (e.type.isImaginary && sc.inCfile)
+        else if (!e.type.isImaginary || !sc.inCfile)
         {
-            /* Convert to core.stdc.config.complex
-             */
-            Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
-            if (t.ty == Terror)
-                return setError();
+            e.type = e.type.typeSemantic(e.loc, sc);
+            result = e;
+            return;
+        }
 
-            Type tf;
-            switch (e.type.ty)
-            {
-                case Timaginary32: tf = Type.tfloat32; break;
-                case Timaginary64: tf = Type.tfloat64; break;
-                case Timaginary80: tf = Type.tfloat80; break;
-                default:
-                    assert(0);
-            }
+        /* Convert to core.stdc.config.complex
+         */
+        Type t = getComplexLibraryType(e.loc, sc, e.type.ty);
+        if (t.ty == Terror)
+            return setError();
 
-            /* Construct ts{re : 0.0, im : e}
-             */
-            TypeStruct ts = t.isTypeStruct;
-            Expressions* elements = new Expressions(2);
-            (*elements)[0] = new RealExp(e.loc,    CTFloat.zero, tf);
-            (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
-            Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
-            result = sle.expressionSemantic(sc);
-            return;
+        Type tf;
+        switch (e.type.ty)
+        {
+            case Timaginary32: tf = Type.tfloat32; break;
+            case Timaginary64: tf = Type.tfloat64; break;
+            case Timaginary80: tf = Type.tfloat80; break;
+            default:
+                assert(0);
         }
-        else
-            e.type = e.type.typeSemantic(e.loc, sc);
-        result = e;
+
+        /* Construct ts{re : 0.0, im : e}
+         */
+        TypeStruct ts = t.isTypeStruct;
+        Expressions* elements = new Expressions(2);
+        (*elements)[0] = new RealExp(e.loc,    CTFloat.zero, tf);
+        (*elements)[1] = new RealExp(e.loc, e.toImaginary(), tf);
+        Expression sle = new StructLiteralExp(e.loc, ts.sym, elements);
+        result = sle.expressionSemantic(sc);
     }
 
     override void visit(ComplexExp e)
@@ -4129,6 +4182,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         ClassDeclaration cd;
         Dsymbol s;
 
+        void err()
+        {
+            error(e.loc, "`super` is only allowed in non-static class member functions");
+            result = ErrorExp.get();
+        }
         /* Special case for typeof(this) and typeof(super) since both
          * should work even if they are not inside a non-static member function
          */
@@ -4143,22 +4201,22 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
                 }
                 cd = s.isClassDeclaration();
-                if (cd)
+                if (!cd)
+                    continue;
+
+                cd = cd.baseClass;
+                if (!cd)
                 {
-                    cd = cd.baseClass;
-                    if (!cd)
-                    {
-                        error(e.loc, "class `%s` has no `super`", s.toChars());
-                        return setError();
-                    }
-                    e.type = cd.type;
-                    result = e;
-                    return;
+                    error(e.loc, "class `%s` has no `super`", s.toChars());
+                    return setError();
                 }
+                e.type = cd.type;
+                result = e;
+                return;
             }
         }
         if (!fd)
-            goto Lerr;
+            return err();
 
         e.var = fd.vthis;
         assert(e.var && e.var.parent);
@@ -4170,7 +4228,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         cd = s.isClassDeclaration();
         //printf("parent is %s %s\n", fd.toParent().kind(), fd.toParent().toChars());
         if (!cd)
-            goto Lerr;
+            return err();
         if (!cd.baseClass)
         {
             error(e.loc, "no base class for `%s`", cd.toChars());
@@ -4186,11 +4244,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
 
         result = e;
-        return;
-
-    Lerr:
-        error(e.loc, "`super` is only allowed in non-static class member functions");
-        result = ErrorExp.get();
     }
 
     override void visit(NullExp e)
@@ -5522,7 +5575,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else if (auto f = e.var.isFuncDeclaration())
         {
-            if (f.checkNestedReference(sc, e.loc))
+            if (f.checkNestedFuncReference(sc, e.loc))
                 return setError();
         }
 
@@ -5576,10 +5629,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         else if (fd)
         {
-            // TODO: If fd isn't yet resolved its overload, the checkNestedReference
+            // TODO: If fd isn't yet resolved its overload, the checkNestedFuncReference
             // call would cause incorrect validation.
             // Maybe here should be moved in CallExp, or AddrExp for functions.
-            if (fd.checkNestedReference(sc, e.loc))
+            if (fd.checkNestedFuncReference(sc, e.loc))
                 return setError();
         }
         else if (auto od = e.var.isOverDeclaration())
@@ -5652,7 +5705,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         Expression e = exp;
-        uint olderrors;
 
         sc = sc.push(); // just create new scope
         sc.ctfe = false; // temporary stop CTFE
@@ -5681,6 +5733,12 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
 
+        void done()
+        {
+            sc = sc.pop();
+            result = e;
+        }
+
         //printf("td = %p, treq = %p\n", td, fd.treq);
         if (exp.td)
         {
@@ -5696,10 +5754,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 else
                     e = ErrorExp.get();
             }
-            goto Ldone;
+            return done();
         }
 
-        olderrors = global.errors;
+        const olderrors = global.errors;
         exp.fd.dsymbolSemantic(sc);
         if (olderrors == global.errors)
         {
@@ -5712,7 +5770,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (exp.fd.type && exp.fd.type.ty == Tfunction && !exp.fd.type.nextOf())
                 (cast(TypeFunction)exp.fd.type).next = Type.terror;
             e = ErrorExp.get();
-            goto Ldone;
+            return done();
         }
 
         // Type is a "delegate to" or "pointer to" the function literal
@@ -5725,7 +5783,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (exp.fd.type.isTypeError())
             {
                 e = ErrorExp.get();
-                goto Ldone;
+                return done();
             }
             exp.type = new TypeDelegate(exp.fd.type.isTypeFunction());
             exp.type = exp.type.typeSemantic(exp.loc, sc);
@@ -5754,10 +5812,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
         exp.fd.tookAddressOf++;
-
-    Ldone:
-        sc = sc.pop();
-        result = e;
+        done();
     }
 
     /**
@@ -6279,47 +6334,46 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             {
                 if (tiargs && s.isFuncDeclaration())
                     continue;
-                if (auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet))
+                auto f2 = resolveFuncCall(loc, sc, s, tiargs, tthis, argumentList, FuncResolveFlag.quiet);
+                if (!f2)
+                    continue;
+                if (f2.errors)
+                    return null;
+                if (!f)
                 {
-                    if (f2.errors)
-                        return null;
-                    if (f)
-                    {
-                        /* Match in more than one overload set,
-                         * even if one is a 'better' match than the other.
-                         */
-                        if (f.isCsymbol() && f2.isCsymbol())
-                        {
-                            /* C has global name space, so just pick one, such as f.
-                             * If f and f2 are not compatible, that's how C rolls.
-                             */
-                        }
-                        else
-                            ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
-                    }
-                    else
-                        f = f2;
+                    f = f2;
+                    continue;
                 }
-            }
-            if (!f)
-            {
-                .error(loc, "no overload matches for `%s`", exp.toChars());
-                errorSupplemental(loc, "Candidates are:");
-                foreach (s; os.a)
+                /* Match in more than one overload set,
+                 * even if one is a 'better' match than the other.
+                 */
+                if (f.isCsymbol() && f2.isCsymbol())
                 {
-                    overloadApply(s, (ds){
-                        if (auto fd = ds.isFuncDeclaration())
-                            .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
-                                fd.type.toTypeFunction().parameterList.parametersTypeToChars());
-                        else
-                            .errorSupplemental(ds.loc, "%s", ds.toChars());
-                        return 0;
-                    });
+                    /* C has global name space, so just pick one, such as f.
+                     * If f and f2 are not compatible, that's how C rolls.
+                     */
                 }
+                else
+                    ScopeDsymbol.multiplyDefined(loc, f, f2); // issue error
             }
-            else if (f.errors)
-                f = null;
-            return f;
+            if (f && f.errors)
+                return null;
+            if (f)
+                return f;
+            .error(loc, "no overload matches for `%s`", exp.toChars());
+            errorSupplemental(loc, "Candidates are:");
+            foreach (s; os.a)
+            {
+                overloadApply(s, (ds){
+                    if (auto fd = ds.isFuncDeclaration())
+                        .errorSupplemental(ds.loc, "%s%s", fd.toChars(),
+                            fd.type.toTypeFunction().parameterList.parametersTypeToChars());
+                    else
+                        .errorSupplemental(ds.loc, "%s", ds.toChars());
+                    return 0;
+                });
+            }
+            return f;
         }
 
         bool isSuper = false;
@@ -6678,7 +6732,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 exp.f.checkPurity(exp.loc, sc);
                 exp.f.checkSafety(exp.loc, sc);
                 exp.f.checkNogc(exp.loc, sc);
-                if (exp.f.checkNestedReference(sc, exp.loc))
+                if (exp.f.checkNestedFuncReference(sc, exp.loc))
                     return setError();
             }
             else if (sc.func && sc.intypeof != 1 && !(sc.ctfe || sc.debug_))
@@ -6761,7 +6815,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (exp.f.needThis())
             {
                 // Change the ancestor lambdas to delegate before hasThis(sc) call.
-                if (exp.f.checkNestedReference(sc, exp.loc))
+                if (exp.f.checkNestedFuncReference(sc, exp.loc))
                     return setError();
 
                 auto memberFunc = hasThis(sc);
@@ -6796,7 +6850,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             checkFunctionAttributes(exp, sc, exp.f);
             checkAccess(exp.loc, sc, null, exp.f);
-            if (exp.f.checkNestedReference(sc, exp.loc))
+            if (exp.f.checkNestedFuncReference(sc, exp.loc))
                 return setError();
 
             ethis = null;
@@ -6915,7 +6969,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             printf("DeclarationExp::semantic() %s\n", e.toChars());
         }
 
-        uint olderrors = global.errors;
+        const olderrors = global.errors;
 
         /* This is here to support extern(linkage) declaration,
          * where the extern(linkage) winds up being an AttribDeclaration
@@ -7144,17 +7198,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // Handle this in the glue layer
         Expression e = new TypeidExp(exp.loc, ta);
 
-        bool genObjCode = true;
-
-        // https://issues.dlang.org/show_bug.cgi?id=23650
-        // We generate object code for typeinfo, required
-        // by typeid, only if in non-speculative context
-        if (sc.traitsCompiles)
-        {
-            genObjCode = false;
-        }
-
-        e.type = getTypeInfoType(exp.loc, ta, sc, genObjCode);
+        e.type = getTypeInfoType(exp.loc, ta, sc);
         semanticTypeInfo(sc, ta);
 
         if (ea)
@@ -7440,39 +7484,37 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             //printf("targ  = %s, %s\n", e.targ.toChars(), e.targ.deco);
             //printf("tspec = %s, %s\n", e.tspec.toChars(), e.tspec.deco);
 
-            if (e.tok == TOK.colon)
+            if (e.tok != TOK.colon) /* == */
             {
-                // current scope is itself deprecated, or deprecations are not errors
-                const bool deprecationAllowed = sc.isDeprecated
-                    || global.params.useDeprecated != DiagnosticReporting.error;
-                const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
+                if (e.targ.equals(e.tspec))
+                    return yes();
+                else
+                    return no();
+            }
 
-                if (preventAliasThis && e.targ.ty == Tstruct)
-                {
-                    if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
-                        return yes();
-                    else
-                        return no();
-                }
-                else if (preventAliasThis && e.targ.ty == Tclass)
-                {
-                    if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
-                        return yes();
-                    else
-                        return no();
-                }
-                else if (e.targ.implicitConvTo(e.tspec))
+            // current scope is itself deprecated, or deprecations are not errors
+            const bool deprecationAllowed = sc.isDeprecated
+                || global.params.useDeprecated != DiagnosticReporting.error;
+            const bool preventAliasThis = e.targ.hasDeprecatedAliasThis && !deprecationAllowed;
+
+            if (preventAliasThis && e.targ.ty == Tstruct)
+            {
+                if ((cast(TypeStruct) e.targ).implicitConvToWithoutAliasThis(e.tspec))
                     return yes();
                 else
                     return no();
             }
-            else /* == */
+            else if (preventAliasThis && e.targ.ty == Tclass)
             {
-                if (e.targ.equals(e.tspec))
+                if ((cast(TypeClass) e.targ).implicitConvToWithoutAliasThis(e.tspec))
                     return yes();
                 else
                     return no();
             }
+            else if (e.targ.implicitConvTo(e.tspec))
+                return yes();
+            else
+                return no();
         }
         else if (e.tspec)
         {
@@ -7656,16 +7698,15 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
     private Expression compileIt(MixinExp exp, Scope *sc)
     {
         OutBuffer buf;
-        if (expressionsToString(buf, sc, exp.exps))
+        if (expressionsToString(buf, sc, exp.exps, exp.loc, null, true))
             return null;
 
-        uint errors = global.errors;
+        const errors = global.errors;
         const len = buf.length;
         const str = buf.extractChars()[0 .. len];
         const bool doUnittests = global.params.parsingUnittestsRequired();
         auto loc = adjustLocForMixin(str, exp.loc, global.params.mixinOut);
         scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
-        p.transitionIn = global.params.v.vin;
         p.nextToken();
         //printf("p.loc.linnum = %d\n", p.loc.linnum);
 
@@ -8094,8 +8135,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             /* This is an `assert(0)` which means halt program execution
              */
             FuncDeclaration fd = sc.parent.isFuncDeclaration();
-            if (fd)
-                fd.hasReturnExp |= 4;
             sc.ctorflow.orCSX(CSX.halt);
 
             if (global.params.useAssert == CHECKENABLE.off)
@@ -8192,7 +8231,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (e && isDotOpDispatch(e))
         {
             auto ode = e;
-            uint errors = global.startGagging();
+            const errors = global.startGagging();
             e = resolvePropertiesX(sc, e);
             // Any error or if 'e' is not resolved, go to UFCS
             if (global.endGagging(errors) || e is ode)
@@ -10555,7 +10594,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                      */
                     auto ode = e;
                     exp.e2 = exp.e2.expressionSemantic(sc);
-                    uint errors = global.startGagging();
+                    const errors = global.startGagging();
                     e = resolvePropertiesX(sc, e, exp.e2);
                     // Any error or if 'e' is not resolved, go to UFCS
                     if (global.endGagging(errors) || e is ode)
@@ -12206,7 +12245,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         if (tb1.ty == Tpointer && tb2.ty == Tpointer ||
-	    tb1.ty == Tnull && tb2.ty == Tnull)
+            tb1.ty == Tnull && tb2.ty == Tnull)
         {
             result = exp.incompatibleTypes();
             return;
@@ -14237,7 +14276,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 Expression trySemantic(Expression exp, Scope* sc)
 {
     //printf("+trySemantic(%s)\n", exp.toChars());
-    uint errors = global.startGagging();
+    const errors = global.startGagging();
     Expression e = expressionSemantic(exp, sc);
     if (global.endGagging(errors))
     {
@@ -14434,14 +14473,6 @@ private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
     return exp;
 }
 
-private bool checkDisabled(Dsymbol s, ref Loc loc, Scope* sc)
-{
-    if (auto d = s.isDeclaration())
-        return d.checkDisabled(loc, sc);
-
-    return false;
-}
-
 /******************************
  * Resolve properties, i.e. `e1.ident`, without seeing UFCS.
  * Params:
@@ -14536,7 +14567,8 @@ Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
             s = s.toAlias();
 
             s.checkDeprecated(exp.loc, sc);
-            s.checkDisabled(exp.loc, sc);
+            if (auto d = s.isDeclaration())
+                d.checkDisabled(exp.loc, sc);
 
             if (auto em = s.isEnumMember())
             {
@@ -14833,6 +14865,13 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
     auto die = new DotIdExp(exp.loc, e1, exp.ti.name);
 
     Expression e = die.dotIdSemanticPropX(sc);
+
+    Expression notTemplate()
+    {
+        error(exp.loc, "`%s` isn't a template", e.toChars());
+        return errorExp();
+    }
+
     if (e == die)
     {
         exp.e1 = die.e1; // take back
@@ -14877,7 +14916,7 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
             exp.e1 = dve.e1; // pull semantic() result
 
             if (!exp.findTempDecl(sc))
-                goto Lerr;
+                return notTemplate();
             if (exp.ti.needsTypeInference(sc))
                 return exp;
             exp.ti.dsymbolSemantic(sc);
@@ -14973,9 +15012,7 @@ Expression dotTemplateSemanticProp(DotTemplateInstanceExp exp, Scope* sc, bool g
                .expressionSemantic(sc);
     }
 
-Lerr:
-    error(exp.loc, "`%s` isn't a template", e.toChars());
-    return errorExp();
+    return notTemplate();
 }
 
 MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
@@ -16280,7 +16317,7 @@ private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
  * Returns:
  *      `true` if ok, `false` for error
  */
-bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
+private bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
 {
     //printf("checkAddressVar(exp: %s, v: %s)\n", exp.toChars(), v.toChars());
     if (v is null)
@@ -16464,7 +16501,7 @@ Expression getThisSkipNestedFuncs(const ref Loc loc, Scope* sc, Dsymbol s, Aggre
  *      newly created variable such that a closure is made for the variable when
  *      the address of `fd` is taken.
  */
-VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
+private VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration fd)
 {
     Type tthis2 = Type.tvoidptr.sarrayOf(2);
     VarDeclaration vthis2 = new VarDeclaration(loc, tthis2, Identifier.generateId("__this"), null);
@@ -16857,3 +16894,760 @@ bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
     }
     return impl(e);
 }
+
+/************************************
+ * Check to see the aggregate type is nested and its context pointer is
+ * accessible from the current scope.
+ * Returns true if error occurs.
+ */
+bool checkFrameAccess(Loc loc, Scope* sc, AggregateDeclaration ad, size_t iStart = 0)
+{
+    Dsymbol sparent = ad.toParentLocal();
+    Dsymbol sparent2 = ad.toParent2();
+    Dsymbol s = sc.func;
+    if (ad.isNested() && s)
+    {
+        //printf("ad = %p %s [%s], parent:%p\n", ad, ad.toChars(), ad.loc.toChars(), ad.parent);
+        //printf("sparent = %p %s [%s], parent: %s\n", sparent, sparent.toChars(), sparent.loc.toChars(), sparent.parent,toChars());
+        //printf("sparent2 = %p %s [%s], parent: %s\n", sparent2, sparent2.toChars(), sparent2.loc.toChars(), sparent2.parent,toChars());
+        if (!ensureStaticLinkTo(s, sparent) || sparent != sparent2 && !ensureStaticLinkTo(s, sparent2))
+        {
+            error(loc, "cannot access frame pointer of `%s`", ad.toPrettyChars());
+            return true;
+        }
+    }
+
+    bool result = false;
+    for (size_t i = iStart; i < ad.fields.length; i++)
+    {
+        VarDeclaration vd = ad.fields[i];
+        Type tb = vd.type.baseElemOf();
+        if (tb.ty == Tstruct)
+        {
+            result |= checkFrameAccess(loc, sc, (cast(TypeStruct)tb).sym);
+        }
+    }
+    return result;
+}
+
+/// Return value for `checkModifiable`
+enum Modifiable
+{
+    /// Not modifiable
+    no,
+    /// Modifiable (the type is mutable)
+    yes,
+    /// Modifiable because it is initialization
+    initialization,
+}
+
+/**
+ * Specifies how the checkModify deals with certain situations
+ */
+enum ModifyFlags
+{
+    /// Issue error messages on invalid modifications of the variable
+    none,
+    /// No errors are emitted for invalid modifications
+    noError = 0x1,
+    /// The modification occurs for a subfield of the current variable
+    fieldAssign = 0x2,
+}
+
+/*************************************
+ * Check to see if declaration can be modified in this context (sc).
+ * Issue error if not.
+ * Params:
+ *  loc  = location for error messages
+ *  e1   = `null` or `this` expression when this declaration is a field
+ *  sc   = context
+ *  flag = if the first bit is set it means do not issue error message for
+ *         invalid modification; if the second bit is set, it means that
+           this declaration is a field and a subfield of it is modified.
+ * Returns:
+ *  Modifiable.yes or Modifiable.initialization
+ */
+private Modifiable checkModify(Declaration d, Loc loc, Scope* sc, Expression e1, ModifyFlags flag)
+{
+    VarDeclaration v = d.isVarDeclaration();
+    if (v && v.canassign)
+        return Modifiable.initialization;
+
+    if (d.isParameter() || d.isResult())
+    {
+        for (Scope* scx = sc; scx; scx = scx.enclosing)
+        {
+            if (scx.func == d.parent && scx.contract != Contract.none)
+            {
+                const(char)* s = d.isParameter() && d.parent.ident != Id.ensure ? "parameter" : "result";
+                if (!(flag & ModifyFlags.noError))
+                    error(loc, "%s `%s` cannot modify %s `%s` in contract", d.kind, d.toPrettyChars, s, d.toChars());
+                return Modifiable.initialization; // do not report type related errors
+            }
+        }
+    }
+
+    if (e1 && e1.op == EXP.this_ && d.isField())
+    {
+        VarDeclaration vthis = e1.isThisExp().var;
+        for (Scope* scx = sc; scx; scx = scx.enclosing)
+        {
+            if (scx.func == vthis.parent && scx.contract != Contract.none)
+            {
+                if (!(flag & ModifyFlags.noError))
+                    error(loc, "%s `%s` cannot modify parameter `this` in contract", d.kind, d.toPrettyChars);
+                return Modifiable.initialization; // do not report type related errors
+            }
+        }
+    }
+
+    if (v && (v.isCtorinit() || d.isField()))
+    {
+        // It's only modifiable if inside the right constructor
+        if ((d.storage_class & (STC.foreach_ | STC.ref_)) == (STC.foreach_ | STC.ref_))
+            return Modifiable.initialization;
+        if (flag & ModifyFlags.fieldAssign)
+            return Modifiable.yes;
+        return modifyFieldVar(loc, sc, v, e1) ? Modifiable.initialization : Modifiable.yes;
+    }
+    return Modifiable.yes;
+}
+
+/***********************************************
+ * Mark variable v as modified if it is inside a constructor that var
+ * is a field in.
+ * Also used to allow immutable globals to be initialized inside a static constructor.
+ * Returns:
+ *    true if it's an initialization of v
+ */
+private bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
+{
+    //printf("modifyFieldVar(var = %s)\n", var.toChars());
+    Dsymbol s = sc.func;
+    while (1)
+    {
+        FuncDeclaration fd = null;
+        if (s)
+            fd = s.isFuncDeclaration();
+        if (fd &&
+            ((fd.isCtorDeclaration() && var.isField()) ||
+             ((fd.isStaticCtorDeclaration() || fd.isCrtCtor) && !var.isField())) &&
+            fd.toParentDecl() == var.toParent2() &&
+            (!e1 || e1.op == EXP.this_))
+        {
+            bool result = true;
+
+            var.ctorinit = true;
+            //printf("setting ctorinit\n");
+
+            if (var.isField() && sc.ctorflow.fieldinit.length && !sc.intypeof)
+            {
+                assert(e1);
+                auto mustInit = ((var.storage_class & STC.nodefaultctor) != 0 ||
+                                 var.type.needsNested());
+
+                const dim = sc.ctorflow.fieldinit.length;
+                auto ad = fd.isMemberDecl();
+                assert(ad);
+                size_t i;
+                for (i = 0; i < dim; i++) // same as findFieldIndexByName in ctfeexp.c ?
+                {
+                    if (ad.fields[i] == var)
+                        break;
+                }
+                assert(i < dim);
+                auto fieldInit = &sc.ctorflow.fieldinit[i];
+                const fi = fieldInit.csx;
+
+                if (fi & CSX.this_ctor)
+                {
+                    if (var.type.isMutable() && e1.type.isMutable())
+                        result = false;
+                    else
+                    {
+                        const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+                        .error(loc, "%s field `%s` initialized multiple times", modStr, var.toChars());
+                        .errorSupplemental(fieldInit.loc, "Previous initialization is here.");
+                    }
+                }
+                else if (sc.inLoop || (fi & CSX.label))
+                {
+                    if (!mustInit && var.type.isMutable() && e1.type.isMutable())
+                        result = false;
+                    else
+                    {
+                        const(char)* modStr = !var.type.isMutable() ? MODtoChars(var.type.mod) : MODtoChars(e1.type.mod);
+                        .error(loc, "%s field `%s` initialization is not allowed in loops or after labels", modStr, var.toChars());
+                    }
+                }
+
+                fieldInit.csx |= CSX.this_ctor;
+                fieldInit.loc = e1.loc;
+                if (var.overlapped) // https://issues.dlang.org/show_bug.cgi?id=15258
+                {
+                    foreach (j, v; ad.fields)
+                    {
+                        if (v is var || !var.isOverlappedWith(v))
+                            continue;
+                        v.ctorinit = true;
+                        sc.ctorflow.fieldinit[j].csx = CSX.this_ctor;
+                    }
+                }
+            }
+            else if (fd != sc.func)
+            {
+                if (var.type.isMutable())
+                    result = false;
+                else if (sc.func.fes)
+                {
+                    const(char)* p = var.isField() ? "field" : var.kind();
+                    .error(loc, "%s %s `%s` initialization is not allowed in foreach loop",
+                        MODtoChars(var.type.mod), p, var.toChars());
+                }
+                else
+                {
+                    const(char)* p = var.isField() ? "field" : var.kind();
+                    .error(loc, "%s %s `%s` initialization is not allowed in nested function `%s`",
+                        MODtoChars(var.type.mod), p, var.toChars(), sc.func.toChars());
+                }
+            }
+            else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+                     var.type.isImmutable())
+            {
+                .error(loc, "%s %s `%s` initialization is not allowed in `static this`",
+                    MODtoChars(var.type.mod), var.kind(), var.toChars());
+                errorSupplemental(loc, "Use `shared static this` instead.");
+            }
+            else if (fd.isStaticCtorDeclaration() && !fd.isSharedStaticCtorDeclaration() &&
+                    var.type.isConst())
+            {
+                // @@@DEPRECATED_2.116@@@
+                // Turn this into an error, merging with the branch above
+                .deprecation(loc, "%s %s `%s` initialization is not allowed in `static this`",
+                    MODtoChars(var.type.mod), var.kind(), var.toChars());
+                deprecationSupplemental(loc, "Use `shared static this` instead.");
+            }
+            return result;
+        }
+        else
+        {
+            if (s)
+            {
+                s = s.toParentP(var.toParent2());
+                continue;
+            }
+        }
+        break;
+    }
+    return false;
+}
+
+/***************************************
+ * Request additional semantic analysis for TypeInfo generation.
+ * Params:
+ *      sc = context
+ *      t = type that TypeInfo is being generated for
+ */
+void semanticTypeInfo(Scope* sc, Type t)
+{
+    if (sc)
+    {
+        if (sc.intypeof)
+            return;
+        if (!sc.needsCodegen())
+            return;
+    }
+
+    if (!t)
+        return;
+
+    void visitVector(TypeVector t)
+    {
+        semanticTypeInfo(sc, t.basetype);
+    }
+
+    void visitAArray(TypeAArray t)
+    {
+        semanticTypeInfo(sc, t.index);
+        semanticTypeInfo(sc, t.next);
+    }
+
+    void visitStruct(TypeStruct t)
+    {
+        //printf("semanticTypeInfo.visit(TypeStruct = %s)\n", t.toChars());
+        StructDeclaration sd = t.sym;
+
+        /* Step 1: create TypeInfoDeclaration
+         */
+        if (!sc) // inline may request TypeInfo.
+        {
+            Scope scx;
+            scx.eSink = global.errorSink;
+            scx._module = sd.getModule();
+            getTypeInfoType(sd.loc, t, &scx);
+            sd.requestTypeInfo = true;
+        }
+        else if (!sc.minst)
+        {
+            // don't yet have to generate TypeInfo instance if
+            // the typeid(T) expression exists in speculative scope.
+        }
+        else
+        {
+            getTypeInfoType(sd.loc, t, sc);
+            sd.requestTypeInfo = true;
+
+            // https://issues.dlang.org/show_bug.cgi?id=15149
+            // if the typeid operand type comes from a
+            // result of auto function, it may be yet speculative.
+            // unSpeculative(sc, sd);
+        }
+
+        /* Step 2: If the TypeInfo generation requires sd.semantic3, run it later.
+         * This should be done even if typeid(T) exists in speculative scope.
+         * Because it may appear later in non-speculative scope.
+         */
+        if (!sd.members)
+            return; // opaque struct
+        if (!sd.xeq && !sd.xcmp && !sd.postblit && !sd.tidtor && !sd.xhash && !search_toString(sd))
+            return; // none of TypeInfo-specific members
+
+        // If the struct is in a non-root module, run semantic3 to get
+        // correct symbols for the member function.
+        if (sd.semanticRun >= PASS.semantic3)
+        {
+            // semantic3 is already done
+        }
+        else if (TemplateInstance ti = sd.isInstantiated())
+        {
+            if (ti.minst && !ti.minst.isRoot())
+                Module.addDeferredSemantic3(sd);
+        }
+        else
+        {
+            if (sd.inNonRoot())
+            {
+                //printf("deferred sem3 for TypeInfo - sd = %s, inNonRoot = %d\n", sd.toChars(), sd.inNonRoot());
+                Module.addDeferredSemantic3(sd);
+            }
+        }
+    }
+
+    void visitTuple(TypeTuple t)
+    {
+        if (t.arguments)
+        {
+            foreach (arg; *t.arguments)
+            {
+                semanticTypeInfo(sc, arg.type);
+            }
+        }
+    }
+
+    /* Note structural similarity of this Type walker to that in isSpeculativeType()
+     */
+
+    Type tb = t.toBasetype();
+    switch (tb.ty)
+    {
+        case Tvector:   visitVector(tb.isTypeVector()); break;
+        case Taarray:   visitAArray(tb.isTypeAArray()); break;
+        case Tstruct:   visitStruct(tb.isTypeStruct()); break;
+        case Ttuple:    visitTuple (tb.isTypeTuple());  break;
+
+        case Tclass:
+        case Tenum:     break;
+
+        default:        semanticTypeInfo(sc, tb.nextOf()); break;
+    }
+}
+
+/**
+ * Issue an error if an attempt to call a disabled method is made
+ *
+ * If the declaration is disabled but inside a disabled function,
+ * returns `true` but do not issue an error message.
+ *
+ * Params:
+ *   d = Declaration to check
+ *   loc = Location information of the call
+ *   sc  = Scope in which the call occurs
+ *   isAliasedDeclaration = if `true` searches overload set
+ *
+ * Returns:
+ *   `true` if this `Declaration` is `@disable`d, `false` otherwise.
+ */
+bool checkDisabled(Declaration d, Loc loc, Scope* sc, bool isAliasedDeclaration = false)
+{
+    if (!(d.storage_class & STC.disable))
+        return false;
+
+    if (sc.func && sc.func.storage_class & STC.disable)
+        return true;
+
+    if (auto p = d.toParent())
+    {
+        if (auto postblit = d.isPostBlitDeclaration())
+        {
+            /* https://issues.dlang.org/show_bug.cgi?id=21885
+             *
+             * If the generated postblit is disabled, it
+             * means that one of the fields has a disabled
+             * postblit. Print the first field that has
+             * a disabled postblit.
+             */
+            if (postblit.isGenerated())
+            {
+                auto sd = p.isStructDeclaration();
+                assert(sd);
+                for (size_t i = 0; i < sd.fields.length; i++)
+                {
+                    auto structField = sd.fields[i];
+                    if (structField.overlapped)
+                        continue;
+                    Type tv = structField.type.baseElemOf();
+                    if (tv.ty != Tstruct)
+                        continue;
+                    auto sdv = (cast(TypeStruct)tv).sym;
+                    if (!sdv.postblit)
+                        continue;
+                    if (sdv.postblit.isDisabled())
+                    {
+                        .error(loc, "%s `%s` is not copyable because field `%s` is not copyable", p.kind, p.toPrettyChars, structField.toChars());
+                        return true;
+                    }
+                }
+            }
+            .error(loc, "%s `%s` is not copyable because it has a disabled postblit", p.kind, p.toPrettyChars);
+            return true;
+        }
+    }
+
+    // if the function is @disabled, maybe there
+    // is an overload in the overload set that isn't
+    if (isAliasedDeclaration)
+    {
+        if (FuncDeclaration fd = d.isFuncDeclaration())
+        {
+            for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
+                if (!(ovl.storage_class & STC.disable))
+                    return false;
+        }
+    }
+
+    if (auto ctor = d.isCtorDeclaration())
+    {
+        if (ctor.isCpCtor && ctor.isGenerated())
+        {
+            .error(loc, "generating an `inout` copy constructor for `struct %s` failed, therefore instances of it are uncopyable", d.parent.toPrettyChars());
+            return true;
+        }
+    }
+    .error(loc, "%s `%s` cannot be used because it is annotated with `@disable`", d.kind, d.toPrettyChars);
+    return true;
+}
+
+/*******************************************
+ * Helper function for the expansion of manifest constant.
+ */
+private Expression expandInitializer(VarDeclaration vd, Loc loc)
+{
+    assert((vd.storage_class & STC.manifest) && vd._init);
+
+    auto e = vd.getConstInitializer();
+    if (!e)
+    {
+        .error(loc, "cannot make expression out of initializer for `%s`", vd.toChars());
+        return ErrorExp.get();
+    }
+
+    e = e.copy();
+    e.loc = loc;    // for better error message
+    return e;
+}
+
+/*****************************************************
+ * Determine if template instance is really a template function,
+ * and that template function needs to infer types from the function
+ * arguments.
+ *
+ * Like findBestMatch, iterate possible template candidates,
+ * but just looks only the necessity of type inference.
+ */
+private bool needsTypeInference(TemplateInstance ti, Scope* sc, int flag = 0)
+{
+    //printf("TemplateInstance.needsTypeInference() %s\n", toChars());
+    if (ti.semanticRun != PASS.initial)
+        return false;
+
+    const olderrs = global.errors;
+    Objects dedtypes;
+    size_t count = 0;
+
+    auto tovers = ti.tempdecl.isOverloadSet();
+    foreach (size_t oi; 0 .. tovers ? tovers.a.length : 1)
+    {
+        Dsymbol dstart = tovers ? tovers.a[oi] : ti.tempdecl;
+        int r = overloadApply(dstart, (Dsymbol s)
+        {
+            auto td = s.isTemplateDeclaration();
+            if (!td)
+                return 0;
+
+            /* If any of the overloaded template declarations need inference,
+             * then return true
+             */
+            if (!td.onemember)
+                return 0;
+            if (auto td2 = td.onemember.isTemplateDeclaration())
+            {
+                if (!td2.onemember || !td2.onemember.isFuncDeclaration())
+                    return 0;
+                if (ti.tiargs.length >= td.parameters.length - (td.isVariadic() ? 1 : 0))
+                    return 0;
+                return 1;
+            }
+            auto fd = td.onemember.isFuncDeclaration();
+            if (!fd || fd.type.ty != Tfunction)
+                return 0;
+
+            foreach (tp; *td.parameters)
+            {
+                if (tp.isTemplateThisParameter())
+                    return 1;
+            }
+
+            /* Determine if the instance arguments, tiargs, are all that is necessary
+             * to instantiate the template.
+             */
+            //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
+            auto tf = fd.type.isTypeFunction();
+            if (tf.parameterList.length)
+            {
+                auto tp = td.isVariadic();
+                if (tp && td.parameters.length > 1)
+                    return 1;
+
+                if (!tp && ti.tiargs.length < td.parameters.length)
+                {
+                    // Can remain tiargs be filled by default arguments?
+                    foreach (size_t i; ti.tiargs.length .. td.parameters.length)
+                    {
+                        if (!(*td.parameters)[i].hasDefaultArg())
+                            return 1;
+                    }
+                }
+
+                foreach (i, fparam; tf.parameterList)
+                {
+                    // 'auto ref' needs inference.
+                    if (fparam.storageClass & STC.auto_)
+                        return 1;
+                }
+            }
+
+            if (!flag)
+            {
+                /* Calculate the need for overload resolution.
+                 * When only one template can match with tiargs, inference is not necessary.
+                 */
+                dedtypes.setDim(td.parameters.length);
+                dedtypes.zero();
+                if (td.semanticRun == PASS.initial)
+                {
+                    if (td._scope)
+                    {
+                        // Try to fix forward reference. Ungag errors while doing so.
+                        Ungag ungag = td.ungagSpeculative();
+                        td.dsymbolSemantic(td._scope);
+                    }
+                    if (td.semanticRun == PASS.initial)
+                    {
+                        .error(ti.loc, "%s `%s` `%s` forward references template declaration `%s`",
+                               ti.kind, ti.toPrettyChars, ti.toChars(), td.toChars());
+                        return 1;
+                    }
+                }
+                MATCH m = matchWithInstance(sc, td, ti, dedtypes, ArgumentList(), 0);
+                if (m == MATCH.nomatch)
+                    return 0;
+            }
+
+            /* If there is more than one function template which matches, we may
+             * need type inference (see https://issues.dlang.org/show_bug.cgi?id=4430)
+             */
+            return ++count > 1 ? 1 : 0;
+        });
+        if (r)
+            return true;
+    }
+
+    if (olderrs != global.errors)
+    {
+        if (!global.gag)
+        {
+            errorSupplemental(ti.loc, "while looking for match for `%s`", ti.toChars());
+            ti.semanticRun = PASS.semanticdone;
+            ti.inst = ti;
+        }
+        ti.errors = true;
+    }
+    //printf("false\n");
+    return false;
+}
+
+/***************************************
+ * Fill out remainder of elements[] with default initializers for fields[].
+ * Params:
+ *      sd          = struct
+ *      loc         = location
+ *      elements    = explicit arguments which given to construct object.
+ *      ctorinit    = true if the elements will be used for default initialization.
+ * Returns:
+ *      false if any errors occur.
+ *      Otherwise, returns true and the missing arguments will be pushed in elements[].
+ */
+bool fill(StructDeclaration sd, const ref Loc loc, ref Expressions elements, bool ctorinit)
+{
+    //printf("AggregateDeclaration::fill() %s\n", toChars());
+    assert(sd.sizeok == Sizeok.done);
+    const nfields = sd.nonHiddenFields();
+    bool errors = false;
+
+    size_t dim = elements.length;
+    elements.setDim(nfields);
+    foreach (size_t i; dim .. nfields)
+        elements[i] = null;
+
+    // Fill in missing any elements with default initializers
+    foreach (i; 0 .. nfields)
+    {
+        if (elements[i])
+            continue;
+
+        auto vd = sd.fields[i];
+        auto vx = vd;
+        if (vd._init && vd._init.isVoidInitializer())
+            vx = null;
+
+        // Find overlapped fields with the hole [vd.offset .. vd.offset.size()].
+        size_t fieldi = i;
+        foreach (j; 0 .. nfields)
+        {
+            if (i == j)
+                continue;
+            auto v2 = sd.fields[j];
+            if (!vd.isOverlappedWith(v2))
+                continue;
+
+            if (elements[j])
+            {
+                vx = null;
+                break;
+            }
+            if (v2._init && v2._init.isVoidInitializer())
+                continue;
+
+            version (all)
+            {
+                /* Prefer first found non-void-initialized field
+                 * union U { int a; int b = 2; }
+                 * U u;    // Error: overlapping initialization for field a and b
+                 */
+                if (!vx)
+                {
+                    vx = v2;
+                    fieldi = j;
+                }
+                else if (v2._init)
+                {
+                    .error(loc, "overlapping initialization for field `%s` and `%s`", v2.toChars(), vd.toChars());
+                    errors = true;
+                }
+            }
+            else
+            {
+                // fixes https://issues.dlang.org/show_bug.cgi?id=1432 by enabling this path always
+
+                /* Prefer explicitly initialized field
+                 * union U { int a; int b = 2; }
+                 * U u;    // OK (u.b == 2)
+                 */
+                if (!vx || !vx._init && v2._init)
+                {
+                    vx = v2;
+                    fieldi = j;
+                }
+                else if (vx != vd && !vx.isOverlappedWith(v2))
+                {
+                    // Both vx and v2 fills vd, but vx and v2 does not overlap
+                }
+                else if (vx._init && v2._init)
+                {
+                    .error(loc, "overlapping default initialization for field `%s` and `%s`",
+                        v2.toChars(), vd.toChars());
+                    errors = true;
+                }
+                else
+                    assert(vx._init || !vx._init && !v2._init);
+            }
+        }
+        if (!vx)
+            continue;
+
+        Expression e;
+        if (vx.type.size() == 0)
+        {
+            e = null;
+        }
+        else if (vx._init)
+        {
+            assert(!vx._init.isVoidInitializer());
+            if (vx.inuse)   // https://issues.dlang.org/show_bug.cgi?id=18057
+            {
+                .error(loc, "%s `%s` recursive initialization of field", vx.kind(), vx.toPrettyChars());
+                errors = true;
+            }
+            else
+                e = vx.getConstInitializer(false);
+        }
+        else
+        {
+            if ((vx.storage_class & STC.nodefaultctor) && !ctorinit)
+            {
+                .error(loc, "field `%s.%s` must be initialized because it has no default constructor",
+                    sd.type.toChars(), vx.toChars());
+                errors = true;
+            }
+            /* https://issues.dlang.org/show_bug.cgi?id=12509
+             * Get the element of static array type.
+             */
+            Type telem = vx.type;
+            if (telem.ty == Tsarray)
+            {
+                /* We cannot use Type::baseElemOf() here.
+                 * If the bottom of the Tsarray is an enum type, baseElemOf()
+                 * will return the base of the enum, and its default initializer
+                 * would be different from the enum's.
+                 */
+                TypeSArray tsa;
+                while ((tsa = telem.toBasetype().isTypeSArray()) !is null)
+                    telem = tsa.next;
+                if (telem.ty == Tvoid)
+                    telem = Type.tuns8.addMod(telem.mod);
+            }
+            if (telem.needsNested() && ctorinit)
+                e = telem.defaultInit(loc);
+            else
+                e = telem.defaultInitLiteral(loc);
+        }
+        elements[fieldi] = e;
+    }
+    foreach (e; elements)
+    {
+        if (e && e.op == EXP.error)
+            return false;
+    }
+
+    return !errors;
+}
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 9d59fc99104aa4287eb5adc191fc2b8d76af4a81..e9b9367fd32ef0971cdc4acf20bed75799167b78 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -29,15 +29,14 @@ import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.delegatize;
-import dmd.dinterpret;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
 import dmd.dtemplate;
-import dmd.errors;
 import dmd.escape;
 import dmd.expression;
+import dmd.funcsem : overloadApply;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
@@ -50,8 +49,6 @@ import dmd.common.outbuffer;
 import dmd.rootobject;
 import dmd.root.string;
 import dmd.root.stringtable;
-import dmd.semantic2;
-import dmd.semantic3;
 import dmd.statement;
 import dmd.tokens;
 import dmd.visitor;
@@ -140,6 +137,10 @@ private struct FUNCFLAG
     bool computedEscapingSiblings; /// `hasEscapingSiblings` has been computed
     bool dllImport;          /// __declspec(dllimport)
     bool dllExport;          /// __declspec(dllexport)
+
+    bool hasReturnExp;         /// Has return exp; statement
+    bool hasInlineAsm;         /// Has asm{} statement
+    bool hasMultipleReturnExp; /// Has multiple return exp; statements
 }
 
 /***********************************************************
@@ -237,13 +238,6 @@ extern (C++) class FuncDeclaration : Declaration
 
     // Things that should really go into Scope
 
-    /// 1 if there's a return exp; statement
-    /// 2 if there's a throw statement
-    /// 4 if there's an assert(0)
-    /// 8 if there's inline asm
-    /// 16 if there are multiple return statements
-    int hasReturnExp;
-
     VarDeclaration nrvo_var;            /// variable to replace with shidden
     Symbol* shidden;                    /// hidden pointer passed to function
 
@@ -685,72 +679,6 @@ extern (C++) class FuncDeclaration : Declaration
         return bitFields;
     }
 
-    final bool isSafe()
-    {
-        if (safetyInprocess)
-            setUnsafe();
-        return type.toTypeFunction().trust == TRUST.safe;
-    }
-
-    extern (D) final bool isSafeBypassingInference()
-    {
-        return !(safetyInprocess) && isSafe();
-    }
-
-    final bool isTrusted()
-    {
-        if (safetyInprocess)
-            setUnsafe();
-        return type.toTypeFunction().trust == TRUST.trusted;
-    }
-
-    /**************************************
-     * The function is doing something unsafe, so mark it as unsafe.
-     *
-     * Params:
-     *   gag = surpress error message (used in escape.d)
-     *   loc = location of error
-     *   fmt = printf-style format string
-     *   arg0  = (optional) argument for first %s format specifier
-     *   arg1  = (optional) argument for second %s format specifier
-     *   arg2  = (optional) argument for third %s format specifier
-     * Returns: whether there's a safe error
-     */
-    extern (D) final bool setUnsafe(
-        bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
-        RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-    {
-        if (safetyInprocess)
-        {
-            safetyInprocess = false;
-            type.toTypeFunction().trust = TRUST.system;
-            if (fmt || arg0)
-                safetyViolation = new AttributeViolation(loc, fmt, arg0, arg1, arg2);
-
-            if (fes)
-                fes.func.setUnsafe();
-        }
-        else if (isSafe())
-        {
-            if (!gag && fmt)
-                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-
-            return true;
-        }
-        return false;
-    }
-
-    /**************************************
-     * The function is calling `@system` function `f`, so mark it as unsafe.
-     *
-     * Params:
-     *   f = function being called (needed for diagnostic of inferred functions)
-     * Returns: whether there's a safe error
-     */
-    extern (D) final bool setUnsafeCall(FuncDeclaration f)
-    {
-        return setUnsafe(false, f.loc, null, f, null);
-    }
 
     /**************************************
      * The function is doing something that may throw an exception, register that in case nothrow is being inferred
@@ -1124,118 +1052,6 @@ extern (C++) class FuncDeclaration : Declaration
     }
 }
 
-/***************************************************
- * Visit each overloaded function/template in turn, and call dg(s) on it.
- * Exit when no more, or dg(s) returns nonzero.
- *
- * Params:
- *  fstart = symbol to start from
- *  dg = the delegate to be called on the overload
- *  sc = context used to check if symbol is accessible (and therefore visible),
- *       can be null
- *
- * Returns:
- *      ==0     continue
- *      !=0     done (and the return value from the last dg() call)
- */
-extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
-{
-    Dsymbols visited;
-
-    int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
-    {
-        // Detect cyclic calls.
-        if (visited.contains(fstart))
-            return 0;
-        visited.push(fstart);
-
-        Dsymbol next;
-        for (auto d = fstart; d; d = next)
-        {
-            import dmd.access : checkSymbolAccess;
-            if (auto od = d.isOverDeclaration())
-            {
-                /* The scope is needed here to check whether a function in
-                   an overload set was added by means of a private alias (or a
-                   selective import). If the scope where the alias is created
-                   is imported somewhere, the overload set is visible, but the private
-                   alias is not.
-                */
-                if (sc)
-                {
-                    if (checkSymbolAccess(sc, od))
-                    {
-                        if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
-                            return r;
-                    }
-                }
-                else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
-                    return r;
-                next = od.overnext;
-            }
-            else if (auto fa = d.isFuncAliasDeclaration())
-            {
-                if (fa.hasOverloads)
-                {
-                    if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
-                        return r;
-                }
-                else if (auto fd = fa.toAliasFunc())
-                {
-                    if (int r = dg(fd))
-                        return r;
-                }
-                else
-                {
-                    .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
-                    break;
-                }
-                next = fa.overnext;
-            }
-            else if (auto ad = d.isAliasDeclaration())
-            {
-                if (sc)
-                {
-                    if (checkSymbolAccess(sc, ad))
-                        next = ad.toAlias();
-                }
-                else
-                   next = ad.toAlias();
-                if (next == ad)
-                    break;
-                if (next == fstart)
-                    break;
-            }
-            else if (auto td = d.isTemplateDeclaration())
-            {
-                if (int r = dg(td))
-                    return r;
-                next = td.overnext;
-            }
-            else if (auto fd = d.isFuncDeclaration())
-            {
-                if (int r = dg(fd))
-                    return r;
-                next = fd.overnext;
-            }
-            else if (auto os = d.isOverloadSet())
-            {
-                foreach (ds; os.a)
-                    if (int r = dg(ds))
-                        return r;
-            }
-            else
-            {
-                .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
-                break;
-                // BUG: should print error message?
-            }
-        }
-        return 0;
-    }
-    return overloadApplyRecurse(fstart, dg, sc);
-}
-
 /**
 Checks for mismatching modifiers between `lhsMod` and `rhsMod` and prints the
 mismatching modifiers to `buf`.
@@ -2066,68 +1882,3 @@ struct AttributeViolation
     /// ditto
     RootObject arg2 = null;
 }
-
-/// 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
-void errorSupplementalInferredAttr(FuncDeclaration fd, int maxDepth, bool deprecation, STC stc)
-{
-    auto errorFunc = deprecation ? &deprecationSupplemental : &errorSupplemental;
-
-    AttributeViolation* s;
-    const(char)* attr;
-    if (stc & STC.safe)
-    {
-        s = fd.safetyViolation;
-        attr = "@safe";
-    }
-    else if (stc & STC.pure_)
-    {
-        s = fd.pureViolation;
-        attr = "pure";
-    }
-    else if (stc & STC.nothrow_)
-    {
-        s = fd.nothrowViolation;
-        attr = "nothrow";
-    }
-    else if (stc & STC.nogc)
-    {
-        s = fd.nogcViolation;
-        attr = "@nogc";
-    }
-
-    if (!s)
-        return;
-
-    if (s.fmtStr)
-    {
-        errorFunc(s.loc, deprecation ?
-            "which wouldn't be `%s` because of:" :
-            "which wasn't inferred `%s` because of:", attr);
-        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() : "");
-        }
-        else
-        {
-            errorFunc(s.loc, s.fmtStr,
-                s.arg0 ? s.arg0.toChars() : "", s.arg1 ? s.arg1.toChars() : "", s.arg2 ? s.arg2.toChars() : "");
-        }
-    }
-    else if (auto sa = s.arg0.isDsymbol())
-    {
-        if (FuncDeclaration fd2 = sa.isFuncDeclaration())
-        {
-            if (maxDepth > 0)
-            {
-                errorFunc(s.loc, "which calls `%s`", fd2.toPrettyChars());
-                errorSupplementalInferredAttr(fd2, maxDepth - 1, deprecation, stc);
-            }
-        }
-    }
-}
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index 2ffd3ad5abbcdb7736ec1b6d887cc19ff4e4352f..c142a16f065da237782a1b29e1a3f16cbf521e4b 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -54,6 +54,7 @@ import dmd.rootobject;
 import dmd.root.filename;
 import dmd.root.string;
 import dmd.root.stringtable;
+import dmd.safe;
 import dmd.semantic2;
 import dmd.semantic3;
 import dmd.statement;
@@ -243,7 +244,7 @@ void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
 
     funcdecl.visibility = sc.visibility;
     funcdecl.userAttribDecl = sc.userAttribDecl;
-    UserAttributeDeclaration.checkGNUABITag(funcdecl, funcdecl._linkage);
+    checkGNUABITag(funcdecl, funcdecl._linkage);
     checkMustUseReserved(funcdecl);
 
     if (!funcdecl.originalType)
@@ -1166,8 +1167,8 @@ bool functionSemantic(FuncDeclaration fd)
     if (!fd.originalType) // semantic not yet run
     {
         TemplateInstance spec = fd.isSpeculative();
-        uint olderrs = global.errors;
-        uint oldgag = global.gag;
+        const olderrs = global.errors;
+        const oldgag = global.gag;
         if (global.gag && !spec)
             global.gag = 0;
         dsymbolSemantic(fd, fd._scope);
@@ -1222,8 +1223,8 @@ bool functionSemantic3(FuncDeclaration fd)
          * we need to temporarily ungag errors.
          */
         TemplateInstance spec = fd.isSpeculative();
-        uint olderrs = global.errors;
-        uint oldgag = global.gag;
+        const olderrs = global.errors;
+        const oldgag = global.gag;
         if (global.gag && !spec)
             global.gag = 0;
         semantic3(fd, fd._scope);
@@ -1648,6 +1649,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
         return null;
     }
 
+    import dmd.expressionsem : checkDisabled;
     // remove when deprecation period of class allocators and deallocators is over
     if (fd.isNewDeclaration() && fd.checkDisabled(loc, sc))
         return null;
@@ -2262,17 +2264,17 @@ bool canInferAttributes(FuncDeclaration fd, Scope* sc)
 }
 
 /*********************************************
- * In the current function, we are calling 'this' function.
- * 1. Check to see if the current function can call 'this' function, issue error if not.
- * 2. If the current function is not the parent of 'this' function, then add
- *    the current function to the list of siblings of 'this' function.
+ * In the current function 'sc.func', we are calling 'fd'.
+ * 1. Check to see if the current function can call 'fd' , issue error if not.
+ * 2. If the current function is not the parent of 'fd' , then add
+ *    the current function to the list of siblings of 'fd' .
  * 3. If the current function is a literal, and it's accessing an uplevel scope,
  *    then mark it as a delegate.
  * Returns true if error occurs.
  */
-bool checkNestedReference(FuncDeclaration fd, Scope* sc, const ref Loc loc)
+bool checkNestedFuncReference(FuncDeclaration fd, Scope* sc, const ref Loc loc)
 {
-    //printf("FuncDeclaration::checkNestedReference() %s\n", toPrettyChars());
+    //printf("FuncDeclaration::checkNestedFuncReference() %s\n", toPrettyChars());
     if (auto fld = fd.isFuncLiteralDeclaration())
     {
         if (fld.tok == TOK.reserved)
@@ -2802,121 +2804,11 @@ void modifyReturns(FuncLiteralDeclaration fld, Scope* sc, Type tret)
  * Returns: `true` if the provided scope is the root
  * of the traits compiles list of scopes.
  */
-bool isRootTraitsCompilesScope(Scope* sc)
+bool isRootTraitsCompilesScope(Scope* sc) @safe
 {
     return (sc.traitsCompiles) && !sc.func.skipCodegen;
 }
 
-/**************************************
- * A statement / expression in this scope is not `@safe`,
- * so mark the enclosing function as `@system`
- *
- * Params:
- *   sc = scope that the unsafe statement / expression is in
- *   gag = surpress error message (used in escape.d)
- *   loc = location of error
- *   fmt = printf-style format string
- *   arg0  = (optional) argument for first %s format specifier
- *   arg1  = (optional) argument for second %s format specifier
- *   arg2  = (optional) argument for third %s format specifier
- * Returns: whether there's a safe error
- */
-bool setUnsafe(Scope* sc,
-    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
-    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
-    if (sc.intypeof)
-        return false; // typeof(cast(int*)0) is safe
-
-    if (sc.debug_) // debug {} scopes are permissive
-        return false;
-
-    if (!sc.func)
-    {
-        if (sc.varDecl)
-        {
-            if (sc.varDecl.storage_class & STC.safe)
-            {
-                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-                return true;
-            }
-            else if (!(sc.varDecl.storage_class & STC.trusted))
-            {
-                sc.varDecl.storage_class |= STC.system;
-                sc.varDecl.systemInferred = true;
-            }
-        }
-        return false;
-    }
-
-
-    if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
-    {
-        if (sc.func.isSafeBypassingInference())
-        {
-            // Message wil be gagged, but still call error() to update global.errors and for
-            // -verrors=spec
-            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
-            return true;
-        }
-        return false;
-    }
-
-    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
-}
-
-/***************************************
- * Like `setUnsafe`, but for safety errors still behind preview switches
- *
- * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
- * the behavior changes based on the setting:
- *
- * - In case of `-revert=fs`, it does nothing.
- * - In case of `-preview=fs`, it's the same as `setUnsafe`
- * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
- *
- * Params:
- *   sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
- *   fs = feature state from the preview flag
- *   gag = surpress error message
- *   loc = location of error
- *   msg = 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,
-    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
-{
-    //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
-    with (FeatureState) final switch (fs)
-    {
-      case disabled:
-        return false;
-
-      case enabled:
-        return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
-
-      case default_:
-        if (!sc.func)
-            return false;
-        if (sc.func.isSafeBypassingInference())
-        {
-            if (!gag && !sc.isDeprecated())
-            {
-                deprecation(loc, msg, 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);
-        }
-        return false;
-    }
-}
-
 /+
  + Checks the parameter and return types iff this is a `main` function.
  +
@@ -3448,3 +3340,176 @@ extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type
             return true;
     }
 }
+
+/**
+ * Check signature of `pragma(printf)` function, print error if invalid.
+ *
+ * printf/scanf-like functions must be of the form:
+ *    extern (C/C++) T printf([parameters...], const(char)* format, ...);
+ * or:
+ *    extern (C/C++) T vprintf([parameters...], const(char)* format, va_list);
+ *
+ * Params:
+ *      funcdecl = function to check
+ *      f = function type
+ *      sc = scope
+ */
+private void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope* sc)
+{
+    static bool isPointerToChar(Parameter p)
+    {
+        if (auto tptr = p.type.isTypePointer())
+        {
+            return tptr.next.ty == Tchar;
+        }
+        return false;
+    }
+
+    bool isVa_list(Parameter p)
+    {
+        return p.type.equals(target.va_listType(funcdecl.loc, sc));
+    }
+
+    const nparams = f.parameterList.length;
+    const p = (funcdecl.printf ? Id.printf : Id.scanf).toChars();
+    if (!(f.linkage == LINK.c || f.linkage == LINK.cpp))
+    {
+        .error(funcdecl.loc, "`pragma(%s)` function `%s` must have `extern(C)` or `extern(C++)` linkage,"
+            ~" not `extern(%s)`",
+            p, funcdecl.toChars(), f.linkage.linkageToChars());
+    }
+    if (f.parameterList.varargs == VarArg.variadic)
+    {
+        if (!(nparams >= 1 && isPointerToChar(f.parameterList[nparams - 1])))
+        {
+            .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"
+                ~ " signature `%s %s([parameters...], const(char)*, ...)` not `%s`",
+                p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars(), funcdecl.type.toChars());
+        }
+    }
+    else if (f.parameterList.varargs == VarArg.none)
+    {
+        if(!(nparams >= 2 && isPointerToChar(f.parameterList[nparams - 2]) &&
+            isVa_list(f.parameterList[nparams - 1])))
+            .error(funcdecl.loc, "`pragma(%s)` function `%s` must have"~
+                " signature `%s %s([parameters...], const(char)*, va_list)`",
+                p, funcdecl.toChars(), f.next.toChars(), funcdecl.toChars());
+    }
+    else
+    {
+        .error(funcdecl.loc, "`pragma(%s)` function `%s` must have C-style variadic `...` or `va_list` parameter",
+            p, funcdecl.toChars());
+    }
+}
+
+/***************************************************
+ * Visit each overloaded function/template in turn, and call dg(s) on it.
+ * Exit when no more, or dg(s) returns nonzero.
+ *
+ * Params:
+ *  fstart = symbol to start from
+ *  dg = the delegate to be called on the overload
+ *  sc = context used to check if symbol is accessible (and therefore visible),
+ *       can be null
+ *
+ * Returns:
+ *      ==0     continue
+ *      !=0     done (and the return value from the last dg() call)
+ */
+extern (D) int overloadApply(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc = null)
+{
+    Dsymbols visited;
+
+    int overloadApplyRecurse(Dsymbol fstart, scope int delegate(Dsymbol) dg, Scope* sc)
+    {
+        // Detect cyclic calls.
+        if (visited.contains(fstart))
+            return 0;
+        visited.push(fstart);
+
+        Dsymbol next;
+        for (auto d = fstart; d; d = next)
+        {
+            import dmd.access : checkSymbolAccess;
+            if (auto od = d.isOverDeclaration())
+            {
+                /* The scope is needed here to check whether a function in
+                 an overload set was added by means of a private alias (or a
+                 selective import). If the scope where the alias is created
+                 is imported somewhere, the overload set is visible, but the private
+                 alias is not.
+                 */
+                if (sc)
+                {
+                    if (checkSymbolAccess(sc, od))
+                    {
+                        if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
+                            return r;
+                    }
+                }
+                else if (int r = overloadApplyRecurse(od.aliassym, dg, sc))
+                    return r;
+                next = od.overnext;
+            }
+            else if (auto fa = d.isFuncAliasDeclaration())
+            {
+                if (fa.hasOverloads)
+                {
+                    if (int r = overloadApplyRecurse(fa.funcalias, dg, sc))
+                        return r;
+                }
+                else if (auto fd = fa.toAliasFunc())
+                {
+                    if (int r = dg(fd))
+                        return r;
+                }
+                else
+                {
+                    .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
+                    break;
+                }
+                next = fa.overnext;
+            }
+            else if (auto ad = d.isAliasDeclaration())
+            {
+                if (sc)
+                {
+                    if (checkSymbolAccess(sc, ad))
+                    next = ad.toAlias();
+                }
+                else
+                    next = ad.toAlias();
+                if (next == ad)
+                    break;
+                if (next == fstart)
+                    break;
+            }
+            else if (auto td = d.isTemplateDeclaration())
+            {
+                if (int r = dg(td))
+                    return r;
+                next = td.overnext;
+            }
+            else if (auto fd = d.isFuncDeclaration())
+            {
+                if (int r = dg(fd))
+                    return r;
+                next = fd.overnext;
+            }
+            else if (auto os = d.isOverloadSet())
+            {
+                foreach (ds; os.a)
+                if (int r = dg(ds))
+                    return r;
+            }
+            else
+            {
+                .error(d.loc, "%s `%s` is aliased to a function", d.kind, d.toPrettyChars);
+                break;
+                // BUG: should print error message?
+            }
+        }
+        return 0;
+    }
+    return overloadApplyRecurse(fstart, dg, sc);
+}
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index ea884455161070a75a1a11cd7152315e88ff4246..ccb63e330e9e5879b67bd65585e1c173461c9895 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -134,7 +134,7 @@ extern(C++) struct Verbose
     uint errorLimit = 20;
     uint errorSupplementLimit = 6;      // Limit the number of supplemental messages for each error (0 means unlimited)
 
-    uint errorSupplementCount()
+    uint errorSupplementCount() @safe
     {
         if (verbose)
             return uint.max;
@@ -157,7 +157,7 @@ extern (C++) struct Param
     bool useInline = false;     // inline expand functions
     bool release;           // build release version
     bool preservePaths;     // true means don't strip path from source file
-    DiagnosticReporting warnings = DiagnosticReporting.off;  // how compiler warnings are handled
+    DiagnosticReporting useWarnings = DiagnosticReporting.off;  // how compiler warnings are handled
     bool cov;               // generate code coverage data
     ubyte covPercent;       // 0..100 code coverage percentage required
     bool ctfe_cov = false;  // generate coverage data for ctfe
@@ -256,7 +256,7 @@ extern (C++) struct Param
     const(char)* timeTraceFile; /// File path of output file
 
     ///
-    bool parsingUnittestsRequired()
+    bool parsingUnittestsRequired() @safe
     {
         return useUnitTests || ddoc.doOutput || dihdr.doOutput;
     }
@@ -383,7 +383,15 @@ extern (C++) struct Global
         {
             compileEnv.vendor = "GNU D";
         }
-        compileEnv.versionNumber = parseVersionNumber(_version);
+        else version (IN_LLVM)
+        {
+            compileEnv.vendor = "LDC";
+
+            import dmd.console : detectTerminal;
+            params.v.color = detectTerminal();
+        }
+
+        compileEnv.versionNumber = parseVersionNumber(versionString());
 
         /* Initialize date, time, and timestamp
          */
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 45efab094752b82d14d0eb300878426943fc3f16..5348d614ebb3a64429042b805fd668bdef9e6136 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -35,7 +35,8 @@ enum
 enum class MessageStyle : unsigned char
 {
     digitalmars, // file(line,column): message
-    gnu          // file:line:column: message
+    gnu,         // file:line:column: message
+    sarif        // JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
 };
 
 // The state of array bounds checking
@@ -160,7 +161,7 @@ struct Param
     d_bool useInline;     // inline expand functions
     d_bool release;       // build release version
     d_bool preservePaths; // true means don't strip path from source file
-    Diagnostic warnings;
+    Diagnostic useWarnings;
     d_bool cov;           // generate code coverage data
     unsigned char covPercent;   // 0..100 code coverage percentage required
     d_bool ctfe_cov;      // generate coverage data for ctfe
@@ -291,6 +292,7 @@ struct CompileEnv
     DString vendor;
     DString timestamp;
     d_bool previewIn;
+    d_bool transitionIn;
     d_bool ddocOutput;
     d_bool masm;
     IdentifierCharLookup cCharLookupTable;
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index e3f1dc283f7039c12cd43b9ac44a0535818431ee..86131f2f11c96ed239a999fbe9b20c7afff008ab 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -1720,10 +1720,10 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
         //printf("FuncDeclaration::toCBuffer() '%s'\n", f.toChars());
         if (stcToBuffer(buf, f.storage_class))
             buf.writeByte(' ');
+        typeToBuffer(f.type, f.ident, buf, hgs);
         auto tf = f.type.isTypeFunction();
-        typeToBuffer(tf, f.ident, buf, hgs);
 
-        if (hgs.hdrgen)
+        if (hgs.hdrgen && tf)
         {
             // if the return type is missing (e.g. ref functions or auto)
             // https://issues.dlang.org/show_bug.cgi?id=20090
@@ -1858,9 +1858,9 @@ void toCBuffer(Dsymbol s, ref OutBuffer buf, ref HdrGenState hgs)
         if (stcToBuffer(buf, d.storage_class))
             buf.writeByte(' ');
         buf.writestring("invariant");
-        if(auto es = d.fbody.isExpStatement())
+        auto es = d.fbody.isExpStatement();
+        if (es && es.exp && es.exp.op == EXP.assert_)
         {
-            assert(es.exp && es.exp.op == EXP.assert_);
             buf.writestring(" (");
             (cast(AssertExp)es.exp).e1.expressionToBuffer(buf, hgs);
             buf.writestring(");");
@@ -3796,7 +3796,8 @@ private void tiargsToBuffer(TemplateInstance ti, ref OutBuffer buf, ref HdrGenSt
         }
         else if (Expression e = isExpression(oarg))
         {
-            if (e.op == EXP.int64 || e.op == EXP.float64 || e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
+            if (!(e.type && e.type.isTypeEnum()) && e.op == EXP.int64 || e.op == EXP.float64 ||
+                e.op == EXP.null_ || e.op == EXP.string_ || e.op == EXP.this_)
             {
                 toCBuffer(e, buf, hgs);
                 return;
diff --git a/gcc/d/dmd/iasm.d b/gcc/d/dmd/iasm.d
index 1399ac27fae2b9b3719b3d56bfbdc652af803b83..7eb51d995ce1ee9cd5707f718bc34f95261dbb15 100644
--- a/gcc/d/dmd/iasm.d
+++ b/gcc/d/dmd/iasm.d
@@ -50,7 +50,7 @@ Statement asmSemantic(AsmStatement s, Scope *sc)
         return null;
 
     // Assume assembler code takes care of setting the return value
-    sc.func.hasReturnExp |= 8;
+    sc.func.hasInlineAsm = true;
 
     version (NoBackend)
     {
diff --git a/gcc/d/dmd/iasmgcc.d b/gcc/d/dmd/iasmgcc.d
index 4b1b2e78c69e9f399ad04cc5fafdf7b0f5afef3e..1410e0a2299173d055ce63260f0e4f318f7b9752 100644
--- a/gcc/d/dmd/iasmgcc.d
+++ b/gcc/d/dmd/iasmgcc.d
@@ -29,6 +29,117 @@ import dmd.tokens;
 import dmd.statement;
 import dmd.statementsem;
 
+/***********************************
+ * Parse and run semantic analysis on a GccAsmStatement.
+ * Params:
+ *      s  = gcc asm statement being parsed
+ *      sc = the scope where the asm statement is located
+ * Returns:
+ *      the completed gcc asm statement, or null if errors occurred
+ */
+public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
+{
+    //printf("GccAsmStatement.semantic()\n");
+    const bool doUnittests = global.params.parsingUnittestsRequired();
+    scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests);
+
+    // Make a safe copy of the token list before parsing.
+    Token *toklist = null;
+    Token **ptoklist = &toklist;
+
+    for (Token *token = s.tokens; token; token = token.next)
+    {
+        *ptoklist = p.allocateToken();
+        memcpy(*ptoklist, token, Token.sizeof);
+        ptoklist = &(*ptoklist).next;
+        *ptoklist = null;
+    }
+    p.token = *toklist;
+    p.scanloc = s.loc;
+
+    // Parse the gcc asm statement.
+    const errors = global.errors;
+    s = p.parseGccAsm(s);
+    if (errors != global.errors)
+        return null;
+    s.stc = sc.stc;
+
+    // Fold the instruction template string.
+    s.insn = semanticString(sc, s.insn, "asm instruction template");
+
+    if (s.labels && s.outputargs)
+        error(s.loc, "extended asm statements with labels cannot have output constraints");
+
+    // Analyse all input and output operands.
+    if (s.args)
+    {
+        foreach (i; 0 .. s.args.length)
+        {
+            Expression e = (*s.args)[i];
+            e = e.expressionSemantic(sc);
+            // Check argument is a valid lvalue/rvalue.
+            if (i < s.outputargs)
+                e = e.modifiableLvalue(sc);
+            else if (e.checkValue())
+                e = ErrorExp.get();
+            (*s.args)[i] = e;
+
+            e = (*s.constraints)[i];
+            e = e.expressionSemantic(sc);
+            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
+            (*s.constraints)[i] = e;
+        }
+    }
+
+    // Analyse all clobbers.
+    if (s.clobbers)
+    {
+        foreach (i; 0 .. s.clobbers.length)
+        {
+            Expression e = (*s.clobbers)[i];
+            e = e.expressionSemantic(sc);
+            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
+            (*s.clobbers)[i] = e;
+        }
+    }
+
+    // Analyse all goto labels.
+    if (s.labels)
+    {
+        foreach (i; 0 .. s.labels.length)
+        {
+            Identifier ident = (*s.labels)[i];
+            GotoStatement gs = new GotoStatement(s.loc, ident);
+            if (!s.gotos)
+                s.gotos = new GotoStatements();
+            s.gotos.push(gs);
+            gs.statementSemantic(sc);
+        }
+    }
+
+    return s;
+}
+
+/***********************************
+ * Run semantic analysis on an CAsmDeclaration.
+ * Params:
+ *      ad  = asm declaration
+ *      sc = the scope where the asm declaration is located
+ */
+public void gccAsmSemantic(CAsmDeclaration ad, Scope *sc)
+{
+    import dmd.typesem : pointerTo;
+    ad.code = semanticString(sc, ad.code, "asm definition");
+    ad.code.type = ad.code.type.nextOf().pointerTo();
+
+    // Asm definition always needs emitting into the root module.
+    import dmd.dmodule : Module;
+    if (sc._module && sc._module.isRoot())
+        return;
+    if (Module m = Module.rootModule)
+        m.members.push(ad);
+}
+
 private:
 
 /***********************************
@@ -292,117 +403,6 @@ Ldone:
     return s;
 }
 
-/***********************************
- * Parse and run semantic analysis on a GccAsmStatement.
- * Params:
- *      s  = gcc asm statement being parsed
- *      sc = the scope where the asm statement is located
- * Returns:
- *      the completed gcc asm statement, or null if errors occurred
- */
-public Statement gccAsmSemantic(GccAsmStatement s, Scope *sc)
-{
-    //printf("GccAsmStatement.semantic()\n");
-    const bool doUnittests = global.params.parsingUnittestsRequired();
-    scope p = new Parser!ASTCodegen(sc._module, ";", false, global.errorSink, &global.compileEnv, doUnittests);
-
-    // Make a safe copy of the token list before parsing.
-    Token *toklist = null;
-    Token **ptoklist = &toklist;
-
-    for (Token *token = s.tokens; token; token = token.next)
-    {
-        *ptoklist = p.allocateToken();
-        memcpy(*ptoklist, token, Token.sizeof);
-        ptoklist = &(*ptoklist).next;
-        *ptoklist = null;
-    }
-    p.token = *toklist;
-    p.scanloc = s.loc;
-
-    // Parse the gcc asm statement.
-    const errors = global.errors;
-    s = p.parseGccAsm(s);
-    if (errors != global.errors)
-        return null;
-    s.stc = sc.stc;
-
-    // Fold the instruction template string.
-    s.insn = semanticString(sc, s.insn, "asm instruction template");
-
-    if (s.labels && s.outputargs)
-        error(s.loc, "extended asm statements with labels cannot have output constraints");
-
-    // Analyse all input and output operands.
-    if (s.args)
-    {
-        foreach (i; 0 .. s.args.length)
-        {
-            Expression e = (*s.args)[i];
-            e = e.expressionSemantic(sc);
-            // Check argument is a valid lvalue/rvalue.
-            if (i < s.outputargs)
-                e = e.modifiableLvalue(sc);
-            else if (e.checkValue())
-                e = ErrorExp.get();
-            (*s.args)[i] = e;
-
-            e = (*s.constraints)[i];
-            e = e.expressionSemantic(sc);
-            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
-            (*s.constraints)[i] = e;
-        }
-    }
-
-    // Analyse all clobbers.
-    if (s.clobbers)
-    {
-        foreach (i; 0 .. s.clobbers.length)
-        {
-            Expression e = (*s.clobbers)[i];
-            e = e.expressionSemantic(sc);
-            assert(e.op == EXP.string_ && (cast(StringExp) e).sz == 1);
-            (*s.clobbers)[i] = e;
-        }
-    }
-
-    // Analyse all goto labels.
-    if (s.labels)
-    {
-        foreach (i; 0 .. s.labels.length)
-        {
-            Identifier ident = (*s.labels)[i];
-            GotoStatement gs = new GotoStatement(s.loc, ident);
-            if (!s.gotos)
-                s.gotos = new GotoStatements();
-            s.gotos.push(gs);
-            gs.statementSemantic(sc);
-        }
-    }
-
-    return s;
-}
-
-/***********************************
- * Run semantic analysis on an CAsmDeclaration.
- * Params:
- *      ad  = asm declaration
- *      sc = the scope where the asm declaration is located
- */
-public void gccAsmSemantic(CAsmDeclaration ad, Scope *sc)
-{
-    import dmd.typesem : pointerTo;
-    ad.code = semanticString(sc, ad.code, "asm definition");
-    ad.code.type = ad.code.type.nextOf().pointerTo();
-
-    // Asm definition always needs emitting into the root module.
-    import dmd.dmodule : Module;
-    if (sc._module && sc._module.isRoot())
-        return;
-    if (Module m = Module.rootModule)
-        m.members.push(ad);
-}
-
 unittest
 {
     import dmd.mtype : TypeBasic;
@@ -410,7 +410,7 @@ unittest
     if (!global.errorSink)
         global.errorSink = new ErrorSinkCompiler;
 
-    uint errors = global.startGagging();
+    const errors = global.startGagging();
     scope(exit) global.endGagging(errors);
 
     // If this check fails, then Type._init() was called before reaching here,
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index a72fd90ec983b8b48fb79c162daf18c02e388771..505a3e13636fb81fb3fccbdd29f80cd3fc93fb28 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -41,6 +41,7 @@ import dmd.location;
 import dmd.mtype;
 import dmd.opover;
 import dmd.optimize;
+import dmd.safe : setUnsafe;
 import dmd.statement;
 import dmd.target;
 import dmd.tokens;
diff --git a/gcc/d/dmd/json.d b/gcc/d/dmd/json.d
index f20b3d4b38a3cec36a33e5061b3c2520b79d5df9..021387d6f4380eda4c3870b9ac6bd19a86385740 100644
--- a/gcc/d/dmd/json.d
+++ b/gcc/d/dmd/json.d
@@ -24,6 +24,7 @@ import dmd.denum;
 import dmd.dimport;
 import dmd.dmodule;
 import dmd.dsymbol;
+import dmd.dsymbolsem : include;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index 0ef2dbd8e0ecb9437ed1b333ac41211ddde09e1a..90c794e240555e6f9512876012976b6964a9851e 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -26,8 +26,8 @@ import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.expression;
 import dmd.func;
-import dmd.dmangle;
 import dmd.hdrgen;
+import dmd.mangle;
 import dmd.mtype;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 2a11f30801799c3da7f5b33404f225ac92f86349..476a700bdeb7da13b58663130c87aff85ce1c751 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -53,6 +53,7 @@ struct CompileEnv
     const(char)[] timestamp; /// __TIMESTAMP__
 
     bool previewIn;          /// `in` means `[ref] scope const`, accepts rvalues
+    bool transitionIn;       /// `-transition=in` is active, `in` parameters are listed
     bool ddocOutput;         /// collect embedded documentation comments
     bool masm;               /// use MASM inline asm syntax
 
diff --git a/gcc/d/dmd/location.d b/gcc/d/dmd/location.d
index ca6805ee0b68a12033120d8e56707416f39cf2a7..07870685910164cb105d33283f35fbe681616b0b 100644
--- a/gcc/d/dmd/location.d
+++ b/gcc/d/dmd/location.d
@@ -16,6 +16,7 @@ import core.stdc.stdio;
 import dmd.common.outbuffer;
 import dmd.root.array;
 import dmd.root.filename;
+import dmd.root.string: toDString;
 
 version (DMDLIB)
 {
@@ -27,8 +28,8 @@ enum MessageStyle : ubyte
 {
     digitalmars,  /// filename.d(line): message
     gnu,          /// filename.d:line: message, see https://www.gnu.org/prep/standards/html_node/Errors.html
+    sarif         /// JSON SARIF output, see https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
 }
-
 /**
 A source code location
 
@@ -126,35 +127,7 @@ nothrow:
         MessageStyle messageStyle = Loc.messageStyle) const nothrow
     {
         OutBuffer buf;
-        if (fileIndex)
-        {
-            buf.writestring(filename);
-        }
-        if (linnum)
-        {
-            final switch (messageStyle)
-            {
-                case MessageStyle.digitalmars:
-                    buf.writeByte('(');
-                    buf.print(linnum);
-                    if (showColumns && charnum)
-                    {
-                        buf.writeByte(',');
-                        buf.print(charnum);
-                    }
-                    buf.writeByte(')');
-                    break;
-                case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
-                    buf.writeByte(':');
-                    buf.print(linnum);
-                    if (showColumns && charnum)
-                    {
-                        buf.writeByte(':');
-                        buf.print(charnum);
-                    }
-                    break;
-            }
-        }
+        writeSourceLoc(buf, SourceLoc(this), showColumns, messageStyle);
         return buf.extractChars();
     }
 
@@ -210,3 +183,79 @@ nothrow:
         return fileIndex != 0;
     }
 }
+
+/**
+ * Format a source location for error messages
+ *
+ * Params:
+ *   buf = buffer to write string into
+ *   loc = source location to write
+ *   showColumns = include column number in message
+ *   messageStyle = select error message format
+ */
+void writeSourceLoc(ref OutBuffer buf,
+    SourceLoc loc,
+    bool showColumns,
+    MessageStyle messageStyle) nothrow
+{
+    buf.writestring(loc.filename);
+    if (loc.line == 0)
+        return;
+
+    final switch (messageStyle)
+    {
+        case MessageStyle.digitalmars:
+            buf.writeByte('(');
+            buf.print(loc.line);
+            if (showColumns && loc.column)
+            {
+                buf.writeByte(',');
+                buf.print(loc.column);
+            }
+            buf.writeByte(')');
+            break;
+        case MessageStyle.gnu: // https://www.gnu.org/prep/standards/html_node/Errors.html
+            buf.writeByte(':');
+            buf.print(loc.line);
+            if (showColumns && loc.column)
+            {
+                buf.writeByte(':');
+                buf.print(loc.column);
+            }
+            break;
+        case MessageStyle.sarif: // https://docs.oasis-open.org/sarif/sarif/v2.1.0/sarif-v2.1.0.html
+            // No formatting needed here for SARIF
+            break;
+    }
+}
+
+/**
+ * Describes a location in the source code as a file + line number + column number
+ *
+ * While `Loc` is a compact opaque location meant to be stored in the AST,
+ * this struct has simple modifiable fields and is used for printing.
+ */
+struct SourceLoc
+{
+    const(char)[] filename; /// name of source file
+    uint line; /// line number (starts at 1)
+    uint column; /// column number (starts at 1)
+
+    // aliases for backwards compatibility
+    alias linnum = line;
+    alias charnum = column;
+
+    this(const(char)[] filename, uint line, uint column) nothrow
+    {
+        this.filename = filename;
+        this.line = line;
+        this.column = column;
+    }
+
+    this(Loc loc) nothrow
+    {
+        this.filename = loc.filename.toDString();
+        this.line = loc.linnum;
+        this.column = loc.charnum;
+    }
+}
diff --git a/gcc/d/dmd/basicmangle.d b/gcc/d/dmd/mangle/basic.d
similarity index 99%
rename from gcc/d/dmd/basicmangle.d
rename to gcc/d/dmd/mangle/basic.d
index 52534fa3526bad4038b7c6b7560832b611f3fd46..eb5a49e9f15fc4e963a9d1f99712d39f3cdd65da 100644
--- a/gcc/d/dmd/basicmangle.d
+++ b/gcc/d/dmd/mangle/basic.d
@@ -7,7 +7,7 @@
  * Documentation:  https://dlang.org/phobos/dmd_basicmangle.html
  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/basicmangle.d
  */
-module dmd.basicmangle;
+module dmd.mangle.basic;
 
 import dmd.astenums;
 import dmd.common.outbuffer : OutBuffer;
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/mangle/cpp.d
similarity index 99%
rename from gcc/d/dmd/cppmangle.d
rename to gcc/d/dmd/mangle/cpp.d
index c5519217bcf9cae74f1b55939518512a2e899f29..9ce3f9c8ed038ae2989bb644ceb2dbf3fb0330af 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/mangle/cpp.d
@@ -21,7 +21,7 @@
  *  enter `C++, mangling` as the keywords.
  */
 
-module dmd.cppmangle;
+module dmd.mangle.cpp;
 
 import core.stdc.stdio;
 
@@ -30,6 +30,7 @@ import dmd.astenums;
 import dmd.attrib;
 import dmd.declaration;
 import dmd.dsymbol;
+import dmd.dsymbolsem : isGNUABITag;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
@@ -2433,7 +2434,7 @@ private struct ABITagContainer
 
         foreach (exp; *s.userAttribDecl.atts)
         {
-            if (UserAttributeDeclaration.isGNUABITag(exp))
+            if (isGNUABITag(exp))
                 return (*exp.isStructLiteralExp().elements)[0]
                     .isArrayLiteralExp();
         }
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/mangle/package.d
similarity index 99%
rename from gcc/d/dmd/dmangle.d
rename to gcc/d/dmd/mangle/package.d
index 21f0392a6fe3a3ca2922fabf6ff1d6752b978315..d184fe9f42c247c1a9eaa510fe77df530afc8714 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/mangle/package.d
@@ -12,7 +12,7 @@
  * References:  https://dlang.org/blog/2017/12/20/ds-newfangled-name-mangling/
  */
 
-module dmd.dmangle;
+module dmd.mangle;
 
 
 /******************************************************************************
@@ -70,7 +70,7 @@ void mangleToBuffer(TemplateInstance ti, ref OutBuffer buf)
 }
 
 /// Returns: `true` if the given character is a valid mangled character
-package bool isValidMangling(dchar c) nothrow
+package(dmd) bool isValidMangling(dchar c) nothrow
 {
     import dmd.common.charactertables;
 
@@ -139,7 +139,7 @@ import core.stdc.string;
 import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
-import dmd.basicmangle;
+import dmd.mangle.basic;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dinterpret;
@@ -830,7 +830,7 @@ public:
                     continue;
                 }
                 // Now that we know it is not an alias, we MUST obtain a value
-                uint olderr = global.errors;
+                const olderr = global.errors;
                 ea = ea.ctfeInterpret();
                 if (ea.op == EXP.error || olderr != global.errors)
                     continue;
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index aa4ca40d10801bfcd87b10378fecdd1237ec673d..be70b02dec90c4489f711e704396671330c5ec04 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -30,6 +30,7 @@ import dmd.dtemplate;
 import dmd.enumsem;
 import dmd.errors;
 import dmd.expression;
+import dmd.dsymbolsem : determineSize;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
@@ -515,7 +516,7 @@ extern (C++) abstract class Type : ASTNode
 
         static Type merge(Type t)
         {
-            import dmd.basicmangle : tyToDecoBuffer;
+            import dmd.mangle.basic : tyToDecoBuffer;
 
             OutBuffer buf;
             buf.reserve(3);
@@ -1115,65 +1116,66 @@ extern (C++) abstract class Type : ASTNode
         Type t = this;
         if (t.isImmutable())
         {
+            return t;
         }
         else if (stc & STC.immutable_)
         {
             t = t.makeImmutable();
+            return t;
         }
-        else
+
+        if ((stc & STC.shared_) && !t.isShared())
         {
-            if ((stc & STC.shared_) && !t.isShared())
+            if (t.isWild())
+            {
+                if (t.isConst())
+                    t = t.makeSharedWildConst();
+                else
+                    t = t.makeSharedWild();
+            }
+            else
+            {
+                if (t.isConst())
+                    t = t.makeSharedConst();
+                else
+                    t = t.makeShared();
+            }
+        }
+        if ((stc & STC.const_) && !t.isConst())
+        {
+            if (t.isShared())
             {
                 if (t.isWild())
-                {
-                    if (t.isConst())
-                        t = t.makeSharedWildConst();
-                    else
-                        t = t.makeSharedWild();
-                }
+                    t = t.makeSharedWildConst();
                 else
-                {
-                    if (t.isConst())
-                        t = t.makeSharedConst();
-                    else
-                        t = t.makeShared();
-                }
+                    t = t.makeSharedConst();
             }
-            if ((stc & STC.const_) && !t.isConst())
+            else
             {
-                if (t.isShared())
-                {
-                    if (t.isWild())
-                        t = t.makeSharedWildConst();
-                    else
-                        t = t.makeSharedConst();
-                }
+                if (t.isWild())
+                    t = t.makeWildConst();
                 else
-                {
-                    if (t.isWild())
-                        t = t.makeWildConst();
-                    else
-                        t = t.makeConst();
-                }
+                    t = t.makeConst();
             }
-            if ((stc & STC.wild) && !t.isWild())
+        }
+        if ((stc & STC.wild) && !t.isWild())
+        {
+            if (t.isShared())
             {
-                if (t.isShared())
-                {
-                    if (t.isConst())
-                        t = t.makeSharedWildConst();
-                    else
-                        t = t.makeSharedWild();
-                }
+                if (t.isConst())
+                    t = t.makeSharedWildConst();
                 else
-                {
-                    if (t.isConst())
-                        t = t.makeWildConst();
-                    else
-                        t = t.makeWild();
-                }
+                    t = t.makeSharedWild();
+            }
+            else
+            {
+                if (t.isConst())
+                    t = t.makeWildConst();
+                else
+                    t = t.makeWild();
             }
         }
+
         return t;
     }
 
@@ -1398,33 +1400,6 @@ extern (C++) abstract class Type : ASTNode
         return t;
     }
 
-    /*******************************************
-     * Compute number of elements for a (possibly multidimensional) static array,
-     * or 1 for other types.
-     * Params:
-     *  loc = for error message
-     * Returns:
-     *  number of elements, uint.max on overflow
-     */
-    final uint numberOfElems(const ref Loc loc)
-    {
-        //printf("Type::numberOfElems()\n");
-        uinteger_t n = 1;
-        Type tb = this;
-        while ((tb = tb.toBasetype()).ty == Tsarray)
-        {
-            bool overflow = false;
-            n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
-            if (overflow || n >= uint.max)
-            {
-                error(loc, "static array `%s` size overflowed to %llu", toChars(), cast(ulong)n);
-                return uint.max;
-            }
-            tb = (cast(TypeSArray)tb).next;
-        }
-        return cast(uint)n;
-    }
-
     /****************************************
      * Return the mask that an integral type will
      * fit into.
@@ -2724,36 +2699,6 @@ extern (C++) final class TypeFunction : TypeNext
         return newArgs;
     }
 
-    extern (D) bool checkRetType(const ref Loc loc)
-    {
-        Type tb = next.toBasetype();
-        if (tb.ty == Tfunction)
-        {
-            error(loc, "functions cannot return a function");
-            next = Type.terror;
-        }
-        if (tb.ty == Ttuple)
-        {
-            error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)");
-            next = Type.terror;
-        }
-        if (!isRef && (tb.ty == Tstruct || tb.ty == Tsarray))
-        {
-            if (auto ts = tb.baseElemOf().isTypeStruct())
-            {
-                if (!ts.sym.members)
-                {
-                    error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
-                    next = Type.terror;
-                }
-            }
-        }
-        if (tb.ty == Terror)
-            return true;
-        return false;
-    }
-
-
     /// Returns: `true` the function is `isInOutQual` or `isInOutParam` ,`false` otherwise.
     bool iswild() const pure nothrow @safe @nogc
     {
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 6ba8d89b248a0047130a9a2bf86839a8a67d62eb..5cd928ca5f41f8ec28d1fefd8ae46f5f35637ecb 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -22,7 +22,6 @@ import dmd.cond;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.denum;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dstruct;
@@ -38,6 +37,7 @@ import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
+import dmd.mangle;
 import dmd.mtype;
 import dmd.root.array;
 import dmd.common.outbuffer;
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index e409a7907e984c027bb87238c9239a05308d7c0e..282575db62cc1265d594b419c588e2133be84f33 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -183,31 +183,29 @@ private Expression fromConstInitializer(int result, Expression e1)
 {
     //printf("fromConstInitializer(result = %x, %s)\n", result, e1.toChars());
     //static int xx; if (xx++ == 10) assert(0);
+    auto ve = e1.isVarExp();
+    if (!ve)
+        return e1;
+
     Expression e = e1;
-    if (auto ve = e1.isVarExp())
+    VarDeclaration v = ve.var.isVarDeclaration();
+    e = expandVar(result, v);
+    if (!e)
+        return e1;
+
+    // If it is a comma expression involving a declaration, we mustn't
+    // perform a copy -- we'd get two declarations of the same variable.
+    // See https://issues.dlang.org/show_bug.cgi?id=4465.
+    if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
+        e = e1;
+    else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
     {
-        VarDeclaration v = ve.var.isVarDeclaration();
-        e = expandVar(result, v);
-        if (e)
-        {
-            // If it is a comma expression involving a declaration, we mustn't
-            // perform a copy -- we'd get two declarations of the same variable.
-            // See https://issues.dlang.org/show_bug.cgi?id=4465.
-            if (e.op == EXP.comma && e.isCommaExp().e1.isDeclarationExp())
-                e = e1;
-            else if (e.type != e1.type && e1.type && e1.type.ty != Tident)
-            {
-                // Type 'paint' operation
-                e = e.copy();
-                e.type = e1.type;
-            }
-            e.loc = e1.loc;
-        }
-        else
-        {
-            e = e1;
-        }
+        // Type 'paint' operation
+        e = e.copy();
+        e.type = e1.type;
     }
+    e.loc = e1.loc;
+
     return e;
 }
 
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index bb2411825faeebd7baf7f866e2c7af22e975aa9d..e8324eb0710654db7f9984e2581f4094bf96fa39 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -49,8 +49,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         bool doUnittests; // parse unittest blocks
     }
 
-    bool transitionIn = false; /// `-transition=in` is active, `in` parameters are listed
-
     /*********************
      * Use this constructor for string mixins.
      * Input:
@@ -543,7 +541,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 break;
 
             case TOK.new_:
-                s = parseNew(pAttrs);
+                s = parseNewDeclaration(pAttrs);
                 break;
 
             case TOK.colon:
@@ -2493,7 +2491,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
 
         AST.Expression constraint = tpl ? parseConstraint() : null;
 
-        AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // RetrunType -> auto
+        AST.Type tf = new AST.TypeFunction(parameterList, null, linkage, stc); // ReturnType -> auto
         tf = tf.addSTC(stc);
 
         auto f = new AST.CtorDeclaration(loc, Loc.initial, stc, tf);
@@ -2791,7 +2789,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
      *      @disable new();
      * Current token is 'new'.
      */
-    private AST.Dsymbol parseNew(PrefixAttributes!AST* pAttrs)
+    private AST.Dsymbol parseNewDeclaration(PrefixAttributes!AST* pAttrs)
     {
         const loc = token.loc;
         StorageClass stc = getStorageClass!AST(pAttrs);
@@ -2918,7 +2916,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                         // Don't call nextToken again.
                     }
                 case TOK.in_:
-                    if (transitionIn)
+                    if (compileEnv.transitionIn)
                         eSink.message(scanloc, "Usage of 'in' on parameter");
                     stc = STC.in_;
                     if (compileEnv.previewIn)
@@ -3501,7 +3499,12 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                         name = _alias;
                         _alias = null;
                     }
-                    s.addAlias(name, _alias);
+                    if (s.isstatic)
+                        error(loc, "static import `%s` cannot have an import bind list", s.toPrettyChars());
+                    if (!s.aliasId)
+                        s.ident = null; // make it an anonymous import
+                    s.names.push(name);
+                    s.aliases.push(_alias);
                 }
                 while (token.value == TOK.comma);
                 break; // no comma-separated imports of this form
@@ -9499,6 +9502,15 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
     }
 
     /*******************************************
+     * Params:
+     *    thisexp = If not null, it is the `this` reference for the creation
+     *              of an inner class.
+     *              https://dlang.org/spec/class.html#nested-explicit
+     *              https://dlang.org/spec/expression.html#postfix_expressions
+     *              If null, then it is a NewExpression.
+     *              https://dlang.org/spec/expression.html#NewExpression
+     * Returns:
+     *   NewExpression
      */
     private AST.Expression parseNewExp(AST.Expression thisexp)
     {
@@ -9769,6 +9781,7 @@ immutable PREC[EXP.max + 1] precedence =
     EXP.assign : PREC.assign,
     EXP.construct : PREC.assign,
     EXP.blit : PREC.assign,
+    EXP.loweredAssignExp : PREC.assign,
     EXP.addAssign : PREC.assign,
     EXP.minAssign : PREC.assign,
     EXP.concatenateAssign : PREC.assign,
diff --git a/gcc/d/dmd/pragmasem.d b/gcc/d/dmd/pragmasem.d
index 4dceb595e54fef5a20d2e54b0db44f8aa324883a..f2f748500a633cef34d2aa469cd2d080535ce801 100644
--- a/gcc/d/dmd/pragmasem.d
+++ b/gcc/d/dmd/pragmasem.d
@@ -21,6 +21,7 @@ import dmd.attrib;
 import dmd.dinterpret;
 import dmd.dscope;
 import dmd.dsymbol;
+import dmd.dsymbolsem : include;
 import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
@@ -40,10 +41,10 @@ void pragmaDeclSemantic(PragmaDeclaration pd, Scope* sc)
 {
     import dmd.aggregate;
     import dmd.common.outbuffer;
-    import dmd.dmangle;
     import dmd.dmodule;
     import dmd.dsymbolsem;
     import dmd.identifier;
+    import dmd.mangle : isValidMangling;
     import dmd.root.rmem;
     import dmd.root.utf;
     import dmd.target;
@@ -557,32 +558,19 @@ private uint setMangleOverride(Dsymbol s, const(char)[] sym)
 private bool pragmaMsgSemantic(Loc loc, Scope* sc, Expressions* args)
 {
     import dmd.tokens;
+    import dmd.common.outbuffer;
 
     if (!args)
         return true;
-    foreach (arg; *args)
-    {
-        sc = sc.startCTFE();
-        auto e = arg.expressionSemantic(sc);
-        e = resolveProperties(sc, e);
-        sc = sc.endCTFE();
 
-        // pragma(msg) is allowed to contain types as well as expressions
-        e = ctfeInterpretForPragmaMsg(e);
-        if (e.op == EXP.error)
-        {
-            errorSupplemental(loc, "while evaluating `pragma(msg, %s)`", arg.toChars());
-            return false;
-        }
-        if (auto se = e.toStringExp())
-        {
-            const slice = se.toUTF8(sc).peekString();
-            fprintf(stderr, "%.*s", cast(int)slice.length, slice.ptr);
-        }
-        else
-            fprintf(stderr, "%s", e.toChars());
+    OutBuffer buf;
+    if (expressionsToString(buf, sc, args, loc, "while evaluating `pragma(msg, %s)`", false))
+        return false;
+    else
+    {
+        buf.writestring("\n");
+        fprintf(stderr, buf.extractChars);
     }
-    fprintf(stderr, "\n");
     return true;
 }
 
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index fb9a18b2892d05c3c66e6d774119523445f3abbb..a2f074dbfaec0167c19a52a091cfcb6cdf46ee07 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -277,7 +277,7 @@ nothrow:
      * Returns:
      *  the slice
      */
-    extern (D) static const(char)[] sansExt(const char[] filename)
+    extern (D) static const(char)[] sansExt(const char[] filename) @safe
     {
         auto e = ext(filename);
         size_t length = e.length;
@@ -1101,7 +1101,7 @@ nothrow:
         return str.ptr;
     }
 
-    const(char)[] toString() const pure nothrow @nogc @trusted
+    const(char)[] toString() const pure nothrow @nogc @safe
     {
         return str;
     }
diff --git a/gcc/d/dmd/root/string.d b/gcc/d/dmd/root/string.d
index 4b4c3e1f6457fb99bee41afb1d4c3329509a86e2..383c59de01362fbfc8e65e9d28b3e0336052e265 100644
--- a/gcc/d/dmd/root/string.d
+++ b/gcc/d/dmd/root/string.d
@@ -20,6 +20,27 @@ inout(char)[] toDString (inout(char)* s) pure nothrow @nogc
     return s ? s[0 .. strlen(s)] : null;
 }
 
+private struct FTuple(T...)
+{
+    T expand;
+}
+
+/// Returns: a (length, ptr) tuple for passing a D string to `printf`-style functions with the format string `%.*s`
+auto fTuple(const(char)[] str)
+{
+    return FTuple!(int, const(char)*)(cast(int) str.length, str.ptr);
+}
+
+///
+unittest
+{
+    import core.stdc.stdio: snprintf;
+    char[6] buf = '.';
+    const(char)[] str = "cutoff"[0..4];
+    snprintf(buf.ptr, buf.length, "%.*s", str.fTuple.expand);
+    assert(buf[] == "cuto\0.");
+}
+
 /**
 Compare two slices for equality, in a case-insensitive way
 
@@ -433,7 +454,7 @@ Returns:
    a `FindSplit` object that casts to `true` iff `needle` was found inside `str`.
    In that case, `split[1]` is the needle, and `split[0]`/`split[2]` are before/after the needle.
 */
-FindSplit findSplit(return scope const(char)[] str, scope const(char)[] needle)
+FindSplit findSplit(return scope const(char)[] str, scope const(char)[] needle) @safe
 {
     if (needle.length > str.length)
         return FindSplit([str, null, null]);
@@ -469,7 +490,7 @@ Params:
 Returns:
    substring of `str` inbetween `l` and `r`
 */
-const(char)[] findBetween(const(char)[] str, const(char)[] l, const(char)[] r)
+const(char)[] findBetween(const(char)[] str, const(char)[] l, const(char)[] r) @safe
 {
     if (auto s0 = str.findSplit(l))
         if (auto s1 = s0[2].findSplit(r))
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 34cab8008683bcac2c2cb2bc63c6977fcba47fc7..24d87458551655a2595f0b68f2a3117e49aa19c7 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -21,14 +21,20 @@ import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dscope;
+import dmd.dsymbolsem : determineSize;
+import dmd.errors;
 import dmd.expression;
+import dmd.func;
+import dmd.funcsem : isRootTraitsCompilesScope;
+import dmd.globals : FeatureState;
 import dmd.id;
 import dmd.identifier;
+import dmd.location;
 import dmd.mtype;
+import dmd.rootobject;
 import dmd.target;
 import dmd.tokens;
 import dmd.typesem : hasPointers, arrayOf, size;
-import dmd.funcsem : setUnsafe, setUnsafePreview;
 
 /*************************************************************
  * Check for unsafe access in @safe code:
@@ -309,3 +315,183 @@ bool checkUnsafeDotExp(Scope* sc, Expression e, Identifier id, int flag)
     }
     return false;
 }
+
+bool isSafe(FuncDeclaration fd)
+{
+    if (fd.safetyInprocess)
+        fd.setUnsafe();
+    return fd.type.toTypeFunction().trust == TRUST.safe;
+}
+
+extern (D) bool isSafeBypassingInference(FuncDeclaration fd)
+{
+    return !(fd.safetyInprocess) && fd.isSafe();
+}
+
+bool isTrusted(FuncDeclaration fd)
+{
+    if (fd.safetyInprocess)
+        fd.setUnsafe();
+    return fd.type.toTypeFunction().trust == TRUST.trusted;
+}
+
+/**************************************
+ * The function is doing something unsafe, so mark it as 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
+ *   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)
+{
+    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() : "");
+
+        return true;
+    }
+    return false;
+}
+
+/**************************************
+ * The function is calling `@system` function `f`, so mark it as unsafe.
+ *
+ * Params:
+ *   fd = caller
+ *   f = function being called (needed for diagnostic of inferred functions)
+ * Returns: whether there's a safe error
+ */
+extern (D) bool setUnsafeCall(FuncDeclaration fd, FuncDeclaration f)
+{
+    return fd.setUnsafe(false, f.loc, null, f, null);
+}
+
+/**************************************
+ * A statement / expression in this scope is not `@safe`,
+ * so mark the enclosing function as `@system`
+ *
+ * Params:
+ *   sc = scope that the unsafe statement / expression is in
+ *   gag = surpress error message (used in escape.d)
+ *   loc = location of error
+ *   fmt = printf-style format string
+ *   arg0  = (optional) argument for first %s format specifier
+ *   arg1  = (optional) argument for second %s format specifier
+ *   arg2  = (optional) argument for third %s format specifier
+ * Returns: whether there's a safe error
+ */
+bool setUnsafe(Scope* sc,
+    bool gag = false, Loc loc = Loc.init, const(char)* fmt = null,
+    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+{
+    if (sc.intypeof)
+        return false; // typeof(cast(int*)0) is safe
+
+    if (sc.debug_) // debug {} scopes are permissive
+        return false;
+
+    if (!sc.func)
+    {
+        if (sc.varDecl)
+        {
+            if (sc.varDecl.storage_class & STC.safe)
+            {
+                .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+                return true;
+            }
+            else if (!(sc.varDecl.storage_class & STC.trusted))
+            {
+                sc.varDecl.storage_class |= STC.system;
+                sc.varDecl.systemInferred = true;
+            }
+        }
+        return false;
+    }
+
+
+    if (isRootTraitsCompilesScope(sc)) // __traits(compiles, x)
+    {
+        if (sc.func.isSafeBypassingInference())
+        {
+            // Message wil be gagged, but still call error() to update global.errors and for
+            // -verrors=spec
+            .error(loc, fmt, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+            return true;
+        }
+        return false;
+    }
+
+    return sc.func.setUnsafe(gag, loc, fmt, arg0, arg1, arg2);
+}
+
+/***************************************
+ * Like `setUnsafe`, but for safety errors still behind preview switches
+ *
+ * Given a `FeatureState fs`, for example dip1000 / dip25 / systemVariables,
+ * the behavior changes based on the setting:
+ *
+ * - In case of `-revert=fs`, it does nothing.
+ * - In case of `-preview=fs`, it's the same as `setUnsafe`
+ * - By default, print a deprecation in `@safe` functions, or store an attribute violation in inferred functions.
+ *
+ * Params:
+ *   sc = used to find affected function/variable, and for checking whether we are in a deprecated / speculative scope
+ *   fs = feature state from the preview flag
+ *   gag = surpress error message
+ *   loc = location of error
+ *   msg = 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,
+    RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
+{
+    //printf("setUnsafePreview() fs:%d %s\n", fs, msg);
+    with (FeatureState) final switch (fs)
+    {
+      case disabled:
+        return false;
+
+      case enabled:
+        return sc.setUnsafe(gag, loc, msg, arg0, arg1, arg2);
+
+      case default_:
+        if (!sc.func)
+            return false;
+        if (sc.func.isSafeBypassingInference())
+        {
+            if (!gag && !sc.isDeprecated())
+            {
+                deprecation(loc, msg, 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);
+        }
+        return false;
+    }
+}
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index fb7373c73f7bd7d2848a1f6b61046f2c35e54fd7..31fc418dbcc32b9e44dcfd257fab8bf7ee88fc28 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -146,11 +146,9 @@ private extern(C++) final class Semantic2Visitor : Visitor
         sc.tinst = tempinst;
         sc.minst = tempinst.minst;
 
-        int needGagging = (tempinst.gagged && !global.gag);
-        uint olderrors = global.errors;
-        int oldGaggedErrors = -1; // dead-store to prevent spurious warning
-        if (needGagging)
-            oldGaggedErrors = global.startGagging();
+        const needGagging = (tempinst.gagged && !global.gag);
+        const olderrors = global.errors;
+        const oldGaggedErrors = needGagging ? global.startGagging() : -1;
 
         for (size_t i = 0; i < tempinst.members.length; i++)
         {
@@ -230,7 +228,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
             return;
         }
 
-        UserAttributeDeclaration.checkGNUABITag(vd, vd._linkage);
+        checkGNUABITag(vd, vd._linkage);
 
         if (vd._init && !vd.toParent().isFuncDeclaration())
         {
@@ -471,7 +469,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
             return;
         TypeFunction f = cast(TypeFunction) fd.type;
 
-        UserAttributeDeclaration.checkGNUABITag(fd, fd._linkage);
+        checkGNUABITag(fd, fd._linkage);
         //semantic for parameters' UDAs
         foreach (i, param; f.parameterList)
         {
@@ -505,7 +503,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
             printf("+Nspace::semantic2('%s')\n", ns.toChars());
             scope(exit) printf("-Nspace::semantic2('%s')\n", ns.toChars());
         }
-        UserAttributeDeclaration.checkGNUABITag(ns, LINK.cpp);
+        checkGNUABITag(ns, LINK.cpp);
         if (!ns.members)
             return;
 
@@ -563,7 +561,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
 
     override void visit(CPPNamespaceDeclaration decl)
     {
-        UserAttributeDeclaration.checkGNUABITag(decl, LINK.cpp);
+        checkGNUABITag(decl, LINK.cpp);
         visit(cast(AttribDeclaration)decl);
     }
 
@@ -590,7 +588,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
                 }
 
                 // Handles compiler-recognized `core.attribute.gnuAbiTag`
-                if (UserAttributeDeclaration.isGNUABITag(e))
+                if (isGNUABITag(e))
                     doGNUABITagSemantic(e, lastTag);
             }
         }
@@ -612,8 +610,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
             return;
         }
 
-        UserAttributeDeclaration.checkGNUABITag(
-            ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
+        checkGNUABITag(ad, ad.classKind == ClassKind.cpp ? LINK.cpp : LINK.d);
 
         auto sc2 = ad.newScope(sc);
 
@@ -720,8 +717,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
  */
 private void doGNUABITagSemantic(ref Expression e, ref Expression* lastTag)
 {
-    import dmd.dmangle;
-
+    import dmd.mangle : isValidMangling;
     // When `@gnuAbiTag` is used, the type will be the UDA, not the struct literal
     if (e.op == EXP.type)
     {
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 24bdd449d5eee68221638c79093934a2a78532f3..4f10982a2d1cfd524a87a1e79090eece335cde15 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -120,15 +120,13 @@ private extern(C++) final class Semantic3Visitor : Visitor
         sc.minst = tempinst.minst;
 
         bool needGagging = tempinst.gagged && !global.gag;
-        uint olderrors = global.errors;
-        int oldGaggedErrors = -1; // dead-store to prevent spurious warning
+        const olderrors = global.errors;
+        const oldGaggedErrors = needGagging ? global.startGagging() : -1;
         /* If this is a gagged instantiation, gag errors.
          * Future optimisation: If the results are actually needed, errors
          * would already be gagged, so we don't really need to run semantic
          * on the members.
          */
-        if (needGagging)
-            oldGaggedErrors = global.startGagging();
 
         for (size_t i = 0; i < tempinst.members.length; i++)
         {
@@ -171,7 +169,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
         sc = sc.push(tmix.argsym);
         sc = sc.push(tmix);
 
-        uint olderrors = global.errors;
+        const olderrors = global.errors;
 
         for (size_t i = 0; i < tmix.members.length; i++)
         {
@@ -280,7 +278,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                  * For generated opAssign function, any errors
                  * from its body need to be gagged.
                  */
-                uint oldErrors = global.startGagging();
+                const oldErrors = global.startGagging();
                 ++funcdecl.inuse;
                 funcdecl.semantic3(sc);
                 --funcdecl.inuse;
@@ -313,7 +311,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
             return;
         }
 
-        uint oldErrors = global.errors;
+        const oldErrors = global.errors;
         auto fds = FuncDeclSem3(funcdecl,sc);
 
         fds.checkInContractOverrides();
@@ -799,7 +797,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
                         Statement s = new ReturnStatement(funcdecl.loc, null);
                         s = s.statementSemantic(sc2);
                         funcdecl.fbody = new CompoundStatement(funcdecl.loc, funcdecl.fbody, s);
-                        funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+                        funcdecl.hasMultipleReturnExp = funcdecl.hasReturnExp;
+                        funcdecl.hasReturnExp = true;
                     }
                 }
                 else if (funcdecl.fes)
@@ -810,7 +809,8 @@ private extern(C++) final class Semantic3Visitor : Visitor
                         Expression e = IntegerExp.literal!0;
                         Statement s = new ReturnStatement(Loc.initial, e);
                         funcdecl.fbody = new CompoundStatement(Loc.initial, funcdecl.fbody, s);
-                        funcdecl.hasReturnExp |= (funcdecl.hasReturnExp & 1 ? 16 : 1);
+                        funcdecl.hasMultipleReturnExp = funcdecl.hasReturnExp;
+                        funcdecl.hasReturnExp = true;
                     }
                     assert(!funcdecl.returnLabel);
                 }
@@ -825,8 +825,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
                 }
                 else
                 {
-                    const(bool) inlineAsm = (funcdecl.hasReturnExp & 8) != 0;
-                    if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm && !sc.inCfile)
+                    if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !funcdecl.hasInlineAsm && !sc.inCfile)
                     {
                         if (!funcdecl.hasReturnExp)
                             .error(funcdecl.loc, "%s `%s` has no `return` statement, but is expected to return a value of type `%s`", funcdecl.kind, funcdecl.toPrettyChars, f.next.toChars());
@@ -1177,32 +1176,31 @@ private extern(C++) final class Semantic3Visitor : Visitor
                     {
                         if (v.isReference() || (v.storage_class & STC.lazy_))
                             continue;
-                        if (v.needsScopeDtor())
-                        {
-                            v.storage_class |= STC.nodtor;
-                            if (!paramsNeedDtor)
-                                continue;
-
-                            // same with ExpStatement.scopeCode()
-                            Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
+                        if (!v.needsScopeDtor())
+                            continue;
+                        v.storage_class |= STC.nodtor;
+                        if (!paramsNeedDtor)
+                            continue;
 
-                            s = s.statementSemantic(sc2);
+                        // same with ExpStatement.scopeCode()
+                        Statement s = new DtorExpStatement(Loc.initial, v.edtor, v);
 
-                            const blockexit = s.blockExit(funcdecl, isNothrow ? global.errorSink : null);
-                            if (blockexit & BE.throw_)
-                            {
-                                funcdecl.hasNoEH = false;
-                                if (isNothrow)
-                                    error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
-                                else if (funcdecl.nothrowInprocess)
-                                    f.isNothrow = false;
-                            }
+                        s = s.statementSemantic(sc2);
 
-                            if (sbody.blockExit(funcdecl, f.isNothrow ? global.errorSink : null) == BE.fallthru)
-                                sbody = new CompoundStatement(Loc.initial, sbody, s);
-                            else
-                                sbody = new TryFinallyStatement(Loc.initial, sbody, s);
+                        const blockexit = s.blockExit(funcdecl, isNothrow ? global.errorSink : null);
+                        if (blockexit & BE.throw_)
+                        {
+                            funcdecl.hasNoEH = false;
+                            if (isNothrow)
+                                error(funcdecl.loc, "%s `%s` may throw but is marked as `nothrow`", funcdecl.kind(), funcdecl.toPrettyChars());
+                            else if (funcdecl.nothrowInprocess)
+                                f.isNothrow = false;
                         }
+
+                        if (sbody.blockExit(funcdecl, f.isNothrow ? global.errorSink : null) == BE.fallthru)
+                            sbody = new CompoundStatement(Loc.initial, sbody, s);
+                        else
+                            sbody = new TryFinallyStatement(Loc.initial, sbody, s);
                     }
                 }
                 // from this point on all possible 'throwers' are checked
@@ -1640,7 +1638,7 @@ void semanticTypeInfoMembers(StructDeclaration sd)
         sd.xeq._scope &&
         sd.xeq.semanticRun < PASS.semantic3done)
     {
-        uint errors = global.startGagging();
+        const errors = global.startGagging();
         sd.xeq.semantic3(sd.xeq._scope);
         if (global.endGagging(errors))
             sd.xeq = sd.xerreq;
@@ -1650,7 +1648,7 @@ void semanticTypeInfoMembers(StructDeclaration sd)
         sd.xcmp._scope &&
         sd.xcmp.semanticRun < PASS.semantic3done)
     {
-        uint errors = global.startGagging();
+        const errors = global.startGagging();
         sd.xcmp.semantic3(sd.xcmp._scope);
         if (global.endGagging(errors))
             sd.xcmp = sd.xerrcmp;
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index b53c3d085b9d7aa091632cd92b6fd193ef707c30..5c759b088f5d6edc0fccef336ba0b93aa7ba9dea 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -19,7 +19,6 @@ import core.stdc.stdio;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
-import dmd.errors;
 import dmd.cond;
 import dmd.declaration;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 9d988f08d12531cb89632f7be5095997e192c772..c584b846489060fa8287f9dfa167acb47043b982 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -57,6 +57,7 @@ import dmd.opover;
 import dmd.parse;
 import dmd.common.outbuffer;
 import dmd.root.string;
+import dmd.safe : isSafe, setUnsafe;
 import dmd.semantic2;
 import dmd.sideeffect;
 import dmd.statement;
@@ -2514,7 +2515,8 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
         }
         else if (rs.exp)
         {
-            fd.hasReturnExp |= (fd.hasReturnExp & 1 ? 16 : 1);
+            fd.hasMultipleReturnExp = fd.hasReturnExp;
+            fd.hasReturnExp = true;
 
             FuncLiteralDeclaration fld = fd.isFuncLiteralDeclaration();
             if (tret)
@@ -3685,9 +3687,6 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
         return false;
     }
 
-    if (FuncDeclaration fd = sc.parent.isFuncDeclaration())
-        fd.hasReturnExp |= 2;
-
     if (auto ne = exp.isNewExp())
     {
         ne.thrownew = true;
@@ -4802,7 +4801,7 @@ private Statements* flatten(Statement statement, Scope* sc)
 
 
             OutBuffer buf;
-            if (expressionsToString(buf, sc, cs.exps))
+            if (expressionsToString(buf, sc, cs.exps, cs.loc, null, true))
                 return errorStatements();
 
             const errors = global.errors;
@@ -4812,7 +4811,6 @@ private Statements* flatten(Statement statement, Scope* sc)
             const bool doUnittests = global.params.parsingUnittestsRequired();
             auto loc = adjustLocForMixin(str, cs.loc, global.params.mixinOut);
             scope p = new Parser!ASTCodegen(loc, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
-            p.transitionIn = global.params.v.vin;
             p.nextToken();
 
             auto a = new Statements();
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index cc44b6c0c3b7e118fbc845cb661c16df58b2e486..77187105c516706b409f41d6f192683f9ff86ab4 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -301,6 +301,8 @@ extern (C++) struct Target
  */
 struct TargetC
 {
+    import dmd.declaration : BitFieldDeclaration;
+
     enum Runtime : ubyte
     {
         Unspecified,
@@ -331,6 +333,14 @@ struct TargetC
     ubyte wchar_tsize;        /// size of a C `wchar_t` type
     Runtime runtime;          /// vendor of the C runtime to link against
     BitFieldStyle bitFieldStyle; /// different C compilers do it differently
+
+    /**
+     * Indicates whether the specified bit-field contributes to the alignment
+     * of the containing aggregate.
+     * E.g., (not all) ARM ABIs do NOT ignore anonymous (incl. 0-length)
+     * bit-fields.
+     */
+    extern (C++) bool contributesToAggregateAlignment(BitFieldDeclaration bfd);
 }
 
 ////////////////////////////////////////////////////////////////////////////////
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index 2284b8322e7bb0e8d5c530133a659cdadbe51f34..1a9837ff4c70cf24b531b530d642cc89c2c7a789 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -16,6 +16,7 @@
 #include "globals.h"
 #include "tokens.h"
 
+class BitFieldDeclaration;
 class ClassDeclaration;
 class Dsymbol;
 class Expression;
@@ -77,6 +78,8 @@ struct TargetC
     uint8_t wchar_tsize;         // size of a C 'wchar_t' type
     Runtime runtime;
     BitFieldStyle bitFieldStyle; // different C compilers do it differently
+
+    bool contributesToAggregateAlignment(BitFieldDeclaration *bfd);
 };
 
 struct TargetCPP
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index bccec1a68c128ff7222ef69677ff86735d7e7160..e751eadb5aeb7066c77b9045b732e19e0eaa171d 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -133,9 +133,6 @@ public:
 
     DYNCAST dyncast() const override { return DYNCAST_TEMPLATEPARAMETER; }
 
-    /* Create dummy argument based on parameter.
-     */
-    virtual RootObject *dummyArg() = 0;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -155,7 +152,6 @@ public:
     RootObject *specialization() override final;
     RootObject *defaultArg(const Loc &instLoc, Scope *sc) override final;
     bool hasDefaultArg() override final;
-    RootObject *dummyArg() override final;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -187,7 +183,6 @@ public:
     RootObject *specialization() override;
     RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
     bool hasDefaultArg() override;
-    RootObject *dummyArg() override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -208,7 +203,6 @@ public:
     RootObject *specialization() override;
     RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
     bool hasDefaultArg() override;
-    RootObject *dummyArg() override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -225,7 +219,6 @@ public:
     RootObject *specialization() override;
     RootObject *defaultArg(const Loc &instLoc, Scope *sc) override;
     bool hasDefaultArg() override;
-    RootObject *dummyArg() override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d
index 21b10bee7c94f44699dccf394062fdd98013bb74..bd3674a8cc8260b39c46ce0e7b54bc04ca3da070 100644
--- a/gcc/d/dmd/templatesem.d
+++ b/gcc/d/dmd/templatesem.d
@@ -23,7 +23,6 @@ import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
@@ -109,7 +108,7 @@ void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl)
     tempdecl.isstatic = tempdecl.toParent().isModule() || (tempdecl._scope.stc & STC.static_);
     tempdecl.deprecated_ = !!(sc.stc & STC.deprecated_);
 
-    UserAttributeDeclaration.checkGNUABITag(tempdecl, sc.linkage);
+    checkGNUABITag(tempdecl, sc.linkage);
 
     if (!tempdecl.isstatic)
     {
@@ -354,7 +353,7 @@ MATCH matchWithInstance(Scope* sc, TemplateDeclaration td, TemplateInstance ti,
 
             // Resolve parameter types and 'auto ref's.
             tf.inferenceArguments = argumentList;
-            uint olderrors = global.startGagging();
+            const olderrors = global.startGagging();
             fd.type = tf.typeSemantic(td.loc, paramscope);
             global.endGagging(olderrors);
             if (fd.type.ty != Tfunction)
@@ -1422,7 +1421,7 @@ extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
                             Dsymbol s;
                             Scope *sco;
 
-                            uint errors = global.startGagging();
+                            const errors = global.startGagging();
                             /* ref: https://issues.dlang.org/show_bug.cgi?id=11118
                              * The parameter isn't part of the template
                              * ones, let's try to find it in the
@@ -2429,3 +2428,70 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
         m.last = MATCH.nomatch;
     }
 }
+/* Create dummy argument based on parameter.
+ */
+private RootObject dummyArg(TemplateParameter tp)
+{
+    scope v = new DummyArgVisitor();
+    tp.accept(v);
+    return v.result;
+}
+private extern(C++) class DummyArgVisitor : Visitor
+{
+    RootObject result;
+
+    alias visit = typeof(super).visit;
+    override void visit(TemplateTypeParameter ttp)
+    {
+        Type t = ttp.specType;
+        if (t)
+        {
+            result = t;
+            return;
+        }
+        // Use this for alias-parameter's too (?)
+        if (!ttp.tdummy)
+            ttp.tdummy = new TypeIdentifier(ttp.loc, ttp.ident);
+        result = ttp.tdummy;
+    }
+
+    override void visit(TemplateValueParameter tvp)
+    {
+        Expression e = tvp.specValue;
+        if (e)
+        {
+            result = e;
+            return;
+        }
+
+        // Create a dummy value
+        auto pe = cast(void*)tvp.valType in tvp.edummies;
+        if (pe)
+        {
+            result = *pe;
+            return;
+        }
+
+        e = tvp.valType.defaultInit(Loc.initial);
+        tvp.edummies[cast(void*)tvp.valType] = e;
+        result = e;
+    }
+
+    override void visit(TemplateAliasParameter tap)
+    {
+        RootObject s = tap.specAlias;
+        if (s)
+        {
+            result = s;
+            return;
+        }
+        if (!tap.sdummy)
+            tap.sdummy = new Dsymbol();
+        result = tap.sdummy;
+    }
+
+    override void visit(TemplateTupleParameter tap)
+    {
+        result = null;
+    }
+}
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 1e7386147b1df8ad6e53799b97cd35f0c631d382..7b32209fd2ef7fecdb69de99968823113dd64119 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -26,7 +26,6 @@ import dmd.dclass;
 import dmd.declaration;
 import dmd.dimport;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
@@ -43,6 +42,7 @@ import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
+import dmd.mangle : decoToType;
 import dmd.mtype;
 import dmd.nogc;
 import dmd.optimize;
@@ -1038,7 +1038,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
                  e.ident == Id.getVirtualMethods ||
                  e.ident == Id.getOverloads)
         {
-            uint errors = global.errors;
+            const errors = global.errors;
             Expression eorig = ex;
             ex = ex.expressionSemantic(scx);
             if (errors < global.errors)
@@ -1746,7 +1746,7 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
 
         foreach (o; *e.args)
         {
-            uint errors = global.startGagging();
+            const errors = global.startGagging();
             Scope* sc2 = sc.push();
             sc2.tinst = null;
             sc2.minst = null;   // this is why code for these are not emitted to object file
@@ -1991,9 +1991,9 @@ Expression semanticTraits(TraitsExp e, Scope* sc)
             return dimError(1);
         auto arg0 = (*e.args)[0];
         Dsymbol s = getDsymbolWithoutExpCtx(arg0);
-        if (!s || !s.loc.isValid())
+        if (!s || !s.loc.isValid() || s.isModule())
         {
-            error(e.loc, "can only get the location of a symbol, not `%s`", arg0.toChars());
+            error(e.loc, "can only get the location of a symbol, not `%s`", s ? s.toPrettyChars() : arg0.toChars());
             return ErrorExp.get();
         }
 
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index a35a6eba73f713c7d1c0d9770ebee9bf1bcc856a..eebbf45573dc32c15ae3712d645569a0c5d6a4e0 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -28,7 +28,6 @@ import dmd.declaration;
 import dmd.denum;
 import dmd.dimport;
 import dmd.dinterpret;
-import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dstruct;
@@ -53,6 +52,7 @@ import dmd.initsem;
 import dmd.location;
 import dmd.visitor;
 import dmd.mtype;
+import dmd.mangle;
 import dmd.nogc;
 import dmd.objc;
 import dmd.opover;
@@ -230,7 +230,7 @@ private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
         }
 
         Type t = s.getType(); // type symbol, type alias, or type tuple?
-        uint errorsave = global.errors;
+        const errorsave = global.errors;
         SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
 
         Dsymbol sm = s.searchX(loc, sc, id, flags);
@@ -836,7 +836,9 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
         L1:
             if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
             {
-                auto trailingArgs = args[u .. $];
+                Expression[] trailingArgs;
+                if (args.length >= u)
+                    trailingArgs = args[u .. $];
                 if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
                     return vmatch < match ? vmatch : match;
                 // Error message was already generated in `matchTypeSafeVarArgs`
@@ -905,25 +907,19 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
      */
     OutBuffer buf;
     auto callExp = e.isCallExp();
-    void nocpctor()
+
+    bool nocpctor()
     {
         buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
                    argStruct.toChars(), arg.type.toChars(), tprm.toChars());
-    }
-    auto f = callExp.f;
-    if (!f)
-    {
-        nocpctor();
         *pMessage = buf.extractChars();
         return false;
     }
-    char[] s;
-    if (!f.isPure && sc.func.setImpure())
-        s ~= "pure ";
-    if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
-        s ~= "@safe ";
-    if (!f.isNogc && sc.func.setGC(arg.loc, null))
-        s ~= "nogc ";
+
+    auto f = callExp.f;
+    if (!f)
+        return nocpctor();
+
     if (f.isDisabled() && !f.isGenerated())
     {
         /* https://issues.dlang.org/show_bug.cgi?id=24301
@@ -931,11 +927,21 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
          */
         buf.printf("`%s` copy constructor cannot be used because it is annotated with `@disable`",
             f.type.toChars());
+        *pMessage = buf.extractChars();
+        return false;
     }
-    else if (s)
+
+    bool bpure = !f.isPure && sc.func.setImpure();
+    bool bsafe = !f.isSafe() && !f.isTrusted() && sc.setUnsafe();
+    bool bnogc = !f.isNogc && sc.func.setGC(arg.loc, null);
+    if (bpure | bsafe | bnogc)
     {
-        s[$-1] = '\0';
-        buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+        const nullptr = "".ptr;
+        buf.printf("`%s` copy constructor cannot be called from a `%s%s%s` context",
+            f.type.toChars(),
+            bpure ? "pure " .ptr : nullptr,
+            bsafe ? "@safe ".ptr : nullptr,
+            bnogc ? "nogc"  .ptr : nullptr);
     }
     else if (f.isGenerated() && f.isDisabled())
     {
@@ -951,7 +957,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
          * i.e: `inout` constructor creates `const` object, not mutable.
          * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
          */
-        nocpctor();
+        return nocpctor();
     }
 
     *pMessage = buf.extractChars();
@@ -2706,23 +2712,21 @@ Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 which isn't a particularly good error message (x is a variable?).
             */
             Dsymbol varDecl = mtype.toDsymbol(sc);
-            const(Loc) varDeclLoc = varDecl.getLoc();
             Module varDeclModule = varDecl.getModule(); //This can be null
 
             .error(loc, "variable `%s` is used as a type", mtype.toChars());
             //Check for null to avoid https://issues.dlang.org/show_bug.cgi?id=22574
             if ((varDeclModule !is null) && varDeclModule != sc._module) // variable is imported
             {
-                const(Loc) varDeclModuleImportLoc = varDeclModule.getLoc();
                 .errorSupplemental(
-                    varDeclModuleImportLoc,
+                    varDeclModule.loc,
                     "variable `%s` is imported here from: `%s`",
                     varDecl.toChars,
                     varDeclModule.toPrettyChars,
                 );
             }
 
-            .errorSupplemental(varDeclLoc, "variable `%s` is declared here", varDecl.toChars);
+            .errorSupplemental(varDecl.loc, "variable `%s` is declared here", varDecl.toChars);
         }
         else
             .error(loc, "`%s` is used as a type", mtype.toChars());
@@ -4921,7 +4925,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
                  * e.g.
                  *  template opDispatch(name) if (isValid!name) { ... }
                  */
-                uint errors = gagError ? global.startGagging() : 0;
+                const errors = gagError ? global.startGagging() : 0;
                 e = dti.dotTemplateSemanticProp(sc, DotExpFlag.none);
                 if (gagError && global.endGagging(errors))
                     e = null;
@@ -4939,7 +4943,7 @@ Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
                  */
                 auto die = new DotIdExp(e.loc, alias_e, ident);
 
-                auto errors = gagError ? 0 : global.startGagging();
+                const errors = gagError ? 0 : global.startGagging();
                 auto exp = die.dotIdSemanticProp(sc, gagError);
                 if (!gagError)
                 {
@@ -7479,6 +7483,62 @@ MATCH implicitConvToThroughAliasThis(TypeStruct from, Type to)
     return MATCH.nomatch;
 }
 
+/*******************************************
+ * Compute number of elements for a (possibly multidimensional) static array,
+ * or 1 for other types.
+ * Params:
+ *  t = static array type
+ *  loc = for error message
+ * Returns:
+ *  number of elements, uint.max on overflow
+ */
+uint numberOfElems(Type t, const ref Loc loc)
+{
+    //printf("Type::numberOfElems()\n");
+    uinteger_t n = 1;
+    Type tb = t;
+    while ((tb = tb.toBasetype()).ty == Tsarray)
+    {
+        bool overflow = false;
+        n = mulu(n, (cast(TypeSArray)tb).dim.toUInteger(), overflow);
+        if (overflow || n >= uint.max)
+        {
+            error(loc, "static array `%s` size overflowed to %llu", t.toChars(), cast(ulong)n);
+            return uint.max;
+        }
+        tb = (cast(TypeSArray)tb).next;
+    }
+    return cast(uint)n;
+}
+
+bool checkRetType(TypeFunction tf, const ref Loc loc)
+{
+    Type tb = tf.next.toBasetype();
+    if (tb.ty == Tfunction)
+    {
+        error(loc, "functions cannot return a function");
+        tf.next = Type.terror;
+    }
+    if (tb.ty == Ttuple)
+    {
+        error(loc, "functions cannot return a sequence (use `std.typecons.Tuple`)");
+        tf.next = Type.terror;
+    }
+    if (!tf.isRef && (tb.ty == Tstruct || tb.ty == Tsarray))
+    {
+        if (auto ts = tb.baseElemOf().isTypeStruct())
+        {
+            if (!ts.sym.members)
+            {
+                error(loc, "functions cannot return opaque type `%s` by value", tb.toChars());
+                tf.next = Type.terror;
+            }
+        }
+    }
+    if (tb.ty == Terror)
+        return true;
+    return false;
+}
 
 
 /******************************* Private *****************************************/
@@ -7793,7 +7853,7 @@ Expression getMaxMinValue(EnumDeclaration ed, const ref Loc loc, Identifier id)
 RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
 {
     OutBuffer buf;
-    if (expressionsToString(buf, sc, tm.exps))
+    if (expressionsToString(buf, sc, tm.exps, tm.loc, null, true))
         return null;
 
     const errors = global.errors;
@@ -7803,7 +7863,6 @@ RootObject compileTypeMixin(TypeMixin tm, ref const Loc loc, Scope* sc)
     const bool doUnittests = global.params.parsingUnittestsRequired();
     auto locm = adjustLocForMixin(str, loc, global.params.mixinOut);
     scope p = new Parser!ASTCodegen(locm, sc._module, str, false, global.errorSink, &global.compileEnv, doUnittests);
-    p.transitionIn = global.params.v.vin;
     p.nextToken();
     //printf("p.loc.linnum = %d\n", p.loc.linnum);
 
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 5d7154a39d99aa01b878c0e4e5326b8e079b020e..ceff41473e42862335b0e340cf5981141a272283 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -104,7 +104,7 @@ bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
  * Returns:
  *      The type of the `TypeInfo` object associated with `t`
  */
-extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc, bool genObjCode = true);
+extern (C++) Type getTypeInfoType(const ref Loc loc, Type t, Scope* sc);
 
 private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
 {
diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h
index dd9572aab42f0afca8bf10a8d350e93157d42e78..6414ecdd36acf4b3effa8e480be1159009d0ecb0 100644
--- a/gcc/d/dmd/typinf.h
+++ b/gcc/d/dmd/typinf.h
@@ -22,4 +22,4 @@ namespace dmd
     bool isSpeculativeType(Type *t);
     bool builtinTypeInfo(Type *t);
 }
-Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true);
+Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index cde029d58674d3962b3f56272ee1f2702f90e235..8b418968dab67554b2e7bdc5b46cdbe4e2423734 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -237,7 +237,7 @@ bool parseDigits(T)(ref T val, const(char)[] p, const T max = T.max)
  *   size = 1 for ubyte[], 2 for ushort[], 4 for uint[], 8 for ulong[]
  * Returns: copy of `data`, with bytes shuffled if compiled for `version(LittleEndian)`
  */
-ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size)
+ubyte[] arrayCastBigEndian(const ubyte[] data, size_t size) @safe
 {
     ubyte[] impl(T)()
     {
diff --git a/gcc/d/dmd/visitor/foreachvar.d b/gcc/d/dmd/visitor/foreachvar.d
index 229ade58d762a35ec55761d1f2fef3f68ccc1b74..4f1f64fb0d7c0fdd115cf9f16712cee6948721a8 100644
--- a/gcc/d/dmd/visitor/foreachvar.d
+++ b/gcc/d/dmd/visitor/foreachvar.d
@@ -24,7 +24,6 @@ import dmd.dstruct;
 import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.dtemplate;
-import dmd.errors;
 import dmd.expression;
 import dmd.func;
 import dmd.id;
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index c0a496af2fe5bf6882d90bf400ba8714ad15dfdd..66cfa2c592962ce3d9e940bf05556c79c6511f54 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -1540,12 +1540,10 @@ get_cpp_typeinfo_decl (ClassDeclaration *decl)
   return decl->cpp_type_info_ptr_sym;
 }
 
-/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it.
-   When GENERATE is true, push the TypeInfo as a member of MOD so that it will
-   get code generation. */
+/* Get the exact TypeInfo for TYPE, if it doesn't exist, create it.  */
 
 void
-create_typeinfo (Type *type, Module *mod, bool generate)
+create_typeinfo (Type *type, Module *mod)
 {
   if (!Type::dtypeinfo)
     create_frontend_tinfo_types ();
@@ -1703,7 +1701,7 @@ create_typeinfo (Type *type, Module *mod, bool generate)
 
       /* If this has a custom implementation in rt/typeinfo, then
 	 do not generate a COMDAT for it.  */
-      if (generate && !builtin_typeinfo_p (t))
+      if (!builtin_typeinfo_p (t))
 	{
 	  /* Find module that will go all the way to an object file.  */
 	  if (mod)
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 4815fbbef4298fa3666dc657a463d68e966810a3..47ef66c258074d2283f3c1fbbfeb3510f0ffcecf 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -481,7 +481,7 @@ layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
       AttribDeclaration *attrib = sym->isAttribDeclaration ();
       if (attrib != NULL)
 	{
-	  Dsymbols *decls = attrib->include (NULL);
+	  Dsymbols *decls = dmd::include (attrib, NULL);
 	  if (decls != NULL)
 	    {
 	      fields += layout_aggregate_members (decls, context, inherited_p);
diff --git a/gcc/testsuite/gdc.test/compilable/compile1.d b/gcc/testsuite/gdc.test/compilable/compile1.d
index 4678eb533864e2f7ade6dc00c8b50fb0a3b2cc81..676108f68cfa51b6e2fc2318f16875211ab098b4 100644
--- a/gcc/testsuite/gdc.test/compilable/compile1.d
+++ b/gcc/testsuite/gdc.test/compilable/compile1.d
@@ -623,6 +623,11 @@ static assert       (__traits(compiles, false && error) == false);
 int f11042a3()() if (__traits(compiles, true  || error) == false) { return 0; }   enum x11042a3 = f11042a3();
 int f11042b3()() if (__traits(compiles, false && error) == false) { return 0; }   enum x11042b3 = f11042b3();
 
+// https://issues.dlang.org/show_bug.cgi?id=24699
+enum T24699(bool cond) = cond;
+enum b24699a = T24699!(true || error);
+enum b24699b = T24699!(false && error);
+
 /***************************************************/
 // https://issues.dlang.org/show_bug.cgi?id=11554
 
diff --git a/gcc/testsuite/gdc.test/compilable/deprecationlimit.d b/gcc/testsuite/gdc.test/compilable/deprecationlimit.d
index dcdc9e118ca56b56f10dc71faaaa154539d54f2d..8ee7ab650fbf8daa885228cdd932351c82a96163 100644
--- a/gcc/testsuite/gdc.test/compilable/deprecationlimit.d
+++ b/gcc/testsuite/gdc.test/compilable/deprecationlimit.d
@@ -18,5 +18,5 @@ void main()
     f();
     f();
     f();
-    f();
+    static assert("1"); // also surpress deprecationSupplemental
 }
diff --git a/gcc/testsuite/gdc.test/compilable/import_exp.d b/gcc/testsuite/gdc.test/compilable/import_exp.d
index 014d0f65f6f9ac626f60b8a32c528cb9d4a0ed8a..d29fc67ed66ec9298cb7e044697ee45fa313f75e 100644
--- a/gcc/testsuite/gdc.test/compilable/import_exp.d
+++ b/gcc/testsuite/gdc.test/compilable/import_exp.d
@@ -34,3 +34,11 @@ enum expectedStart = "module imports.imp16088;";
 immutable ubyte[] s0 = import("imp16088.d");
 
 static assert(s0[0 .. expectedStart.length] == "module imports.imp16088;");
+
+// https://issues.dlang.org/show_bug.cgi?id=24687
+
+void foo(string path);
+void foo(const(ubyte[]) data);
+
+void bar1() { foo(import("imp16088.d")); } // matches both
+void bar2() { foo(cast(const(ubyte[])) import("imp16088.d")); } // matches both!
diff --git a/gcc/testsuite/gdc.test/compilable/imports/vcg_ast_import.d b/gcc/testsuite/gdc.test/compilable/imports/vcg_ast_import.d
new file mode 100644
index 0000000000000000000000000000000000000000..a2064c0d175bfee1636708e22bdf2ccade3edec6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/imports/vcg_ast_import.d
@@ -0,0 +1,4 @@
+struct O
+{
+    invariant() {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/isZeroInit.d b/gcc/testsuite/gdc.test/compilable/isZeroInit.d
index a64420febc0fbfa85329106ab956a9c3c31045b8..342dc07bf0f2b4b0eac7f645af8b2f11ef2ad4ba 100644
--- a/gcc/testsuite/gdc.test/compilable/isZeroInit.d
+++ b/gcc/testsuite/gdc.test/compilable/isZeroInit.d
@@ -78,3 +78,45 @@ static if (is(Vector!(int[4])))
     static assert(__traits(isZeroInit, Holder!(Vector!(int[4]), 0)));
     static assert(!__traits(isZeroInit, Holder!(Vector!(int[4]), 1)));
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=24776
+struct S6 {
+    union {
+        int i1;
+        float f1;
+    }
+}
+static assert(__traits(isZeroInit, S6));
+
+struct S7
+{
+    union {
+        float f2;
+        int i2;
+    }
+}
+static assert(!__traits(isZeroInit, S7));
+
+// https://issues.dlang.org/show_bug.cgi?id=23841
+union U
+{
+    float x = 0;
+    float y;
+}
+static assert(__traits(isZeroInit, U));
+
+union U2
+{
+    float x;
+    int y;
+}
+static assert(!__traits(isZeroInit, U2));
+
+struct S8 {
+    int[0] dummy; // same offset as anon union, but doesn't overlap; should be ignored anyway for zero-init check
+    union {
+        float f; // is the first member of the anon union and must be checked
+        int i;
+    }
+}
+static assert(!__traits(isZeroInit, S8));
diff --git a/gcc/testsuite/gdc.test/compilable/staticforeach.d b/gcc/testsuite/gdc.test/compilable/staticforeach.d
index ce9eb74a1ef0af220973be45ee05de69bd3c4fa2..5b23446f89b8a4885805eb8b990c34db9c3a1e95 100644
--- a/gcc/testsuite/gdc.test/compilable/staticforeach.d
+++ b/gcc/testsuite/gdc.test/compilable/staticforeach.d
@@ -117,8 +117,8 @@ foo2
 T2
 TestStaticForeach2
 issue22007
-1 2 '3'
-2 3 '4'
+1 2 3
+2 3 4
 0 1
 1 2
 2 3
diff --git a/gcc/testsuite/gdc.test/compilable/test24337.d b/gcc/testsuite/gdc.test/compilable/test24337.d
new file mode 100644
index 0000000000000000000000000000000000000000..a31f665f35271ba02ed1a6a0190587f8a71fd95c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test24337.d
@@ -0,0 +1,11 @@
+/*
+TEST_OUTPUT:
+---
+"ab"w x"11223344556677"
+---
+*/
+// https://issues.dlang.org/show_bug.cgi?id=24337
+
+immutable ushort[] y = cast(immutable ushort[]) "ab"w;
+immutable ulong[] z = x"00 11 22 33 44 55 66 77";
+pragma(msg, y, " ", z);
diff --git a/gcc/testsuite/gdc.test/compilable/test24760.d b/gcc/testsuite/gdc.test/compilable/test24760.d
new file mode 100644
index 0000000000000000000000000000000000000000..7c84848a6fe939d3b02e3be5b2f1dad451c72856
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test24760.d
@@ -0,0 +1,4 @@
+// https://issues.dlang.org/show_bug.cgi?id=24760
+
+long f(int e = 0, uint[] optional...) => optional.length;
+long f0() => f(); // compiler segfaults
diff --git a/gcc/testsuite/gdc.test/compilable/vcg-ast.d b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
index 4a7b8bc33c489e3ef9d88a451ef83500caead81c..9197441affea872f75b1560d4270115e5d8b3813 100644
--- a/gcc/testsuite/gdc.test/compilable/vcg-ast.d
+++ b/gcc/testsuite/gdc.test/compilable/vcg-ast.d
@@ -2,6 +2,7 @@
 REQUIRED_ARGS: -vcg-ast -o-
 PERMUTE_ARGS:
 OUTPUT_FILES: compilable/vcg-ast.d.cg
+EXTRA_FILES: imports/vcg_ast_import.d
 TEST_OUTPUT_FILE: extra-files/vcg-ast.d.cg
 */
 
@@ -63,3 +64,14 @@ void main()
 {
     values!wchar_t;
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=24764
+
+import imports.vcg_ast_import;
+
+template imported()
+{
+    import imported = imports.vcg_ast_import;
+}
+
+alias myImport = imported!();
diff --git a/gcc/testsuite/gdc.test/compilable/vcg_ast_compilable.d b/gcc/testsuite/gdc.test/compilable/vcg_ast_compilable.d
new file mode 100644
index 0000000000000000000000000000000000000000..e84846dfbe18ee726b195259f1c6304f39418a42
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/vcg_ast_compilable.d
@@ -0,0 +1,69 @@
+/*
+REQUIRED_ARGS: -vcg-ast -o-
+OUTPUT_FILES: compilable/vcg_ast_compilable.d.cg
+TEST_OUTPUT:
+---
+=== compilable/vcg_ast_compilable.d.cg
+import object;
+auto binaryFun(E)(E b)
+{
+	return 'a' == b;
+}
+void find(Element)(Element needle) if (is(typeof(binaryFun(needle))))
+{
+}
+void find()(string needle)
+{
+}
+void splitter()
+{
+	find(3);
+	find("");
+}
+binaryFun!int
+{
+	auto pure nothrow @nogc @safe bool binaryFun(int b)
+	{
+		return 97 == b;
+	}
+
+}
+find!int
+{
+	pure nothrow @nogc @safe void find(int needle)
+	{
+	}
+
+}
+binaryFun!string
+{
+	auto _error_ binaryFun
+	{
+		__error__
+	}
+
+}
+find!()
+{
+	pure nothrow @nogc @safe void find(string needle)
+	{
+	}
+
+}
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24431
+auto binaryFun(E)(E b)
+{
+    return 'a' == b;
+}
+
+void find(Element)(Element needle) if (is(typeof(binaryFun(needle)))) { }
+void find()(string needle) { }
+
+void splitter()
+{
+    find!int(3);
+    find!()("");
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d b/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d
deleted file mode 100644
index f341675f32814a2713335e27e320e14f0cf3e981..0000000000000000000000000000000000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/failCopyCtor.d
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
-TEST_OUTPUT:
----
-fail_compilation/failCopyCtor.d(10): Error: `struct A` may not define both a rvalue constructor and a copy constructor
-fail_compilation/failCopyCtor.d(12):        rvalue constructor defined here
-fail_compilation/failCopyCtor.d(13):        copy constructor defined here
----
-*/
-
-struct A
-{
-    this(immutable A a) {}
-    this(ref shared A a) immutable {}
-    this(ref A a) {}
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/template_enum_param.d b/gcc/testsuite/gdc.test/fail_compilation/template_enum_param.d
new file mode 100644
index 0000000000000000000000000000000000000000..79fb5e4d8f8547ea83123085e6fd59663d8758d6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/template_enum_param.d
@@ -0,0 +1,17 @@
+/*
+TEST_OUTPUT:
+---
+fail_compilation/template_enum_param.d(15): Error: static assert:  `false` is false
+fail_compilation/template_enum_param.d(17):        instantiated from here: `X!(E.a)`
+---
+*/
+
+enum E
+{
+    a,b,c
+}
+template X(E e)
+{
+    static assert(false);
+}
+alias Y = X!(E.a);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21995.d b/gcc/testsuite/gdc.test/fail_compilation/test21995.d
new file mode 100644
index 0000000000000000000000000000000000000000..a1e0b8319194f46a63ef38dced5d7b966c9552a8
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21995.d
@@ -0,0 +1,11 @@
+/* TEST_OUTPUT:
+---
+fail_compilation/test21995.d(10): Error: max object size 4294967295 exceeded from adding field size 3 + alignment adjustment 1 + field offset 4294967292 when placing field in aggregate
+---
+*/
+struct S
+{
+    ubyte[0x7ffffffe] a;
+    ubyte[0x7ffffffe] b;
+    ubyte[3] c;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
index c5d0579f4a055367b0f07a1b8feeef972908303d..29162144110b01f7f0e120dc5a8654b900260c84 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/trait_loc_err.d
@@ -1,8 +1,9 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/trait_loc_err.d(13): Error: can only get the location of a symbol, not `trait_loc_err`
-fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `stdc`
+fail_compilation/trait_loc_err.d(14): Error: can only get the location of a symbol, not `trait_loc_err`
+fail_compilation/trait_loc_err.d(15): Error: can only get the location of a symbol, not `core.stdc`
+fail_compilation/trait_loc_err.d(16): Error: can only get the location of a symbol, not `core.stdc.stdio`
 ---
 */
 module trait_loc_err;
@@ -12,4 +13,5 @@ void main()
 {
     __traits(getLocation, __traits(parent, main));
     __traits(getLocation, __traits(parent, core.stdc.stdio));
+    __traits(getLocation, core.stdc.stdio);
 }
diff --git a/gcc/testsuite/gdc.test/runnable/ifti.d b/gcc/testsuite/gdc.test/runnable/ifti.d
index 0c94946c8b36861f308247ffe14abe080cf4140a..293b8198d7fb7ecb8dced743619f30a8e3f9d396 100644
--- a/gcc/testsuite/gdc.test/runnable/ifti.d
+++ b/gcc/testsuite/gdc.test/runnable/ifti.d
@@ -72,6 +72,20 @@ class Tst(TST, int v = 2) {
 
 class Y : Tst!(float) {}
 
+// https://issues.dlang.org/show_bug.cgi?id=24731
+void test24731()
+{
+    static int solve(size_t N)(ref double[N+1][N])
+    {
+        return N;
+    }
+
+    double[3][2] m;
+    assert(solve(m) == 2);
+    assert(solve!2(m) == 2);
+}
+
+
 void main() {
     Tst!(int) t = new Tst!(int);
     Y u = new Y;
@@ -113,4 +127,5 @@ void main() {
         printf("%g\n", i);
     }
 
+    test24731();
 }
diff --git a/gcc/testsuite/gdc.test/runnable/test13613.d b/gcc/testsuite/gdc.test/runnable/test13613.d
index ea57df4e9159d5be12ea33844158fdedeea6fae3..1382f00a1780db2b693a1fb795eb250bb829f4c5 100644
--- a/gcc/testsuite/gdc.test/runnable/test13613.d
+++ b/gcc/testsuite/gdc.test/runnable/test13613.d
@@ -4,9 +4,9 @@
 /*
 TEST_OUTPUT:
 ---
-CT x.offsetof = <
 CT y.offsetof = <
 0 > y
+CT x.offsetof = <
 0 > x
 ---
 */
diff --git a/gcc/testsuite/gdc.test/runnable/test23650.d b/gcc/testsuite/gdc.test/runnable/test23650.d
deleted file mode 100644
index 3ce8f5f0759ba6b415aaca8a4472abaf17718a8e..0000000000000000000000000000000000000000
--- a/gcc/testsuite/gdc.test/runnable/test23650.d
+++ /dev/null
@@ -1,13 +0,0 @@
-// https://issues.dlang.org/show_bug.cgi?id=23650
-
-__gshared int x;
-
-void main()
-{
-
-    static assert(__traits(compiles,
-    {
-        struct S { int *p = &x; }
-        auto t = typeid(S);
-    }));
-}
diff --git a/gcc/testsuite/gdc.test/runnable/test24599.d b/gcc/testsuite/gdc.test/runnable/test24599.d
new file mode 100644
index 0000000000000000000000000000000000000000..257773846ebf070793682ffa284ae7a2c6641445
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test24599.d
@@ -0,0 +1,24 @@
+module mod;
+
+struct Variable
+{
+    size_t toHash() const { return 0; }
+}
+
+enum hasInoutConstruction(T) = __traits(compiles, { struct S { T a; } });
+
+struct Algebraic(T)
+{
+    static if (hasInoutConstruction!T)
+    {
+    }
+}
+
+Algebraic!Variable foo();
+
+struct S
+{
+    Variable[] symbols;
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/test24819.d b/gcc/testsuite/gdc.test/runnable/test24819.d
new file mode 100644
index 0000000000000000000000000000000000000000..3ba374bed368eddac00110a65ea25dbefdaabd76
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test24819.d
@@ -0,0 +1,18 @@
+import core.stdc.stdio;
+
+pragma(inline, true)
+double sqrt(double x)
+{
+    static import core.math;
+    return core.math.sqrt(x);
+}
+
+int main()
+{
+    double q = -5.0;
+    double r = q + 1.0;
+    double result = sqrt(-r);
+    //printf("%f\n", result);
+    assert(result == 2);
+    return 0;
+}
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index acb7d98123f83f1bc90324fe0616009d2eaffb88..f660884c3b9590a9f318b1d3025a5c9b36456315 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-4ccb01fde535c7ad6ad4bdae2516c99420751814
+2b89c2909de239bd603d6f36379658fe902667db
 
 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/core/sys/windows/w32api.d b/libphobos/libdruntime/core/sys/windows/w32api.d
index 5a8a59bad463f99c45fa1814f3eaefa93d694dca..a5aa975b20806501bd57b73194be90aa3bfbee00 100644
--- a/libphobos/libdruntime/core/sys/windows/w32api.d
+++ b/libphobos/libdruntime/core/sys/windows/w32api.d
@@ -42,7 +42,7 @@ enum __W32API_MINOR_VERSION = 17;
     // but third-party compilers could use this
     enum uint _WIN32_WINNT = 0x500;
 } else {
-    enum uint _WIN32_WINNT = 0x501;
+    enum uint _WIN32_WINNT = 0x601;
 }
 
 version (IE11) {
diff --git a/libphobos/libdruntime/core/sys/windows/winbase.d b/libphobos/libdruntime/core/sys/windows/winbase.d
index 2e32ba25abf69d2d53c4cd14461a0447b8b7e1cd..a30035c0accc66786f9e12695d72fca48ab24c19 100644
--- a/libphobos/libdruntime/core/sys/windows/winbase.d
+++ b/libphobos/libdruntime/core/sys/windows/winbase.d
@@ -345,6 +345,14 @@ enum DWORD
     SECURITY_SQOS_PRESENT     = 0x00100000,
     SECURITY_VALID_SQOS_FLAGS = 0x001F0000;
 
+// for GetFinalPathNameByHandle()
+enum DWORD
+    VOLUME_NAME_DOS      = 0x0,
+    VOLUME_NAME_GUID     = 0x1,
+    VOLUME_NAME_NT       = 0x2,
+    VOLUME_NAME_NONE     = 0x4,
+    FILE_NAME_NORMALIZED = 0x0,
+    FILE_NAME_OPENED     = 0x8;
 
 // Thread exit code
 enum DWORD STILL_ACTIVE = 0x103;
@@ -1333,6 +1341,51 @@ enum GET_FILEEX_INFO_LEVELS {
     GetFileExMaxInfoLevel
 }
 
+import core.sys.windows.sdkddkver : NTDDI_VERSION, NTDDI_LONGHORN;
+
+static if (NTDDI_VERSION >= NTDDI_LONGHORN)
+{
+    enum FILE_INFO_BY_HANDLE_CLASS
+    {
+        FileBasicInfo,
+        FileStandardInfo,
+        FileNameInfo,
+        FileRenameInfo,
+        FileDispositionInfo,
+        FileAllocationInfo,
+        FileEndOfFileInfo,
+        FileStreamInfo,
+        FileCompressionInfo,
+        FileAttributeTagInfo,
+        FileIdBothDirectoryInfo,
+        FileIdBothDirectoryRestartInfo,
+        FileIoPriorityHintInfo,
+        FileRemoteProtocolInfo,
+        FileFullDirectoryInfo,
+        FileFullDirectoryRestartInfo,
+//        static if (NTDDI_VERSION >= NTDDI_WIN8)
+//        {
+            FileStorageInfo,
+            FileAlignmentInfo,
+            FileIdInfo,
+            FileIdExtdDirectoryInfo,
+            FileIdExtdDirectoryRestartInfo,
+//        }
+//        static if (NTDDI_VERSION >= NTDDI_WIN10_RS1)
+//        {
+            FileDispositionInfoEx,
+            FileRenameInfoEx,
+//        }
+//        static if (NTDDI_VERSION >= NTDDI_WIN10_19H1)
+//        {
+            FileCaseSensitiveInfo,
+            FileNormalizedNameInfo,
+//        }
+        MaximumFileInfoByHandleClass
+    }
+    alias PFILE_INFO_BY_HANDLE_CLASS = FILE_INFO_BY_HANDLE_CLASS*;
+}
+
 struct SYSTEM_INFO {
     union {
         DWORD dwOemId;
@@ -1590,12 +1643,32 @@ static if (_WIN32_WINNT >= 0x410) {
     alias DWORD EXECUTION_STATE;
 }
 
-// CreateSymbolicLink
+// CreateSymbolicLink, GetFileInformationByHandleEx
 static if (_WIN32_WINNT >= 0x600) {
     enum {
         SYMBOLIC_LINK_FLAG_DIRECTORY = 0x1,
         SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE = 0x2
     }
+
+    struct FILE_BASIC_INFO
+    {
+        LARGE_INTEGER CreationTime;
+        LARGE_INTEGER LastAccessTime;
+        LARGE_INTEGER LastWriteTime;
+        LARGE_INTEGER ChangeTime;
+        DWORD FileAttributes;
+    }
+    alias PFILE_BASIC_INFO = FILE_BASIC_INFO*;
+
+    struct FILE_STANDARD_INFO
+    {
+        LARGE_INTEGER AllocationSize;
+        LARGE_INTEGER EndOfFile;
+        DWORD NumberOfLinks;
+        BOOLEAN DeletePending;
+        BOOLEAN Directory;
+    }
+    alias PFILE_STANDARD_INFO = FILE_STANDARD_INFO*;
 }
 
 // Callbacks
@@ -1844,6 +1917,8 @@ WINBASEAPI DWORD WINAPI GetCurrentThreadId(void);
     DWORD GetFileSize(HANDLE, PDWORD);
     BOOL GetFileTime(HANDLE, LPFILETIME, LPFILETIME, LPFILETIME);
     DWORD GetFileType(HANDLE);
+    DWORD GetFinalPathNameByHandleA(HANDLE, LPSTR, DWORD, DWORD);
+    DWORD GetFinalPathNameByHandleW(HANDLE, LPWSTR, DWORD, DWORD);
     DWORD GetFullPathNameA(LPCSTR, DWORD, LPSTR, LPSTR*);
     DWORD GetFullPathNameW(LPCWSTR, DWORD, LPWSTR, LPWSTR*);
     DWORD GetLastError() @trusted;
@@ -2485,6 +2560,7 @@ WINBASEAPI BOOL WINAPI SetEvent(HANDLE);
     static if (_WIN32_WINNT >= 0x600) {
         BOOL CreateSymbolicLinkA(LPCSTR, LPCSTR, DWORD);
         BOOL CreateSymbolicLinkW(LPCWSTR, LPCWSTR, DWORD);
+        BOOL GetFileInformationByHandleEx(HANDLE, FILE_INFO_BY_HANDLE_CLASS, LPVOID, DWORD);
     }
 }
 
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index a8d084060cf0ade6b1cb44ee51a44056b5dfcc02..1de993c0bff97501cb5efd86d669889ce5eae641 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -1758,85 +1758,65 @@ do
 Given an array of length `size` that needs to be expanded to `newlength`,
 compute a new capacity.
 
-Better version by Dave Fladebo:
+Better version by Dave Fladebo, enhanced by Steven Schveighoffer:
 This uses an inverse logorithmic algorithm to pre-allocate a bit more
 space for larger arrays.
-- Arrays smaller than PAGESIZE bytes are left as-is, so for the most
-common cases, memory allocation is 1 to 1. The small overhead added
-doesn't affect small array perf. (it's virtually the same as
-current).
-- Larger arrays have some space pre-allocated.
+- The maximum "extra" space is about 80% of the requested space. This is for
+PAGE size and smaller.
 - As the arrays grow, the relative pre-allocated space shrinks.
-- The logorithmic algorithm allocates relatively more space for
-mid-size arrays, making it very fast for medium arrays (for
-mid-to-large arrays, this turns out to be quite a bit faster than the
-equivalent realloc() code in C, on Linux at least. Small arrays are
-just as fast as GCC).
 - Perhaps most importantly, overall memory usage and stress on the GC
 is decreased significantly for demanding environments.
+- The algorithm is tuned to avoid any division at runtime.
 
 Params:
     newlength = new `.length`
-    size = old `.length`
+    elemsize = size of the element in the new array
 Returns: new capacity for array
 */
-size_t newCapacity(size_t newlength, size_t size)
+size_t newCapacity(size_t newlength, size_t elemsize)
 {
-    version (none)
-    {
-        size_t newcap = newlength * size;
-    }
-    else
-    {
-        size_t newcap = newlength * size;
-        size_t newext = 0;
+    size_t newcap = newlength * elemsize;
 
-        if (newcap > PAGESIZE)
+    /*
+     * Max growth factor numerator is 234, so allow for multiplying by 256.
+     * But also, the resulting size cannot be more than 2x, so prevent
+     * growing if 2x would fill up the address space (for 32-bit)
+     */
+    enum largestAllowed = (ulong.max >> 8) & (size_t.max >> 1);
+    if (!newcap || (newcap & ~largestAllowed))
+        return newcap;
+
+    /*
+     * The calculation for "extra" space depends on the requested capacity.
+     * We use an inverse logarithm of the new capacity to add an extra 15%
+     * to 83% capacity. Note that normally we humans think in terms of
+     * percent, but using 128 instead of 100 for the denominator means we
+     * can avoid all division by simply bit-shifthing. Since there are only
+     * 64 bits in a long, the bsr of a size_t is going to be 0 - 63. Using
+     * a lookup table allows us to precalculate the multiplier based on the
+     * inverse logarithm. The formula rougly is:
+     *
+     * newcap = request * (1.0 + min(0.83, 10.0 / (log(request) + 1)))
+     */
+    import core.bitop;
+    static immutable multTable = (){
+        assert(__ctfe);
+        ulong[size_t.sizeof * 8] result;
+        foreach (i; 0 .. result.length)
         {
-            //double mult2 = 1.0 + (size / log10(pow(newcap * 2.0,2.0)));
-
-            // redo above line using only integer math
+            auto factor = 128 + 1280 / (i + 1);
+            result[i] = factor > 234 ? 234 : factor;
+        }
+        return result;
+    }();
 
-            /*static int log2plus1(size_t c)
-            {   int i;
+    auto mult = multTable[bsr(newcap)];
 
-                if (c == 0)
-                    i = -1;
-                else
-                    for (i = 1; c >>= 1; i++)
-                    {
-                    }
-                return i;
-            }*/
-
-            /* The following setting for mult sets how much bigger
-             * the new size will be over what is actually needed.
-             * 100 means the same size, more means proportionally more.
-             * More means faster but more memory consumption.
-             */
-            //long mult = 100 + (1000L * size) / (6 * log2plus1(newcap));
-            //long mult = 100 + (1000L * size) / log2plus1(newcap);
-            import core.bitop;
-            long mult = 100 + (1000L) / (bsr(newcap) + 1);
-
-            // testing shows 1.02 for large arrays is about the point of diminishing return
-            //
-            // Commented out because the multipler will never be < 102.  In order for it to be < 2,
-            // then 1000L / (bsr(x) + 1) must be > 2.  The highest bsr(x) + 1
-            // could be is 65 (64th bit set), and 1000L / 64 is much larger
-            // than 2.  We need 500 bit integers for 101 to be achieved :)
-            /*if (mult < 102)
-                mult = 102;*/
-            /*newext = cast(size_t)((newcap * mult) / 100);
-            newext -= newext % size;*/
-            // This version rounds up to the next element, and avoids using
-            // mod.
-            newext = cast(size_t)((newlength * mult + 99) / 100) * size;
-            debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/100.0,newext / cast(double)size);
-        }
-        newcap = newext > newcap ? newext : newcap;
-        debug(PRINTF) printf("newcap = %d, newlength = %d, size = %d\n", newcap, newlength, size);
-    }
+    // if this were per cent, then the code would look like:
+    // ((newlength * mult + 99) / 100) * elemsize
+    newcap = cast(size_t)((newlength * mult + 127) >> 7) * elemsize;
+    debug(PRINTF) printf("mult: %2.2f, alloc: %2.2f\n",mult/128.0,newcap / cast(double)elemsize);
+    debug(PRINTF) printf("newcap = %d, newlength = %d, elemsize = %d\n", newcap, newlength, elemsize);
     return newcap;
 }
 
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 8daeda505f4f3d7f4c63b05553f9b5aadc8d35b7..a3a6f85c1a4696a405a5292cb7bcc09c262957f6 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-eab6595ade1dab9a757bc0efe2f4e92f39cab0f7
+bdedad3bf8090808e41726e7b9f8e928f6cb10bd
 
 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/comparison.d b/libphobos/src/std/algorithm/comparison.d
index 5c70960a711fc15c36c03f208c634a832c29ffd7..60fd114da2d7bbc42a6314593b3096a55462d4dc 100644
--- a/libphobos/src/std/algorithm/comparison.d
+++ b/libphobos/src/std/algorithm/comparison.d
@@ -102,7 +102,7 @@ template among(values...)
 if (isExpressionTuple!values)
 {
     uint among(Value)(Value value)
-        if (!is(CommonType!(Value, values) == void))
+    if (!is(CommonType!(Value, values) == void))
     {
         switch (value)
         {
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index 1453d2b64b948fcb7832fe6acba0516ae85aa868..8a3add3b73339f7c9adf31edc8efe8cad3712558 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -443,7 +443,8 @@ if (fun.length >= 1)
         A range with each fun applied to all the elements. If there is more than one
         fun, the element type will be `Tuple` containing one element for each fun.
      */
-    auto map(Range)(Range r) if (isInputRange!(Unqual!Range))
+    auto map(Range)(Range r)
+    if (isInputRange!(Unqual!Range))
     {
         import std.meta : AliasSeq, staticMap;
 
@@ -1308,7 +1309,8 @@ if (is(typeof(unaryFun!predicate)))
         A range containing only elements `x` in `range` for
         which `predicate(x)` returns `true`.
      */
-    auto filter(Range)(Range range) if (isInputRange!(Unqual!Range))
+    auto filter(Range)(Range range)
+    if (isInputRange!(Unqual!Range))
     {
         return FilterResult!(unaryFun!predicate, Range)(range);
     }
@@ -1545,7 +1547,8 @@ template filterBidirectional(alias pred)
     Returns:
         A range containing only the elements in `r` for which `pred` returns `true`.
      */
-    auto filterBidirectional(Range)(Range r) if (isBidirectionalRange!(Unqual!Range))
+    auto filterBidirectional(Range)(Range r)
+    if (isBidirectionalRange!(Unqual!Range))
     {
         return FilterBidiResult!(unaryFun!pred, Range)(r);
     }
diff --git a/libphobos/src/std/algorithm/mutation.d b/libphobos/src/std/algorithm/mutation.d
index e434d248edbfb1ec59790445fe866881470876a8..ea1a1b290dc23e42563275cdd87ea02fbd8cd470 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -2860,6 +2860,13 @@ Params:
     lhs = Data to be swapped with `rhs`.
     rhs = Data to be swapped with `lhs`.
 */
+void swap(T)(ref T lhs, ref T rhs)
+if (is(typeof(lhs.proxySwap(rhs))))
+{
+    lhs.proxySwap(rhs);
+}
+
+/// ditto
 void swap(T)(ref T lhs, ref T rhs) @trusted pure nothrow @nogc
 if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
 {
@@ -3121,13 +3128,6 @@ if (isBlitAssignable!T && !is(typeof(lhs.proxySwap(rhs))))
     swap(a3, a4);
 }
 
-/// ditto
-void swap(T)(ref T lhs, ref T rhs)
-if (is(typeof(lhs.proxySwap(rhs))))
-{
-    lhs.proxySwap(rhs);
-}
-
 /**
 Swaps two elements in-place of a range `r`,
 specified by their indices `i1` and `i2`.
diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d
index cb4715328722beea0341a37d8bdddcee35778897..29839d18091aa07c6e0bc11db5f44a12467cf0e6 100644
--- a/libphobos/src/std/algorithm/sorting.d
+++ b/libphobos/src/std/algorithm/sorting.d
@@ -2625,11 +2625,21 @@ private template TimSortImpl(alias pred, R)
             // can't use `temp.length` if there's no default constructor
             static if (__traits(compiles, { T defaultConstructed; cast(void) defaultConstructed; }))
             {
-                if (__ctfe) temp.length = newSize;
-                else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
+
+                static if (hasElaborateAssign!T)
+                    temp.length = newSize;
+                else
+                {
+                    if (__ctfe) temp.length = newSize;
+                    else temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
+                }
             }
             else
             {
+                static assert(!hasElaborateAssign!T,
+                              "Structs which have opAssign but cannot be default-initialized " ~
+                              "do not currently work with stable sort: " ~
+                              "https://issues.dlang.org/show_bug.cgi?id=24810");
                 temp = () @trusted { return uninitializedArray!(T[])(newSize); }();
             }
         }
@@ -3093,6 +3103,65 @@ private template TimSortImpl(alias pred, R)
     array.sort!((a, b) => false, SwapStrategy.stable);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24809
+@safe unittest
+{
+    static struct E
+    {
+        int value;
+        int valid = 42;
+
+        ~this()
+        {
+            assert(valid == 42);
+        }
+    }
+
+    import std.array : array;
+    import std.range : chain, only, repeat;
+    auto arr = chain(repeat(E(41), 18),
+                     only(E(39)),
+                     repeat(E(41), 16),
+                     only(E(1)),
+                     repeat(E(42), 33),
+                     only(E(33)),
+                     repeat(E(42), 16),
+                     repeat(E(43), 27),
+                     only(E(33)),
+                     repeat(E(43), 34),
+                     only(E(34)),
+                     only(E(43)),
+                     only(E(63)),
+                     repeat(E(44), 42),
+                     only(E(27)),
+                     repeat(E(44), 11),
+                     repeat(E(45), 64),
+                     repeat(E(46), 3),
+                     only(E(11)),
+                     repeat(E(46), 7),
+                     only(E(4)),
+                     repeat(E(46), 34),
+                     only(E(36)),
+                     repeat(E(46), 17),
+                     repeat(E(47), 36),
+                     only(E(39)),
+                     repeat(E(47), 26),
+                     repeat(E(48), 17),
+                     only(E(21)),
+                     repeat(E(48), 5),
+                     only(E(39)),
+                     repeat(E(48), 14),
+                     only(E(58)),
+                     repeat(E(48), 24),
+                     repeat(E(49), 13),
+                     only(E(40)),
+                     repeat(E(49), 38),
+                     only(E(18)),
+                     repeat(E(49), 11),
+                     repeat(E(50), 6)).array();
+
+    arr.sort!((a, b) => a.value < b.value, SwapStrategy.stable)();
+}
 
 // schwartzSort
 /**
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index 27d216740aa7cd9b84ba404d89bc999397907a3e..acd5311c4d22cbe71268a166e7f9f3354a9b3b1f 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -3701,7 +3701,8 @@ if (isDynamicArray!A)
      * Params:
      *     item = the single item to append
      */
-    void put(U)(U item) if (canPutItem!U)
+    void put(U)(U item)
+    if (canPutItem!U)
     {
         static if (isSomeChar!T && isSomeChar!U && T.sizeof < U.sizeof)
         {
@@ -3730,7 +3731,8 @@ if (isDynamicArray!A)
     }
 
     // Const fixing hack.
-    void put(Range)(Range items) if (canPutConstRange!Range)
+    void put(Range)(Range items)
+    if (canPutConstRange!Range)
     {
         alias p = put!(Unqual!Range);
         p(items);
@@ -3743,7 +3745,8 @@ if (isDynamicArray!A)
      * Params:
      *     items = the range of items to append
      */
-    void put(Range)(Range items) if (canPutRange!Range)
+    void put(Range)(Range items)
+    if (canPutRange!Range)
     {
         // note, we disable this branch for appending one type of char to
         // another because we can't trust the length portion.
diff --git a/libphobos/src/std/base64.d b/libphobos/src/std/base64.d
index 0fc92ac2b016293ea20cb1e55c8204ccb1194289..0ce81b520efe8e9b4f95bcfba746bfa3d70e0092 100644
--- a/libphobos/src/std/base64.d
+++ b/libphobos/src/std/base64.d
@@ -299,9 +299,10 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
     /**
      * ditto
      */
-    char[] encode(R1, R2)(R1 source, R2 buffer) if (!isArray!R1 && isInputRange!R1 &&
-                                                    is(ElementType!R1 : ubyte) && hasLength!R1 &&
-                                                    is(R2 == char[]))
+    char[] encode(R1, R2)(R1 source, R2 buffer)
+    if (!isArray!R1 && isInputRange!R1 &&
+        is(ElementType!R1 : ubyte) && hasLength!R1 &&
+        is(R2 == char[]))
     in
     {
         assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding");
@@ -474,8 +475,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * ditto
      */
     size_t encode(R1, R2)(R1 source, auto ref R2 range)
-        if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : ubyte) &&
-            hasLength!R1 && !is(R2 == char[]) && isOutputRange!(R2, char))
+    if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : ubyte) &&
+        hasLength!R1 && !is(R2 == char[]) && isOutputRange!(R2, char))
     {
         immutable srcLen = source.length;
         if (srcLen == 0)
@@ -559,7 +560,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      *  A newly-allocated `char[]` buffer containing the encoded string.
      */
     @safe
-    pure char[] encode(Range)(Range source) if (isArray!Range && is(ElementType!Range : ubyte))
+    pure char[] encode(Range)(Range source)
+    if (isArray!Range && is(ElementType!Range : ubyte))
     {
         return encode(source, new char[encodeLength(source.length)]);
     }
@@ -575,8 +577,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
     /**
      * ditto
      */
-    char[] encode(Range)(Range source) if (!isArray!Range && isInputRange!Range &&
-                                           is(ElementType!Range : ubyte) && hasLength!Range)
+    char[] encode(Range)(Range source)
+    if (!isArray!Range && isInputRange!Range &&
+        is(ElementType!Range : ubyte) && hasLength!Range)
     {
         return encode(source, new char[encodeLength(source.length)]);
     }
@@ -592,8 +595,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * Note: This struct is not intended to be created in user code directly;
      * use the $(LREF encoder) function instead.
      */
-    struct Encoder(Range) if (isInputRange!Range && (is(ElementType!Range : const(ubyte)[]) ||
-                                                     is(ElementType!Range : const(char)[])))
+    struct Encoder(Range)
+    if (isInputRange!Range && (is(ElementType!Range : const(ubyte)[]) ||
+        is(ElementType!Range : const(char)[])))
     {
       private:
         Range  range_;
@@ -702,7 +706,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * Note: This struct is not intended to be created in user code directly;
      * use the $(LREF encoder) function instead.
      */
-    struct Encoder(Range) if (isInputRange!Range && is(ElementType!Range : ubyte))
+    struct Encoder(Range)
+    if (isInputRange!Range && is(ElementType!Range : ubyte))
     {
       private:
         Range range_;
@@ -884,7 +889,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * }
      * -----
      */
-    Encoder!(Range) encoder(Range)(Range range) if (isInputRange!Range)
+    Encoder!(Range) encoder(Range)(Range range)
+    if (isInputRange!Range)
     {
         return typeof(return)(range);
     }
@@ -981,8 +987,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      *  base alphabet of the current Base64 encoding scheme.
      */
     @trusted
-    pure ubyte[] decode(R1, R2)(in R1 source, return scope R2 buffer) if (isArray!R1 && is(ElementType!R1 : dchar) &&
-                                                             is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
+    pure ubyte[] decode(R1, R2)(in R1 source, return scope R2 buffer)
+    if (isArray!R1 && is(ElementType!R1 : dchar) &&
+        is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
     in
     {
         assert(buffer.length >= realDecodeLength(source), "Insufficient buffer for decoding");
@@ -1065,9 +1072,10 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
     /**
      * ditto
      */
-    ubyte[] decode(R1, R2)(R1 source, R2 buffer) if (!isArray!R1 && isInputRange!R1 &&
-                                                     is(ElementType!R1 : dchar) && hasLength!R1 &&
-                                                     is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
+    ubyte[] decode(R1, R2)(R1 source, R2 buffer)
+    if (!isArray!R1 && isInputRange!R1 &&
+        is(ElementType!R1 : dchar) && hasLength!R1 &&
+        is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
     in
     {
         assert(buffer.length >= decodeLength(source.length), "Insufficient buffer for decoding");
@@ -1156,8 +1164,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      *  base alphabet of the current Base64 encoding scheme.
      */
     size_t decode(R1, R2)(in R1 source, auto ref R2 range)
-        if (isArray!R1 && is(ElementType!R1 : dchar) &&
-            !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
+    if (isArray!R1 && is(ElementType!R1 : dchar) &&
+        !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
     out(result)
     {
         immutable expect = realDecodeLength(source);
@@ -1244,8 +1252,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * ditto
      */
     size_t decode(R1, R2)(R1 source, auto ref R2 range)
-        if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : dchar) &&
-            hasLength!R1 && !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
+    if (!isArray!R1 && isInputRange!R1 && is(ElementType!R1 : dchar) &&
+        hasLength!R1 && !is(R2 == ubyte[]) && isOutputRange!(R2, ubyte))
     out(result)
     {
         // @@@BUG@@@ Workaround for DbC problem.
@@ -1334,7 +1342,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      *  A newly-allocated `ubyte[]` buffer containing the decoded string.
      */
     @safe
-    pure ubyte[] decode(Range)(Range source) if (isArray!Range && is(ElementType!Range : dchar))
+    pure ubyte[] decode(Range)(Range source)
+    if (isArray!Range && is(ElementType!Range : dchar))
     {
         return decode(source, new ubyte[decodeLength(source.length)]);
     }
@@ -1350,8 +1359,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
     /**
      * ditto
      */
-    ubyte[] decode(Range)(Range source) if (!isArray!Range && isInputRange!Range &&
-                                            is(ElementType!Range : dchar) && hasLength!Range)
+    ubyte[] decode(Range)(Range source)
+    if (!isArray!Range && isInputRange!Range &&
+        is(ElementType!Range : dchar) && hasLength!Range)
     {
         return decode(source, new ubyte[decodeLength(source.length)]);
     }
@@ -1367,8 +1377,9 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * Note: This struct is not intended to be created in user code directly;
      * use the $(LREF decoder) function instead.
      */
-    struct Decoder(Range) if (isInputRange!Range && (is(ElementType!Range : const(char)[]) ||
-                                                     is(ElementType!Range : const(ubyte)[])))
+    struct Decoder(Range)
+    if (isInputRange!Range && (is(ElementType!Range : const(char)[]) ||
+        is(ElementType!Range : const(ubyte)[])))
     {
       private:
         Range   range_;
@@ -1492,7 +1503,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * Note: This struct is not intended to be created in user code directly;
      * use the $(LREF decoder) function instead.
      */
-    struct Decoder(Range) if (isInputRange!Range && is(ElementType!Range : char))
+    struct Decoder(Range)
+    if (isInputRange!Range && is(ElementType!Range : char))
     {
       private:
         Range range_;
@@ -1683,7 +1695,8 @@ template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * }
      * -----
      */
-    Decoder!(Range) decoder(Range)(Range range) if (isInputRange!Range)
+    Decoder!(Range) decoder(Range)(Range range)
+    if (isInputRange!Range)
     {
         return typeof(return)(range);
     }
diff --git a/libphobos/src/std/bigint.d b/libphobos/src/std/bigint.d
index 0240ea1d179a01a2b22dbc927224aef98be51b81..a8b389795976cc75d387827a3cc74b3a441527d2 100644
--- a/libphobos/src/std/bigint.d
+++ b/libphobos/src/std/bigint.d
@@ -63,8 +63,8 @@ public:
      * Throws:
      *     $(REF ConvException, std,conv) if the string doesn't represent a valid number
      */
-    this(Range)(Range s) if (
-        isBidirectionalRange!Range &&
+    this(Range)(Range s)
+    if (isBidirectionalRange!Range &&
         isSomeChar!(ElementType!Range) &&
         !isInfinite!Range &&
         !isNarrowString!Range)
@@ -160,8 +160,8 @@ public:
      *          (ignored when magnitude is zero)
      *     magnitude = a finite range of unsigned integers
      */
-    this(Range)(bool isNegative, Range magnitude) if (
-        isInputRange!Range &&
+    this(Range)(bool isNegative, Range magnitude)
+    if (isInputRange!Range &&
         isUnsigned!(ElementType!Range) &&
         (hasLength!Range || isForwardRange!Range) &&
         !isInfinite!Range)
@@ -181,7 +181,8 @@ public:
     }
 
     /// Construct a `BigInt` from a built-in integral type.
-    this(T)(T x) pure nothrow @safe if (isIntegral!T)
+    this(T)(T x) pure nothrow @safe
+    if (isIntegral!T)
     {
         data = data.init; // @@@: Workaround for compiler bug
         opAssign(x);
@@ -196,7 +197,8 @@ public:
     }
 
     /// Construct a `BigInt` from another `BigInt`.
-    this(T)(T x) pure nothrow @safe if (is(immutable T == immutable BigInt))
+    this(T)(T x) pure nothrow @safe
+    if (is(immutable T == immutable BigInt))
     {
         opAssign(x);
     }
@@ -210,7 +212,8 @@ public:
     }
 
     /// Assignment from built-in integer types.
-    BigInt opAssign(T)(T x) pure nothrow @safe if (isIntegral!T)
+    BigInt opAssign(T)(T x) pure nothrow @safe
+    if (isIntegral!T)
     {
         data = cast(ulong) absUnsign(x);
         sign = (x < 0);
@@ -247,8 +250,8 @@ public:
      * `BigInt op= integer`.
      */
     BigInt opOpAssign(string op, T)(T y) pure nothrow @safe return scope
-        if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
-          || op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T)
+    if ((op=="+" || op=="-" || op=="*" || op=="/" || op=="%"
+        || op==">>" || op=="<<" || op=="^^" || op=="|" || op=="&" || op=="^") && isIntegral!T)
     {
         ulong u = absUnsign(y);
 
@@ -436,8 +439,7 @@ public:
      * Implements assignment operators of the form `BigInt op= BigInt`.
      */
     BigInt opOpAssign(string op, T)(T y) pure nothrow @safe return scope
-        if ((op=="+" || op== "-" || op=="*" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%")
-            && is (T: BigInt))
+    if ((op=="+" || op== "-" || op=="*" || op=="|" || op=="&" || op=="^" || op=="/" || op=="%") && is (T: BigInt))
     {
         static if (op == "+")
         {
@@ -494,9 +496,8 @@ public:
      * Implements binary operators between `BigInt`s.
      */
     BigInt opBinary(string op, T)(T y) pure nothrow @safe const return scope
-        if ((op=="+" || op == "*" || op=="-" || op=="|" || op=="&" || op=="^" ||
-            op=="/" || op=="%")
-            && is (T: BigInt))
+    if ((op=="+" || op == "*" || op=="-" || op=="|" || op=="&" || op=="^" ||
+        op=="/" || op=="%") && is (T: BigInt))
     {
         BigInt r = this;
         return r.opOpAssign!(op)(y);
@@ -515,9 +516,9 @@ public:
      * Implements binary operators between `BigInt`'s and built-in integers.
      */
     BigInt opBinary(string op, T)(T y) pure nothrow @safe const return scope
-        if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="|" || op=="&" ||
-            op=="^"|| op==">>" || op=="<<" || op=="^^")
-            && isIntegral!T)
+    if ((op=="+" || op == "*" || op=="-" || op=="/" || op=="|" || op=="&" ||
+        op=="^"|| op==">>" || op=="<<" || op=="^^")
+        && isIntegral!T)
     {
         BigInt r = this;
         r.opOpAssign!(op)(y);
@@ -546,7 +547,7 @@ public:
         )
      */
     auto opBinary(string op, T)(T y) pure nothrow @safe const
-        if (op == "%" && isIntegral!T)
+    if (op == "%" && isIntegral!T)
     {
         assert(y != 0, "% 0 not allowed");
 
@@ -602,7 +603,7 @@ public:
         `BigInt` on the right-hand side.
      */
     BigInt opBinaryRight(string op, T)(T y) pure nothrow @safe const
-        if ((op=="+" || op=="*" || op=="|" || op=="&" || op=="^") && isIntegral!T)
+    if ((op=="+" || op=="*" || op=="|" || op=="&" || op=="^") && isIntegral!T)
     {
         return opBinary!(op)(y);
     }
@@ -627,7 +628,7 @@ public:
     //  BigInt = integer op BigInt
     /// ditto
     BigInt opBinaryRight(string op, T)(T y) pure nothrow @safe const
-        if (op == "-" && isIntegral!T)
+    if (op == "-" && isIntegral!T)
     {
         ulong u = absUnsign(y);
         BigInt r;
@@ -643,7 +644,7 @@ public:
     //  integer = integer op BigInt
     /// ditto
     T opBinaryRight(string op, T)(T x) pure nothrow @safe const
-        if ((op=="%" || op=="/") && isIntegral!T)
+    if ((op=="%" || op=="/") && isIntegral!T)
     {
         checkDivByZero();
 
@@ -669,7 +670,8 @@ public:
     /**
         Implements `BigInt` unary operators.
      */
-    BigInt opUnary(string op)() pure nothrow @safe const if (op=="+" || op=="-" || op=="~")
+    BigInt opUnary(string op)() pure nothrow @safe const
+    if (op=="+" || op=="-" || op=="~")
     {
        static if (op=="-")
        {
@@ -687,7 +689,8 @@ public:
 
     // non-const unary operations
     /// ditto
-    BigInt opUnary(string op)() pure nothrow @safe if (op=="++" || op=="--")
+    BigInt opUnary(string op)() pure nothrow @safe
+    if (op=="++" || op=="--")
     {
         static if (op=="++")
         {
@@ -721,7 +724,8 @@ public:
     }
 
     /// ditto
-    bool opEquals(T)(const T y) const pure nothrow @nogc @safe if (isIntegral!T)
+    bool opEquals(T)(const T y) const pure nothrow @nogc @safe
+    if (isIntegral!T)
     {
         if (sign != (y<0))
             return 0;
@@ -729,7 +733,8 @@ public:
     }
 
     /// ditto
-    bool opEquals(T)(const T y) const pure nothrow @nogc if (isFloatingPoint!T)
+    bool opEquals(T)(const T y) const pure nothrow @nogc
+    if (isFloatingPoint!T)
     {
         return 0 == opCmp(y);
     }
@@ -896,7 +901,8 @@ public:
     /**
         Implements casting to floating point types.
      */
-    T opCast(T)() @safe nothrow @nogc const if (isFloatingPoint!T)
+    T opCast(T)() @safe nothrow @nogc const
+    if (isFloatingPoint!T)
     {
         return toFloat!(T, "nearest");
     }
@@ -1090,7 +1096,8 @@ public:
     }
 
     /// ditto
-    int opCmp(T)(const T y) pure nothrow @nogc @safe const if (isIntegral!T)
+    int opCmp(T)(const T y) pure nothrow @nogc @safe const
+    if (isIntegral!T)
     {
         if (sign != (y<0) )
             return sign ? -1 : 1;
@@ -1098,7 +1105,8 @@ public:
         return sign? -cmp: cmp;
     }
     /// ditto
-    int opCmp(T)(const T y) nothrow @nogc @safe const if (isFloatingPoint!T)
+    int opCmp(T)(const T y) nothrow @nogc @safe const
+    if (isFloatingPoint!T)
     {
         import core.bitop : bsr;
         import std.math.operations : cmp;
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index 0993d34843fcf58b739372b86381cd96b1eff68f..15211a3a98adab5ab2952bf801a350a5db76055c 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -1925,7 +1925,7 @@ public:
      * Support for unary operator ~ for `BitArray`.
      */
     BitArray opUnary(string op)() const pure nothrow
-        if (op == "~")
+    if (op == "~")
     {
         auto dim = this.dim;
 
@@ -1962,7 +1962,7 @@ public:
      * Support for binary bitwise operators for `BitArray`.
      */
     BitArray opBinary(string op)(const BitArray e2) const pure nothrow
-        if (op == "-" || op == "&" || op == "|" || op == "^")
+    if (op == "-" || op == "&" || op == "|" || op == "^")
     in
     {
         assert(e2.length == _len, "e2 must have the same length as this");
@@ -2064,7 +2064,7 @@ public:
      * Support for operator op= for `BitArray`.
      */
     BitArray opOpAssign(string op)(const BitArray e2) @nogc pure nothrow return scope
-        if (op == "-" || op == "&" || op == "|" || op == "^")
+    if (op == "-" || op == "&" || op == "|" || op == "^")
     in
     {
         assert(e2.length == _len, "e2 must have the same length as this");
@@ -2185,7 +2185,7 @@ public:
      * concatenation semantics are not followed)
      */
     BitArray opOpAssign(string op)(bool b) pure nothrow return scope
-        if (op == "~")
+    if (op == "~")
     {
         length = _len + 1;
         this[_len - 1] = b;
@@ -2215,7 +2215,7 @@ public:
      * ditto
      */
     BitArray opOpAssign(string op)(BitArray b) pure nothrow return scope
-        if (op == "~")
+    if (op == "~")
     {
         auto istart = _len;
         length = _len + b.length;
@@ -2249,7 +2249,7 @@ public:
      * Support for binary operator ~ for `BitArray`.
      */
     BitArray opBinary(string op)(bool b) const pure nothrow
-        if (op == "~")
+    if (op == "~")
     {
         BitArray r;
 
@@ -2261,7 +2261,7 @@ public:
 
     /** ditto */
     BitArray opBinaryRight(string op)(bool b) const pure nothrow
-        if (op == "~")
+    if (op == "~")
     {
         BitArray r;
 
@@ -2274,7 +2274,7 @@ public:
 
     /** ditto */
     BitArray opBinary(string op)(BitArray b) const pure nothrow
-        if (op == "~")
+    if (op == "~")
     {
         BitArray r;
 
@@ -2398,7 +2398,7 @@ public:
      * preserve bits past the end of the array.)
      */
     void opOpAssign(string op)(size_t nbits) @nogc pure nothrow
-        if (op == "<<")
+    if (op == "<<")
     {
         size_t wordsToShift = nbits / bitsPerSizeT;
         size_t bitsToShift = nbits % bitsPerSizeT;
@@ -2432,7 +2432,7 @@ public:
      * preserve bits past the end of the array.)
      */
     void opOpAssign(string op)(size_t nbits) @nogc pure nothrow
-        if (op == ">>")
+    if (op == ">>")
     {
         size_t wordsToShift = nbits / bitsPerSizeT;
         size_t bitsToShift = nbits % bitsPerSizeT;
@@ -2945,58 +2945,6 @@ if (isIntegral!T || isSomeChar!T || isBoolean!T)
 }
 
 
-private union EndianSwapper(T)
-if (canSwapEndianness!T)
-{
-    T value;
-    ubyte[T.sizeof] array;
-
-    static if (is(immutable FloatingPointTypeOf!(T) == immutable float))
-        uint  intValue;
-    else static if (is(immutable FloatingPointTypeOf!(T) == immutable double))
-        ulong intValue;
-
-}
-
-// Can't use EndianSwapper union during CTFE.
-private auto ctfeRead(T)(const ubyte[T.sizeof] array)
-if (__traits(isIntegral, T))
-{
-    Unqual!T result;
-    version (LittleEndian)
-        foreach_reverse (b; array)
-            result = cast() cast(T) ((result << 8) | b);
-    else
-        foreach (b; array)
-            result = cast() cast(T) ((result << 8) | b);
-    return cast(T) result;
-}
-
-// Can't use EndianSwapper union during CTFE.
-private auto ctfeBytes(T)(const T value)
-if (__traits(isIntegral, T))
-{
-    ubyte[T.sizeof] result;
-    Unqual!T tmp = value;
-    version (LittleEndian)
-    {
-        foreach (i; 0 .. T.sizeof)
-        {
-            result[i] = cast(ubyte) tmp;
-            tmp = cast() cast(T) (tmp >>> 8);
-        }
-    }
-    else
-    {
-        foreach_reverse (i; 0 .. T.sizeof)
-        {
-            result[i] = cast(ubyte) tmp;
-            tmp = cast()(T) (tmp >>> 8);
-        }
-    }
-    return result;
-}
-
 /++
     Converts the given value from the native endianness to big endian and
     returns it as a `ubyte[n]` where `n` is the size of the given type.
@@ -3010,13 +2958,21 @@ if (__traits(isIntegral, T))
     and therefore could vary from machine to machine (which could make it
     unusable if you tried to transfer it to another machine).
   +/
-auto nativeToBigEndian(T)(const T val) @safe pure nothrow @nogc
+auto nativeToBigEndian(T)(const T val) @trusted pure nothrow @nogc
 if (canSwapEndianness!T)
 {
-    version (LittleEndian)
-        return nativeToEndianImpl!true(val);
+    static if (isFloatOrDouble!T)
+        return nativeToBigEndian(*cast(const UnsignedOfSize!(T.sizeof)*) &val);
     else
-        return nativeToEndianImpl!false(val);
+    {
+        enum len = T.sizeof;
+        ubyte[len] retval;
+
+        static foreach (i; 0 .. len)
+            retval[i] = cast(ubyte)(val >> (len - i - 1) * 8);
+
+        return retval;
+    }
 }
 
 ///
@@ -3043,26 +2999,6 @@ if (canSwapEndianness!T)
     assert(cd == bigEndianToNative!double(swappedCD));
 }
 
-private auto nativeToEndianImpl(bool swap, T)(const T val) @safe pure nothrow @nogc
-if (__traits(isIntegral, T))
-{
-    if (!__ctfe)
-    {
-        static if (swap)
-            return EndianSwapper!T(swapEndian(val)).array;
-        else
-            return EndianSwapper!T(val).array;
-    }
-    else
-    {
-        // Can't use EndianSwapper in CTFE.
-        static if (swap)
-            return ctfeBytes(swapEndian(val));
-        else
-            return ctfeBytes(val);
-    }
-}
-
 @safe unittest
 {
     import std.meta;
@@ -3149,13 +3085,25 @@ if (__traits(isIntegral, T))
     because the FPU will mess up any swapped floating point values. So, you
     can't actually have swapped floating point values as floating point values).
   +/
-T bigEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc
+T bigEndianToNative(T, size_t n)(ubyte[n] val) @trusted pure nothrow @nogc
 if (canSwapEndianness!T && n == T.sizeof)
 {
-    version (LittleEndian)
-        return endianToNativeImpl!(true, T, n)(val);
+    static if (isFloatOrDouble!T)
+    {
+        auto retval = bigEndianToNative!(UnsignedOfSize!(T.sizeof))(val);
+        return *cast(const T*) &retval;
+    }
     else
-        return endianToNativeImpl!(false, T, n)(val);
+    {
+        enum len = T.sizeof;
+        alias U = UnsignedOfSize!len;
+        U retval;
+
+        static foreach (i; 0 .. len)
+            retval |= (cast(U) val[i]) << (len - i - 1) * 8;
+
+        return cast(T) retval;
+    }
 }
 
 ///
@@ -3179,13 +3127,21 @@ if (canSwapEndianness!T && n == T.sizeof)
     because the FPU will mess up any swapped floating point values. So, you
     can't actually have swapped floating point values as floating point values).
   +/
-auto nativeToLittleEndian(T)(const T val) @safe pure nothrow @nogc
+auto nativeToLittleEndian(T)(const T val) @trusted pure nothrow @nogc
 if (canSwapEndianness!T)
 {
-    version (BigEndian)
-        return nativeToEndianImpl!true(val);
+    static if (isFloatOrDouble!T)
+        return nativeToLittleEndian(*cast(const UnsignedOfSize!(T.sizeof)*) &val);
     else
-        return nativeToEndianImpl!false(val);
+    {
+        enum len = T.sizeof;
+        ubyte[len] retval;
+
+        static foreach (i; 0 .. len)
+            retval[i] = cast(ubyte)(val >> i * 8);
+
+        return retval;
+    }
 }
 
 ///
@@ -3195,9 +3151,21 @@ if (canSwapEndianness!T)
     ubyte[4] swappedI = nativeToLittleEndian(i);
     assert(i == littleEndianToNative!int(swappedI));
 
+    float f = 123.45f;
+    ubyte[4] swappedF = nativeToLittleEndian(f);
+    assert(f == littleEndianToNative!float(swappedF));
+
+    const float cf = 123.45f;
+    ubyte[4] swappedCF = nativeToLittleEndian(cf);
+    assert(cf == littleEndianToNative!float(swappedCF));
+
     double d = 123.45;
     ubyte[8] swappedD = nativeToLittleEndian(d);
     assert(d == littleEndianToNative!double(swappedD));
+
+    const double cd = 123.45;
+    ubyte[8] swappedCD = nativeToLittleEndian(cd);
+    assert(cd == littleEndianToNative!double(swappedCD));
 }
 
 @safe unittest
@@ -3259,13 +3227,25 @@ if (canSwapEndianness!T)
     and therefore could vary from machine to machine (which could make it
     unusable if you tried to transfer it to another machine).
   +/
-T littleEndianToNative(T, size_t n)(ubyte[n] val) @safe pure nothrow @nogc
+T littleEndianToNative(T, size_t n)(ubyte[n] val) @trusted pure nothrow @nogc
 if (canSwapEndianness!T && n == T.sizeof)
 {
-    version (BigEndian)
-        return endianToNativeImpl!(true, T, n)(val);
+    static if (isFloatOrDouble!T)
+    {
+        auto retval = littleEndianToNative!(UnsignedOfSize!(T.sizeof))(val);
+        return *cast(const T*) &retval;
+    }
     else
-        return endianToNativeImpl!(false, T, n)(val);
+    {
+        enum len = T.sizeof;
+        alias U = UnsignedOfSize!len;
+        U retval;
+
+        static foreach (i; 0 .. len)
+            retval |= (cast(U) val[i]) << i * 8;
+
+        return cast(T) retval;
+    }
 }
 
 ///
@@ -3280,70 +3260,6 @@ if (canSwapEndianness!T && n == T.sizeof)
     assert(c == littleEndianToNative!dchar(swappedC));
 }
 
-private T endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @nogc nothrow pure @trusted
-if (__traits(isIntegral, T) && n == T.sizeof)
-{
-    if (!__ctfe)
-    {
-        EndianSwapper!T es = { array: val };
-        static if (swap)
-            return swapEndian(es.value);
-        else
-            return es.value;
-    }
-    else
-    {
-        static if (swap)
-            return swapEndian(ctfeRead!T(val));
-        else
-            return ctfeRead!T(val);
-    }
-}
-
-private auto nativeToEndianImpl(bool swap, T)(const T val) @trusted pure nothrow @nogc
-if (isFloatOrDouble!T)
-{
-    if (!__ctfe)
-    {
-        EndianSwapper!T es = EndianSwapper!T(val);
-        static if (swap)
-            es.intValue = swapEndian(es.intValue);
-        return es.array;
-    }
-    else
-    {
-        static if (T.sizeof == 4)
-            uint intValue = *cast(const uint*) &val;
-        else static if (T.sizeof == 8)
-            ulong intValue = *cast(const ulong*) & val;
-        static if (swap)
-            intValue = swapEndian(intValue);
-        return ctfeBytes(intValue);
-    }
-}
-
-private auto endianToNativeImpl(bool swap, T, size_t n)(ubyte[n] val) @trusted pure nothrow @nogc
-if (isFloatOrDouble!T && n == T.sizeof)
-{
-    if (!__ctfe)
-    {
-        EndianSwapper!T es = { array: val };
-        static if (swap)
-            es.intValue = swapEndian(es.intValue);
-        return es.value;
-    }
-    else
-    {
-        static if (n == 4)
-            uint x = ctfeRead!uint(val);
-        else static if (n == 8)
-            ulong x = ctfeRead!ulong(val);
-        static if (swap)
-            x = swapEndian(x);
-        return *cast(T*) &x;
-    }
-}
-
 private template isFloatOrDouble(T)
 {
     enum isFloatOrDouble = isFloatingPoint!T &&
@@ -3405,6 +3321,42 @@ private template canSwapEndianness(T)
     }
 }
 
+private template UnsignedOfSize(size_t n)
+{
+    static if (n == 8)
+        alias UnsignedOfSize = ulong;
+    else static if (n == 4)
+        alias UnsignedOfSize = uint;
+    else static if (n == 2)
+        alias UnsignedOfSize = ushort;
+    else static if (n == 1)
+        alias UnsignedOfSize = ubyte;
+    else
+        alias UnsignedOfSize = void;
+}
+
+@safe unittest
+{
+    static assert(is(UnsignedOfSize!(byte.sizeof) == ubyte));
+    static assert(is(UnsignedOfSize!(ubyte.sizeof) == ubyte));
+    static assert(is(UnsignedOfSize!(short.sizeof) == ushort));
+    static assert(is(UnsignedOfSize!(ushort.sizeof) == ushort));
+    static assert(is(UnsignedOfSize!(int.sizeof) == uint));
+    static assert(is(UnsignedOfSize!(uint.sizeof) == uint));
+    static assert(is(UnsignedOfSize!(long.sizeof) == ulong));
+    static assert(is(UnsignedOfSize!(ulong.sizeof) == ulong));
+
+    static assert(is(UnsignedOfSize!(bool.sizeof) == ubyte));
+    static assert(is(UnsignedOfSize!(char.sizeof) == ubyte));
+    static assert(is(UnsignedOfSize!(wchar.sizeof) == ushort));
+    static assert(is(UnsignedOfSize!(dchar.sizeof) == uint));
+
+    static assert(is(UnsignedOfSize!(float.sizeof) == uint));
+    static assert(is(UnsignedOfSize!(double.sizeof) == ulong));
+
+    static assert(is(UnsignedOfSize!10 == void));
+}
+
 /++
     Takes a range of `ubyte`s and converts the first `T.sizeof` bytes to
     `T`. The value returned is converted from the given endianness to the
diff --git a/libphobos/src/std/checkedint.d b/libphobos/src/std/checkedint.d
index cec1dc1a2dbbaca26c360a5b6c98b54286c752df..630ae4153a8ce4b3fac36d00e537856318350fcc 100644
--- a/libphobos/src/std/checkedint.d
+++ b/libphobos/src/std/checkedint.d
@@ -3362,12 +3362,14 @@ version (StdUnittest) private struct CountOverflows
     static struct Hook1
     {
         uint calls;
-        auto hookOpUnary(string op, T)(T value) if (op == "-")
+        auto hookOpUnary(string op, T)(T value)
+        if (op == "-")
         {
             ++calls;
             return T(42);
         }
-        auto hookOpUnary(string op, T)(T value) if (op == "~")
+        auto hookOpUnary(string op, T)(T value)
+        if (op == "~")
         {
             ++calls;
             return T(43);
@@ -3383,12 +3385,14 @@ version (StdUnittest) private struct CountOverflows
     static struct Hook2
     {
         uint calls;
-        void hookOpUnary(string op, T)(ref T value) if (op == "++")
+        void hookOpUnary(string op, T)(ref T value)
+        if (op == "++")
         {
             ++calls;
             --value;
         }
-        void hookOpUnary(string op, T)(ref T value) if (op == "--")
+        void hookOpUnary(string op, T)(ref T value)
+        if (op == "--")
         {
             ++calls;
             ++value;
diff --git a/libphobos/src/std/complex.d b/libphobos/src/std/complex.d
index 60746f98ef7f68b3328d92579d2af3e795993a12..01e8dd2c1dac946d7f88012e3f7874a4f6a92847 100644
--- a/libphobos/src/std/complex.d
+++ b/libphobos/src/std/complex.d
@@ -156,7 +156,7 @@ if (isFloatingPoint!T)
 
     /// ditto
     void toString(Writer, Char)(scope Writer w, scope const ref FormatSpec!Char formatSpec) const
-        if (isOutputRange!(Writer, const(Char)[]))
+    if (isOutputRange!(Writer, const(Char)[]))
     {
         import std.format.write : formatValue;
         import std.math.traits : signbit;
@@ -231,14 +231,14 @@ if (isFloatingPoint!T)
 
     // +complex
     Complex opUnary(string op)() const
-        if (op == "+")
+    if (op == "+")
     {
         return this;
     }
 
     // -complex
     Complex opUnary(string op)() const
-        if (op == "-")
+    if (op == "-")
     {
         return Complex(-re, -im);
     }
@@ -255,7 +255,7 @@ if (isFloatingPoint!T)
 
     // complex op numeric
     Complex!(CommonType!(T,R)) opBinary(string op, R)(const R r) const
-        if (isNumeric!R)
+    if (isNumeric!R)
     {
         alias C = typeof(return);
         auto w = C(this.re, this.im);
@@ -264,21 +264,21 @@ if (isFloatingPoint!T)
 
     // numeric + complex,  numeric * complex
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
-        if ((op == "+" || op == "*") && (isNumeric!R))
+    if ((op == "+" || op == "*") && (isNumeric!R))
     {
         return opBinary!(op)(r);
     }
 
     // numeric - complex
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
-        if (op == "-" && isNumeric!R)
+    if (op == "-" && isNumeric!R)
     {
         return Complex(r - re, -im);
     }
 
     // numeric / complex
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R r) const
-        if (op == "/" && isNumeric!R)
+    if (op == "/" && isNumeric!R)
     {
         version (FastMath)
         {
@@ -320,7 +320,7 @@ if (isFloatingPoint!T)
 
     // numeric ^^ complex
     Complex!(CommonType!(T, R)) opBinaryRight(string op, R)(const R lhs) const
-        if (op == "^^" && isNumeric!R)
+    if (op == "^^" && isNumeric!R)
     {
         import core.math : cos, sin;
         import std.math.exponential : exp, log;
@@ -349,7 +349,7 @@ if (isFloatingPoint!T)
 
     // complex += complex,  complex -= complex
     ref Complex opOpAssign(string op, C)(const C z)
-        if ((op == "+" || op == "-") && is(C R == Complex!R))
+    if ((op == "+" || op == "-") && is(C R == Complex!R))
     {
         mixin ("re "~op~"= z.re;");
         mixin ("im "~op~"= z.im;");
@@ -358,7 +358,7 @@ if (isFloatingPoint!T)
 
     // complex *= complex
     ref Complex opOpAssign(string op, C)(const C z)
-        if (op == "*" && is(C R == Complex!R))
+    if (op == "*" && is(C R == Complex!R))
     {
         auto temp = re*z.re - im*z.im;
         im = im*z.re + re*z.im;
@@ -368,7 +368,7 @@ if (isFloatingPoint!T)
 
     // complex /= complex
     ref Complex opOpAssign(string op, C)(const C z)
-        if (op == "/" && is(C R == Complex!R))
+    if (op == "/" && is(C R == Complex!R))
     {
         version (FastMath)
         {
@@ -409,7 +409,7 @@ if (isFloatingPoint!T)
 
     // complex ^^= complex
     ref Complex opOpAssign(string op, C)(const C z)
-        if (op == "^^" && is(C R == Complex!R))
+    if (op == "^^" && is(C R == Complex!R))
     {
         import core.math : cos, sin;
         import std.math.exponential : exp, log;
@@ -425,7 +425,7 @@ if (isFloatingPoint!T)
 
     // complex += numeric,  complex -= numeric
     ref Complex opOpAssign(string op, U : T)(const U a)
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         mixin ("re "~op~"= a;");
         return this;
@@ -433,7 +433,7 @@ if (isFloatingPoint!T)
 
     // complex *= numeric,  complex /= numeric
     ref Complex opOpAssign(string op, U : T)(const U a)
-        if (op == "*" || op == "/")
+    if (op == "*" || op == "/")
     {
         mixin ("re "~op~"= a;");
         mixin ("im "~op~"= a;");
@@ -442,7 +442,7 @@ if (isFloatingPoint!T)
 
     // complex ^^= real
     ref Complex opOpAssign(string op, R)(const R r)
-        if (op == "^^" && isFloatingPoint!R)
+    if (op == "^^" && isFloatingPoint!R)
     {
         import core.math : cos, sin;
         immutable ab = abs(this)^^r;
@@ -454,7 +454,7 @@ if (isFloatingPoint!T)
 
     // complex ^^= int
     ref Complex opOpAssign(string op, U)(const U i)
-        if (op == "^^" && isIntegral!U)
+    if (op == "^^" && isIntegral!U)
     {
         switch (i)
         {
diff --git a/libphobos/src/std/concurrency.d b/libphobos/src/std/concurrency.d
index 267f682b3e964f3146ecc59efea26531b3099ba1..94265a2b7797e85384c9f1631ae8d854cb085bde 100644
--- a/libphobos/src/std/concurrency.d
+++ b/libphobos/src/std/concurrency.d
@@ -163,7 +163,8 @@ private
         MsgType type;
         Variant data;
 
-        this(T...)(MsgType t, T vals) if (T.length > 0)
+        this(T...)(MsgType t, T vals)
+        if (T.length > 0)
         {
             static if (T.length == 1)
             {
diff --git a/libphobos/src/std/container/dlist.d b/libphobos/src/std/container/dlist.d
index 4fdf13d486f107777d2db9145dae3e7344f6e6ba..728aacde5c086dfcf14eb7df1ced86d751d75f63 100644
--- a/libphobos/src/std/container/dlist.d
+++ b/libphobos/src/std/container/dlist.d
@@ -245,7 +245,8 @@ struct DList(T)
 /**
 Constructor taking a number of nodes
      */
-    this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
+    this(U)(U[] values...)
+    if (isImplicitlyConvertible!(U, T))
     {
         insertBack(values);
     }
diff --git a/libphobos/src/std/container/package.d b/libphobos/src/std/container/package.d
index 763da8b52b0bcf3d2a998b8e47b460c54c31d006..fc0495057d0c5cfcc4c0d6298f5237dd0fab09bd 100644
--- a/libphobos/src/std/container/package.d
+++ b/libphobos/src/std/container/package.d
@@ -801,7 +801,8 @@ Indexing operators yield or modify the value at a specified index.
 /**
 $(D k in container) returns true if the given key is in the container.
  */
-    bool opBinaryRight(string op)(KeyType k) if (op == "in")
+    bool opBinaryRight(string op)(KeyType k)
+    if (op == "in")
     {
         assert(0, "Not implemented");
     }
@@ -843,13 +844,15 @@ define `opBinary`.
 Complexity: $(BIGOH n + m), where m is the number of elements in $(D
 stuff)
  */
-    TotalContainer opBinary(string op)(Stuff rhs) if (op == "~")
+    TotalContainer opBinary(string op)(Stuff rhs)
+    if (op == "~")
     {
         assert(0, "Not implemented");
     }
 
     /// ditto
-    TotalContainer opBinaryRight(string op)(Stuff lhs) if (op == "~")
+    TotalContainer opBinaryRight(string op)(Stuff lhs)
+    if (op == "~")
     {
         assert(0, "Not implemented");
     }
@@ -857,7 +860,8 @@ stuff)
 /**
 Forwards to $(D insertAfter(this[], stuff)).
  */
-    void opOpAssign(string op)(Stuff stuff) if (op == "~")
+    void opOpAssign(string op)(Stuff stuff)
+    if (op == "~")
     {
         assert(0, "Not implemented");
     }
diff --git a/libphobos/src/std/container/rbtree.d b/libphobos/src/std/container/rbtree.d
index 9bd8d27c0656b0a36e1697db32f47286dcc87eeb..53697029c970f203109eb3327ce988a8b5ed7377 100644
--- a/libphobos/src/std/container/rbtree.d
+++ b/libphobos/src/std/container/rbtree.d
@@ -1057,7 +1057,8 @@ if (is(typeof(binaryFun!less(T.init, T.init))))
 
        Complexity: $(BIGOH log(n))
      +/
-    bool opBinaryRight(string op)(Elem e) const if (op == "in")
+    bool opBinaryRight(string op)(Elem e) const
+    if (op == "in")
     {
         return _find(e) !is null;
     }
@@ -1261,7 +1262,8 @@ if (is(typeof(binaryFun!less(T.init, T.init))))
      *
      * Complexity: $(BIGOH log(n))
      */
-    size_t stableInsert(Stuff)(Stuff stuff) if (isImplicitlyConvertible!(Stuff, Elem))
+    size_t stableInsert(Stuff)(Stuff stuff)
+    if (isImplicitlyConvertible!(Stuff, Elem))
     {
         static if (allowDuplicates)
         {
@@ -1283,8 +1285,8 @@ if (is(typeof(binaryFun!less(T.init, T.init))))
      * Complexity: $(BIGOH m * log(n))
      */
     size_t stableInsert(Stuff)(scope Stuff stuff)
-        if (isInputRange!Stuff &&
-            isImplicitlyConvertible!(ElementType!Stuff, Elem))
+    if (isInputRange!Stuff &&
+        isImplicitlyConvertible!(ElementType!Stuff, Elem))
     {
         size_t result = 0;
         static if (allowDuplicates)
@@ -1534,7 +1536,7 @@ assert(equal(rbt[], [5]));
 --------------------
       +/
     size_t removeKey(U...)(U elems)
-        if (allSatisfy!(isImplicitlyConvertibleToElem, U))
+    if (allSatisfy!(isImplicitlyConvertibleToElem, U))
     {
         Elem[U.length] toRemove = [elems];
         return removeKey(toRemove[]);
@@ -1542,7 +1544,7 @@ assert(equal(rbt[], [5]));
 
     /++ Ditto +/
     size_t removeKey(U)(scope U[] elems)
-        if (isImplicitlyConvertible!(U, Elem))
+    if (isImplicitlyConvertible!(U, Elem))
     {
         immutable lenBefore = length;
 
@@ -1564,9 +1566,9 @@ assert(equal(rbt[], [5]));
 
     /++ Ditto +/
     size_t removeKey(Stuff)(Stuff stuff)
-        if (isInputRange!Stuff &&
-           isImplicitlyConvertible!(ElementType!Stuff, Elem) &&
-           !isDynamicArray!Stuff)
+    if (isInputRange!Stuff &&
+        isImplicitlyConvertible!(ElementType!Stuff, Elem) &&
+        !isDynamicArray!Stuff)
     {
         import std.array : array;
         //We use array in case stuff is a Range from this RedBlackTree - either
@@ -1873,7 +1875,8 @@ assert(equal(rbt[], [5]));
     /**
      * Constructor. Pass in a range of elements to initialize the tree with.
      */
-    this(Stuff)(Stuff stuff) if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem))
+    this(Stuff)(Stuff stuff)
+    if (isInputRange!Stuff && isImplicitlyConvertible!(ElementType!Stuff, Elem))
     {
         _setup();
         stableInsert(stuff);
diff --git a/libphobos/src/std/container/slist.d b/libphobos/src/std/container/slist.d
index 0b504b474a803c851caed34ed83b8cde6d164730..ef6fbf060f1681ba7f2daf97bff3aec4c955fc8d 100644
--- a/libphobos/src/std/container/slist.d
+++ b/libphobos/src/std/container/slist.d
@@ -182,7 +182,8 @@ if (!is(T == shared))
 /**
 Constructor taking a number of nodes
      */
-    this(U)(U[] values...) if (isImplicitlyConvertible!(U, T))
+    this(U)(U[] values...)
+    if (isImplicitlyConvertible!(U, T))
     {
         insertFront(values);
     }
diff --git a/libphobos/src/std/container/util.d b/libphobos/src/std/container/util.d
index cc273a24b718d45222a3677a1f8cfd1bf17e7470..0b883d06421b37877115b23926b45d1843ebf586 100644
--- a/libphobos/src/std/container/util.d
+++ b/libphobos/src/std/container/util.d
@@ -109,14 +109,14 @@ if (!is(Container))
     import std.traits : isDynamicArray;
 
     auto make(Range)(Range range)
-        if (!isDynamicArray!Range && isInputRange!Range && !isInfinite!Range)
+    if (!isDynamicArray!Range && isInputRange!Range && !isInfinite!Range)
     {
         import std.range : ElementType;
         return .make!(Container!(ElementType!Range, Args))(range);
     }
 
     auto make(T)(T[] items...)
-        if (!isInfinite!T)
+    if (!isInfinite!T)
     {
         return .make!(Container!(T, Args))(items);
     }
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 3aa73c68bf1b1a6da71356f21f63346b77fa9a52..9c9d8db236a4e05c990931887d748d4dbe6031ea 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -205,21 +205,21 @@ $(PRE $(I UnsignedInteger):
 template to(T)
 {
     T to(A...)(A args)
-        if (A.length > 0)
+    if (A.length > 0)
     {
         return toImpl!T(args);
     }
 
     // Fix https://issues.dlang.org/show_bug.cgi?id=6175
     T to(S)(ref S arg)
-        if (isStaticArray!S)
+    if (isStaticArray!S)
     {
         return toImpl!T(arg);
     }
 
     // Fix https://issues.dlang.org/show_bug.cgi?id=16108
     T to(S)(ref S arg)
-        if (isAggregateType!S && !isCopyable!S)
+    if (isAggregateType!S && !isCopyable!S)
     {
         return toImpl!T(arg);
     }
@@ -917,9 +917,22 @@ if (!is(S : T) &&
     auto result = ()@trusted{ return cast(T) value; }();
     if (!result && value)
     {
-        throw new ConvException("Cannot convert object of static type "
-                ~S.classinfo.name~" and dynamic type "~value.classinfo.name
-                ~" to type "~T.classinfo.name);
+        string name(TypeInfo ti) @trusted
+        {
+            while (auto tc = (cast(TypeInfo_Const) ti))
+            {
+                ti = tc.base;
+            }
+            if (auto tinf = cast(TypeInfo_Interface) ti)
+            {
+                ti = tinf.info;
+            }
+            TypeInfo_Class tc = cast(TypeInfo_Class) ti;
+            assert(tc);
+            return tc.name;
+        }
+        throw new ConvException("Cannot convert object of static type " ~
+                name(typeid(S)) ~ " and dynamic type " ~ name(typeid(value)) ~ " to type " ~ name(typeid(T)));
     }
     return result;
 }
diff --git a/libphobos/src/std/datetime/date.d b/libphobos/src/std/datetime/date.d
index c757b1e288096988cf0900b4d4e21fc2ebbf3910..0f417b15081e84bf3dc1c494549c7938a2b351f7 100644
--- a/libphobos/src/std/datetime/date.d
+++ b/libphobos/src/std/datetime/date.d
@@ -1075,7 +1075,7 @@ public:
       +/
     ref DateTime add(string units)
                     (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
-        if (units == "years" || units == "months")
+    if (units == "years" || units == "months")
     {
         _date.add!units(value, allowOverflow);
         return this;
@@ -1140,7 +1140,7 @@ public:
       +/
     ref DateTime roll(string units)
                      (long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe pure nothrow @nogc
-        if (units == "years" || units == "months")
+    if (units == "years" || units == "months")
     {
         _date.roll!units(value, allowOverflow);
         return this;
@@ -1209,7 +1209,7 @@ public:
             A reference to the `DateTime` (`this`).
       +/
     ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
-        if (units == "days")
+    if (units == "days")
     {
         _date.roll!"days"(value);
         return this;
@@ -1250,9 +1250,9 @@ public:
 
     /// ditto
     ref DateTime roll(string units)(long value) @safe pure nothrow @nogc
-        if (units == "hours" ||
-            units == "minutes" ||
-            units == "seconds")
+    if (units == "hours" ||
+        units == "minutes" ||
+        units == "seconds")
     {
         _tod.roll!units(value);
         return this;
@@ -2138,7 +2138,7 @@ public:
                        this $(LREF DateTime).
       +/
     DateTime opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         DateTime retval = this;
         immutable seconds = duration.total!"seconds";
@@ -2233,7 +2233,7 @@ public:
                        $(LREF DateTime).
       +/
     ref DateTime opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         import core.time : convert;
         import std.format : format;
@@ -2339,7 +2339,7 @@ public:
         )
       +/
     Duration opBinary(string op)(DateTime rhs) const @safe pure nothrow @nogc
-        if (op == "-")
+    if (op == "-")
     {
         immutable dateResult = _date - rhs.date;
         immutable todResult = _tod - rhs._tod;
@@ -3151,7 +3151,7 @@ public:
             be valid.
       +/
     static DateTime fromISOString(S)(scope const S isoString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.algorithm.searching : countUntil;
         import std.exception : enforce;
@@ -3252,7 +3252,7 @@ public:
             would not be valid.
       +/
     static DateTime fromISOExtString(S)(scope const S isoExtString) @safe pure
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : countUntil;
         import std.exception : enforce;
@@ -3353,7 +3353,7 @@ public:
             would not be valid.
       +/
     static DateTime fromSimpleString(S)(scope const S simpleString) @safe pure
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : countUntil;
         import std.exception : enforce;
@@ -4483,7 +4483,7 @@ public:
       +/
     @safe pure nothrow @nogc
     ref Date add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-        if (units == "years")
+    if (units == "years")
     {
         _year += value;
 
@@ -4724,7 +4724,7 @@ public:
     // Shares documentation with "years" version.
     @safe pure nothrow @nogc
     ref Date add(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-        if (units == "months")
+    if (units == "months")
     {
         auto years = months / 12;
         months %= 12;
@@ -5268,7 +5268,7 @@ public:
       +/
     @safe pure nothrow @nogc
     ref Date roll(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-        if (units == "years")
+    if (units == "years")
     {
         return add!"years"(value, allowOverflow);
     }
@@ -5313,7 +5313,7 @@ public:
     // Shares documentation with "years" version.
     @safe pure nothrow @nogc
     ref Date roll(string units)(long months, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-        if (units == "months")
+    if (units == "months")
     {
         months %= 12;
         auto newMonth = _month + months;
@@ -5910,7 +5910,7 @@ public:
             A reference to the `Date` (`this`).
       +/
     ref Date roll(string units)(long days) @safe pure nothrow @nogc
-        if (units == "days")
+    if (units == "days")
     {
         immutable limit = maxDay(_year, _month);
         days %= limit;
@@ -6148,7 +6148,7 @@ public:
                        this $(LREF Date).
       +/
     Date opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         Date retval = this;
         immutable days = duration.total!"days";
@@ -6238,7 +6238,7 @@ public:
                        this $(LREF Date).
       +/
     ref Date opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         immutable days = duration.total!"days";
         mixin("return _addDays(" ~ op ~ "days);");
@@ -6313,7 +6313,7 @@ public:
         )
       +/
     Duration opBinary(string op)(Date rhs) const @safe pure nothrow @nogc
-        if (op == "-")
+    if (op == "-")
     {
         import core.time : dur;
         return dur!"days"(this.dayOfGregorianCal - rhs.dayOfGregorianCal);
@@ -7621,7 +7621,7 @@ public:
             valid.
       +/
     static Date fromISOString(S)(scope const S isoString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.algorithm.searching : startsWith;
         import std.conv : to, text, ConvException;
@@ -7764,7 +7764,7 @@ public:
             would not be valid.
       +/
     static Date fromISOExtString(S)(scope const S isoExtString) @safe pure
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : startsWith;
         import std.conv : to, ConvException;
@@ -7902,7 +7902,7 @@ public:
             be valid.
       +/
     static Date fromSimpleString(S)(scope const S simpleString) @safe pure
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : startsWith;
         import std.conv : to, ConvException;
@@ -8606,7 +8606,7 @@ public:
             A reference to the `TimeOfDay` (`this`).
       +/
     ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
-        if (units == "hours")
+    if (units == "hours")
     {
         import core.time : dur;
         return this += dur!"hours"(value);
@@ -8655,7 +8655,7 @@ public:
 
     /// ditto
     ref TimeOfDay roll(string units)(long value) @safe pure nothrow @nogc
-        if (units == "minutes" || units == "seconds")
+    if (units == "minutes" || units == "seconds")
     {
         import std.format : format;
 
@@ -8851,7 +8851,7 @@ public:
                        this $(LREF TimeOfDay).
       +/
     TimeOfDay opBinary(string op)(Duration duration) const @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         TimeOfDay retval = this;
         immutable seconds = duration.total!"seconds";
@@ -8938,7 +8938,7 @@ public:
                        this $(LREF TimeOfDay).
       +/
     ref TimeOfDay opOpAssign(string op)(Duration duration) @safe pure nothrow @nogc
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         immutable seconds = duration.total!"seconds";
         mixin("return _addSeconds(" ~ op ~ "seconds);");
@@ -9004,7 +9004,7 @@ public:
             rhs = The $(LREF TimeOfDay) to subtract from this one.
       +/
     Duration opBinary(string op)(TimeOfDay rhs) const @safe pure nothrow @nogc
-        if (op == "-")
+    if (op == "-")
     {
         immutable lhsSec = _hour * 3600 + _minute * 60 + _second;
         immutable rhsSec = rhs._hour * 3600 + rhs._minute * 60 + rhs._second;
@@ -9201,7 +9201,7 @@ public:
             not be valid.
       +/
     static TimeOfDay fromISOString(S)(scope const S isoString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.conv : to, text, ConvException;
         import std.exception : enforce;
@@ -9326,7 +9326,7 @@ public:
             would not be valid.
       +/
     static TimeOfDay fromISOExtString(S)(scope const S isoExtString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.conv : ConvException, text, to;
         import std.string : strip;
diff --git a/libphobos/src/std/datetime/interval.d b/libphobos/src/std/datetime/interval.d
index d787e3a8080cc5e76c77b6e632b69657aa85cd10..832a2cb998a8de19c3676c89ae632cd4729cf0a4 100644
--- a/libphobos/src/std/datetime/interval.d
+++ b/libphobos/src/std/datetime/interval.d
@@ -137,7 +137,7 @@ public:
         --------------------
       +/
     this(U)(scope const TP begin, scope const U end) pure
-        if (is(immutable TP == immutable U))
+    if (is(immutable TP == immutable U))
     {
         if (!_valid(begin, end))
             throw new DateTimeException("Arguments would result in an invalid Interval.");
@@ -162,7 +162,7 @@ public:
         --------------------
       +/
     this(D)(scope const TP begin, scope const D duration) pure
-        if (__traits(compiles, begin + duration))
+    if (__traits(compiles, begin + duration))
     {
         _begin = cast(TP) begin;
         _end = begin + duration;
@@ -1118,7 +1118,7 @@ public:
         --------------------
       +/
     void shift(D)(D duration) pure
-        if (__traits(compiles, begin + duration))
+    if (__traits(compiles, begin + duration))
     {
         _enforceNotEmpty();
 
@@ -1168,7 +1168,7 @@ public:
             --------------------
           +/
         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-            if (isIntegral!T)
+        if (isIntegral!T)
         {
             _enforceNotEmpty();
 
@@ -1215,7 +1215,7 @@ public:
         --------------------
       +/
     void expand(D)(D duration, Direction dir = Direction.both) pure
-        if (__traits(compiles, begin + duration))
+    if (__traits(compiles, begin + duration))
     {
         _enforceNotEmpty();
 
@@ -3919,7 +3919,7 @@ assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
 --------------------
       +/
     void shift(D)(D duration) pure nothrow
-        if (__traits(compiles, begin + duration))
+    if (__traits(compiles, begin + duration))
     {
         _begin += duration;
     }
@@ -3960,7 +3960,7 @@ assert(interval2 == PosInfInterval!Date(Date(1995, 11, 13)));
 --------------------
           +/
         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-            if (isIntegral!T)
+        if (isIntegral!T)
         {
             auto begin = _begin;
 
@@ -3992,7 +3992,7 @@ assert(interval2 == PosInfInterval!Date(Date(1996, 1, 4)));
 --------------------
       +/
     void expand(D)(D duration) pure nothrow
-        if (__traits(compiles, begin + duration))
+    if (__traits(compiles, begin + duration))
     {
         _begin -= duration;
     }
@@ -4028,7 +4028,7 @@ assert(interval2 == PosInfInterval!Date(Date(1998, 1, 2)));
 --------------------
           +/
         void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-            if (isIntegral!T)
+        if (isIntegral!T)
         {
             auto begin = _begin;
 
@@ -6145,7 +6145,7 @@ assert(interval2 == NegInfInterval!Date( Date(2012, 2, 15)));
 --------------------
       +/
     void shift(D)(D duration) pure nothrow
-        if (__traits(compiles, end + duration))
+    if (__traits(compiles, end + duration))
     {
         _end += duration;
     }
@@ -6185,7 +6185,7 @@ assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
 --------------------
           +/
         void shift(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-            if (isIntegral!T)
+        if (isIntegral!T)
         {
             auto end = _end;
 
@@ -6217,7 +6217,7 @@ assert(interval2 == NegInfInterval!Date(Date(2012, 2, 28)));
 --------------------
       +/
     void expand(D)(D duration) pure nothrow
-        if (__traits(compiles, end + duration))
+    if (__traits(compiles, end + duration))
     {
         _end += duration;
     }
@@ -6253,7 +6253,7 @@ assert(interval2 == NegInfInterval!Date(Date(2010, 3, 1)));
 --------------------
           +/
         void expand(T)(T years, T months = 0, AllowDayOverflow allowOverflow = AllowDayOverflow.yes)
-            if (isIntegral!T)
+        if (isIntegral!T)
         {
             auto end = _end;
 
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index a2e52aebac5db537d6e4ffd01077e049688e42db..fd2a9e192e4278d05b9fa02931c4ee97fb1fa65a 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -2444,7 +2444,7 @@ public:
             this SysTime.
       +/
     T toUnixTime(T = time_t)() @safe const pure nothrow scope
-        if (is(T == int) || is(T == long))
+    if (is(T == int) || is(T == long))
     {
         return stdTimeToUnixTime!T(_stdTime);
     }
@@ -2792,7 +2792,7 @@ public:
                             causing the month to increment.
       +/
     ref SysTime add(string units)(long value, AllowDayOverflow allowOverflow = AllowDayOverflow.yes) @safe nothrow scope
-        if (units == "years" || units == "months")
+    if (units == "years" || units == "months")
     {
         auto hnsecs = adjTime;
         auto days = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
@@ -4830,7 +4830,7 @@ public:
                     $(LREF SysTime).
       +/
     ref SysTime roll(string units)(long value) @safe nothrow scope
-        if (units == "days")
+    if (units == "days")
     {
         auto hnsecs = adjTime;
         auto gdays = splitUnitsFromHNSecs!"days"(hnsecs) + 1;
@@ -5195,7 +5195,7 @@ public:
 
     // Shares documentation with "days" version.
     ref SysTime roll(string units)(long value) @safe nothrow scope
-        if (units == "hours" || units == "minutes" || units == "seconds")
+    if (units == "hours" || units == "minutes" || units == "seconds")
     {
         try
         {
@@ -5871,7 +5871,7 @@ public:
 
     // Shares documentation with "days" version.
     ref SysTime roll(string units)(long value) @safe nothrow scope
-        if (units == "msecs" || units == "usecs" || units == "hnsecs")
+    if (units == "msecs" || units == "usecs" || units == "hnsecs")
     {
         auto hnsecs = adjTime;
         immutable days = splitUnitsFromHNSecs!"days"(hnsecs);
@@ -6308,7 +6308,7 @@ public:
                        this $(LREF SysTime).
       +/
     SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         SysTime retval = SysTime(this._stdTime, this._timezone);
         immutable hnsecs = duration.total!"hnsecs";
@@ -6528,7 +6528,7 @@ public:
                        this $(LREF SysTime).
       +/
     ref SysTime opOpAssign(string op)(Duration duration) @safe pure nothrow scope
-        if (op == "+" || op == "-")
+    if (op == "+" || op == "-")
     {
         immutable hnsecs = duration.total!"hnsecs";
         mixin("_stdTime " ~ op ~ "= hnsecs;");
@@ -6732,7 +6732,7 @@ public:
         )
       +/
     Duration opBinary(string op)(SysTime rhs) @safe const pure nothrow scope
-        if (op == "-")
+    if (op == "-")
     {
         return dur!"hnsecs"(_stdTime - rhs._stdTime);
     }
@@ -7992,7 +7992,7 @@ public:
         Returns a $(REF Date,std,datetime,date) equivalent to this $(LREF SysTime).
       +/
     Date opCast(T)() @safe const nothrow scope
-        if (is(immutable T == immutable Date))
+    if (is(immutable T == immutable Date))
     {
         return Date(dayOfGregorianCal);
     }
@@ -8033,7 +8033,7 @@ public:
         $(LREF SysTime).
       +/
     DateTime opCast(T)() @safe const nothrow scope
-        if (is(immutable T == immutable DateTime))
+    if (is(immutable T == immutable DateTime))
     {
         try
         {
@@ -8099,7 +8099,7 @@ public:
         $(LREF SysTime).
       +/
     TimeOfDay opCast(T)() @safe const nothrow scope
-        if (is(immutable T == immutable TimeOfDay))
+    if (is(immutable T == immutable TimeOfDay))
     {
         try
         {
@@ -8156,7 +8156,7 @@ public:
     // should be allowed, and it doesn't work without this opCast() since opCast()
     // has already been defined for other types.
     SysTime opCast(T)() @safe const pure nothrow scope
-        if (is(immutable T == immutable SysTime))
+    if (is(immutable T == immutable SysTime))
     {
         return SysTime(_stdTime, _timezone);
     }
@@ -8799,7 +8799,7 @@ public:
             be valid.
       +/
     static SysTime fromISOString(S)(scope const S isoString, immutable TimeZone tz = null) @safe
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.algorithm.searching : startsWith, find;
         import std.conv : to;
@@ -9100,7 +9100,7 @@ public:
             be valid.
       +/
     static SysTime fromISOExtString(S)(scope const S isoExtString, immutable TimeZone tz = null) @safe
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : countUntil, find;
         import std.conv : to;
@@ -9351,7 +9351,7 @@ public:
             be valid.
       +/
     static SysTime fromSimpleString(S)(scope const S simpleString, immutable TimeZone tz = null) @safe
-        if (isSomeString!(S))
+    if (isSomeString!(S))
     {
         import std.algorithm.searching : find;
         import std.conv : to;
diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d
index 4b6f27d066d5517bead165f353bd7f5cd91a63b6..6a1898b0ef50c90b6acda4b8ecd5447dcd3c3abd 100644
--- a/libphobos/src/std/datetime/timezone.d
+++ b/libphobos/src/std/datetime/timezone.d
@@ -1550,7 +1550,7 @@ package:
             isoString = A string which represents a time zone in the ISO format.
       +/
     static immutable(SimpleTimeZone) fromISOString(S)(S isoString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.algorithm.searching : startsWith;
         import std.conv : text, to, ConvException;
@@ -1704,7 +1704,7 @@ package:
             isoExtString = A string which represents a time zone in the ISO format.
       +/
     static immutable(SimpleTimeZone) fromISOExtString(S)(scope S isoExtString) @safe pure
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         import std.algorithm.searching : startsWith;
         import std.conv : ConvException, to;
@@ -2642,7 +2642,7 @@ private:
         Reads an int from a TZ file.
       +/
     static T readVal(T)(ref File tzFile) @trusted
-        if ((isIntegral!T || isSomeChar!T) || is(immutable T == immutable bool))
+    if ((isIntegral!T || isSomeChar!T) || is(immutable T == immutable bool))
     {
         import std.bitmanip : bigEndianToNative;
         T[1] buff;
@@ -2657,7 +2657,7 @@ private:
         Reads an array of values from a TZ file.
       +/
     static T readVal(T)(ref File tzFile, size_t length) @trusted
-        if (isArray!T)
+    if (isArray!T)
     {
         auto buff = new T(length);
 
@@ -2672,7 +2672,7 @@ private:
         Reads a `TempTTInfo` from a TZ file.
       +/
     static T readVal(T)(ref File tzFile) @safe
-        if (is(T == TempTTInfo))
+    if (is(T == TempTTInfo))
     {
         return TempTTInfo(readVal!int(tzFile),
                           readVal!bool(tzFile),
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index c3024d799686d35c5edb54cc83f3270493ec6d30..9b1a7c8a62cedbd7c9835bd4be15b2114f615157 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -1801,7 +1801,7 @@ expression.
 @system unittest
 {
     import std.format : format;
-    assert("%s".format.ifThrown!Exception(e => e.classinfo.name) == "std.format.FormatException");
+    assert("%s".format.ifThrown!Exception(e => typeid(e).name) == "std.format.FormatException");
 }
 
 //Verify Examples
@@ -1834,7 +1834,7 @@ expression.
     static assert(!__traits(compiles, (new Object()).ifThrown(1)));
 
     //Use a lambda to get the thrown object.
-    assert("%s".format().ifThrown(e => e.classinfo.name) == "std.format.FormatException");
+    assert("%s".format().ifThrown(e => typeid(e).name) == "std.format.FormatException");
 }
 
 @system unittest
diff --git a/libphobos/src/std/experimental/allocator/common.d b/libphobos/src/std/experimental/allocator/common.d
index d2efe338d7b79b128367124244ea7e448464e0c0..b06fb627d71fa0905789c66c2b7684d2eac6eed1 100644
--- a/libphobos/src/std/experimental/allocator/common.d
+++ b/libphobos/src/std/experimental/allocator/common.d
@@ -66,6 +66,39 @@ unittest
     static assert(stateSize!C3 == 2 * size_t.sizeof + char.sizeof);
 }
 
+/**
+State of an allocator `A`.
+
+`AllocatorState!(A).sizeof` is zero for `A` being `NullAllocator`, `Mallocator`,
+`GCAllocator`, and `MMapAllocator` and typically non-zero for the other.
+ */
+mixin template AllocatorState(A)
+if (isAllocator!A)
+{
+    static if (stateSize!A == 0)
+        alias allocator = A.instance;
+    else
+        A allocator;
+}
+
+///
+@safe @nogc nothrow pure
+unittest
+{
+    import std.experimental.allocator.building_blocks.null_allocator : NullAllocator;
+    import std.experimental.allocator.mallocator : Mallocator;
+    import std.experimental.allocator.gc_allocator : GCAllocator;
+    import std.experimental.allocator.mmap_allocator : MmapAllocator;
+    struct S
+    {
+        mixin AllocatorState!NullAllocator n;
+        mixin AllocatorState!GCAllocator g;
+        mixin AllocatorState!Mallocator m;
+        mixin AllocatorState!MmapAllocator p;
+    }
+    static assert(S.sizeof == 1);
+}
+
 /**
 Returns `true` if the `Allocator` has the alignment known at compile time;
 otherwise it returns `false`.
diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d
index 087dbec449a56eb49edbee7c59cd9f7cade663e9..fbe936644f1d0bbbbf224a15a7c3831f1b1434d7 100644
--- a/libphobos/src/std/experimental/allocator/mallocator.d
+++ b/libphobos/src/std/experimental/allocator/mallocator.d
@@ -118,9 +118,9 @@ struct Mallocator
 
 version (CRuntime_Microsoft)
 {
-    @nogc nothrow private extern(C) void* _aligned_malloc(size_t, size_t);
-    @nogc nothrow private extern(C) void _aligned_free(void *memblock);
-    @nogc nothrow private extern(C) void* _aligned_realloc(void *, size_t, size_t);
+    @nogc nothrow pure private extern(C) void* _aligned_malloc(size_t, size_t);
+    @nogc nothrow pure private extern(C) void _aligned_free(void *memblock);
+    @nogc nothrow pure private extern(C) void* _aligned_realloc(void *, size_t, size_t);
 }
 
 /**
@@ -138,7 +138,7 @@ struct AlignedMallocator
     /**
     Forwards to $(D alignedAllocate(bytes, platformAlignment)).
     */
-    @trusted @nogc nothrow
+    @trusted @nogc nothrow pure
     void[] allocate(size_t bytes) shared
     {
         if (!bytes) return null;
@@ -152,7 +152,7 @@ struct AlignedMallocator
     `__aligned_malloc`) on Windows.
     */
     version (Posix)
-    @trusted @nogc nothrow
+    @trusted @nogc nothrow pure
     void[] alignedAllocate(size_t bytes, uint a) shared
     {
         import core.stdc.errno : ENOMEM, EINVAL;
@@ -184,7 +184,7 @@ version (LDC_AddressSanitizer)
             return result[0 .. bytes];
     }
     else version (Windows)
-    @trusted @nogc nothrow
+    @trusted @nogc nothrow pure
     void[] alignedAllocate(size_t bytes, uint a) shared
     {
         auto result = _aligned_malloc(bytes, a);
@@ -198,15 +198,15 @@ version (LDC_AddressSanitizer)
     `__aligned_free(b.ptr)`) on Windows.
     */
     version (Posix)
-    @system @nogc nothrow
+    @system @nogc nothrow pure
     bool deallocate(void[] b) shared
     {
-        import core.stdc.stdlib : free;
-        free(b.ptr);
+        import core.memory : pureFree;
+        pureFree(b.ptr);
         return true;
     }
     else version (Windows)
-    @system @nogc nothrow
+    @system @nogc nothrow pure
     bool deallocate(void[] b) shared
     {
         _aligned_free(b.ptr);
@@ -219,7 +219,7 @@ version (LDC_AddressSanitizer)
     Should be used with blocks obtained with `allocate` otherwise the custom
     alignment passed with `alignedAllocate` can be lost.
     */
-    @system @nogc nothrow
+    @system @nogc nothrow pure
     bool reallocate(ref void[] b, size_t newSize) shared
     {
         return alignedReallocate(b, newSize, alignment);
@@ -233,7 +233,7 @@ version (LDC_AddressSanitizer)
     $(D __aligned_realloc(b.ptr, newSize, a))).
     */
     version (Windows)
-    @system @nogc nothrow
+    @system @nogc nothrow pure
     bool alignedReallocate(ref void[] b, size_t s, uint a) shared
     {
         if (!s)
@@ -250,7 +250,7 @@ version (LDC_AddressSanitizer)
 
     /// ditto
     version (Posix)
-    @system @nogc nothrow
+    @system @nogc nothrow pure
     bool alignedReallocate(ref void[] b, size_t s, uint a) shared
     {
         if (!s)
@@ -281,7 +281,7 @@ version (LDC_AddressSanitizer)
 }
 
 ///
-@nogc @system nothrow unittest
+pure @nogc @system nothrow unittest
 {
     auto buffer = AlignedMallocator.instance.alignedAllocate(1024 * 1024 * 4,
         128);
@@ -290,7 +290,7 @@ version (LDC_AddressSanitizer)
 }
 
 version (Posix)
-@nogc @system nothrow unittest
+pure @nogc @system nothrow unittest
 {
     // https://issues.dlang.org/show_bug.cgi?id=16398
     // test the "pseudo" alignedReallocate for Posix
diff --git a/libphobos/src/std/file.d b/libphobos/src/std/file.d
index 2a0d1392c0884ac017afefc7874d538bf80da8f0..c3466acc05539f94a2d3a586bd923ad984c2244f 100644
--- a/libphobos/src/std/file.d
+++ b/libphobos/src/std/file.d
@@ -4794,7 +4794,7 @@ private struct DirIteratorImpl
     }
 
     this(R)(R pathname, SpanMode mode, bool followSymlink)
-        if (isSomeFiniteCharInputRange!R)
+    if (isSomeFiniteCharInputRange!R)
     {
         _mode = mode;
         _followSymlink = followSymlink;
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 16c7a51d8c6e114e6ec89e5bac81333b8f8927af..8b60565d8a17177b2bfd83da430d98dcb793e11f 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -1935,7 +1935,8 @@ template hasToString(T, Char)
     static struct G
     {
         string toString() {return "";}
-        void toString(Writer)(ref Writer w) if (isOutputRange!(Writer, string)) {}
+        void toString(Writer)(ref Writer w)
+        if (isOutputRange!(Writer, string)) {}
     }
     static struct H
     {
@@ -1946,7 +1947,8 @@ template hasToString(T, Char)
     }
     static struct I
     {
-        void toString(Writer)(ref Writer w) if (isOutputRange!(Writer, string)) {}
+        void toString(Writer)(ref Writer w)
+        if (isOutputRange!(Writer, string)) {}
         void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt)
         if (isOutputRange!(Writer, string))
         {}
@@ -2042,7 +2044,8 @@ template hasToString(T, Char)
     static struct G
     {
         string toString() const {return "";}
-        void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+        void toString(Writer)(ref Writer w) const
+        if (isOutputRange!(Writer, string)) {}
     }
     static struct H
     {
@@ -2053,7 +2056,8 @@ template hasToString(T, Char)
     }
     static struct I
     {
-        void toString(Writer)(ref Writer w) const if (isOutputRange!(Writer, string)) {}
+        void toString(Writer)(ref Writer w) const
+        if (isOutputRange!(Writer, string)) {}
         void toString(Writer)(ref Writer w, scope const ref FormatSpec!char fmt) const
         if (isOutputRange!(Writer, string))
         {}
@@ -2603,7 +2607,8 @@ if ((is(T == struct) || is(T == union)) && (hasToString!(T, Char) || !is(Builtin
     {
         int n = 0;
         alias n this;
-        T opCast(T) () if (is(T == Frop))
+        T opCast(T) ()
+        if (is(T == Frop))
         {
             return Frop();
         }
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index 588a9c8a54785e046efbb040fe7bc65cabb7cb9e..5022702ace90656b830174622edce17c8af8fbce 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -445,7 +445,7 @@ if (S=="<"||S==">"||S=="<="||S==">="||S=="=="||S=="!=")
 {
     import std.traits : isIntegral;
     private bool unsafeOp(ElementType1, ElementType2)(ElementType1 a, ElementType2 b) pure
-        if (isIntegral!ElementType1 && isIntegral!ElementType2)
+    if (isIntegral!ElementType1 && isIntegral!ElementType2)
     {
         import std.traits : CommonType;
         alias T = CommonType!(ElementType1, ElementType2);
diff --git a/libphobos/src/std/int128.d b/libphobos/src/std/int128.d
index 92895445aedcaaec58a7f937387dbe32faaa4bbc..c5569152bbdd55a7c00ef4284cdbe048c8323ce1 100644
--- a/libphobos/src/std/int128.d
+++ b/libphobos/src/std/int128.d
@@ -111,7 +111,7 @@ public struct Int128
      * Returns: lvalue of result
      */
     Int128 opUnary(string op)() const
-        if (op == "+")
+    if (op == "+")
     {
         return this;
     }
@@ -121,7 +121,7 @@ public struct Int128
      * Returns: lvalue of result
      */
     Int128 opUnary(string op)() const
-        if (op == "-" || op == "~")
+    if (op == "-" || op == "~")
     {
         static if (op == "-")
             return Int128(neg(this.data));
@@ -134,7 +134,7 @@ public struct Int128
      * Returns: lvalue of result
      */
     Int128 opUnary(string op)()
-        if (op == "++" || op == "--")
+    if (op == "++" || op == "--")
     {
         static if (op == "++")
             this.data = inc(this.data);
@@ -206,9 +206,9 @@ public struct Int128
      * Returns: value after the operation is applied
      */
     Int128 opBinary(string op)(Int128 op2) const
-        if (op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^")
+    if (op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^")
     {
         static if (op == "+")
             return Int128(add(this.data, op2.data));
@@ -236,10 +236,10 @@ public struct Int128
 
     /// ditto
     Int128 opBinary(string op, Int)(const Int op2) const
-        if ((op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^") &&
-            is(Int : long) && __traits(isIntegral, Int))
+    if ((op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^") &&
+        is(Int : long) && __traits(isIntegral, Int))
     {
         static if (__traits(isUnsigned, Int))
             return mixin("this " ~ op ~ " Int128(0, op2)");
@@ -249,20 +249,20 @@ public struct Int128
 
     /// ditto
     Int128 opBinary(string op, IntLike)(auto ref IntLike op2) const
-        if ((op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^") &&
-            is(IntLike : long) && !__traits(isIntegral, IntLike))
+    if ((op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^") &&
+        is(IntLike : long) && !__traits(isIntegral, IntLike))
     {
         return opBinary!(op)(__traits(getMember, op2, __traits(getAliasThis, IntLike)[0]));
     }
 
     /// ditto
     Int128 opBinaryRight(string op, Int)(const Int op2) const
-        if ((op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^") &&
-            is(Int : long) && __traits(isIntegral, Int))
+    if ((op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^") &&
+        is(Int : long) && __traits(isIntegral, Int))
     {
         static if (__traits(isUnsigned, Int))
             mixin("return Int128(0, op2) " ~ op ~ " this;");
@@ -272,31 +272,31 @@ public struct Int128
 
     /// ditto
     Int128 opBinaryRight(string op, IntLike)(auto ref IntLike op2) const
-        if ((op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^") &&
-            is(IntLike : long) && !__traits(isIntegral, IntLike))
+    if ((op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^") &&
+        is(IntLike : long) && !__traits(isIntegral, IntLike))
     {
         return opBinaryRight!(op)(__traits(getMember, op2, __traits(getAliasThis, IntLike)[0]));
     }
 
     /// ditto
     Int128 opBinary(string op)(long op2) const
-        if (op == "<<")
+    if (op == "<<")
     {
         return Int128(shl(this.data, cast(uint) op2));
     }
 
     /// ditto
     Int128 opBinary(string op)(long op2) const
-        if (op == ">>")
+    if (op == ">>")
     {
         return Int128(sar(this.data, cast(uint) op2));
     }
 
     /// ditto
     Int128 opBinary(string op)(long op2) const
-        if (op == ">>>")
+    if (op == ">>>")
     {
         return Int128(shr(this.data, cast(uint) op2));
     }
@@ -307,10 +307,10 @@ public struct Int128
      * Returns: lvalue of updated left operand
      */
     ref Int128 opOpAssign(string op)(Int128 op2)
-        if (op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^" ||
-            op == "<<" || op == ">>" || op == ">>>")
+    if (op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^" ||
+        op == "<<" || op == ">>" || op == ">>>")
     {
         mixin("this = this " ~ op ~ " op2;");
         return this;
@@ -318,11 +318,11 @@ public struct Int128
 
     /// ditto
     ref Int128 opOpAssign(string op, Int)(auto ref Int op2)
-        if ((op == "+" || op == "-" ||
-            op == "*" || op == "/" || op == "%" ||
-            op == "&" || op == "|" || op == "^" ||
-            op == "<<" || op == ">>" || op == ">>>")
-            && is(Int : long))
+    if ((op == "+" || op == "-" ||
+        op == "*" || op == "/" || op == "%" ||
+        op == "&" || op == "|" || op == "^" ||
+        op == "<<" || op == ">>" || op == ">>>")
+        && is(Int : long))
     {
         mixin("this = this " ~ op ~ " op2;");
         return this;
diff --git a/libphobos/src/std/internal/math/biguintcore.d b/libphobos/src/std/internal/math/biguintcore.d
index 9df6bb22274ff06585b90120a025bd39c5bac76d..9c794b60de1220ac52ec20bad22efaa563ddb405 100644
--- a/libphobos/src/std/internal/math/biguintcore.d
+++ b/libphobos/src/std/internal/math/biguintcore.d
@@ -250,7 +250,8 @@ private:
        data = x;
     }
   package(std)  // used from: std.bigint
-    this(T)(T x) pure nothrow @safe scope if (isIntegral!T)
+    this(T)(T x) pure nothrow @safe scope
+    if (isIntegral!T)
     {
         opAssign(x);
     }
@@ -312,7 +313,8 @@ public:
     }
 
     ///
-    void opAssign(Tulong)(Tulong u) pure nothrow @safe scope if (is (Tulong == ulong))
+    void opAssign(Tulong)(Tulong u) pure nothrow @safe scope
+    if (is (Tulong == ulong))
     {
         if (u == 0) data = ZERO;
         else if (u == 1) data = ONE;
@@ -356,7 +358,8 @@ public:
     }
 
     ///
-    int opCmp(Tulong)(Tulong y) pure nothrow @nogc const @safe scope if (is (Tulong == ulong))
+    int opCmp(Tulong)(Tulong y) pure nothrow @nogc const @safe scope
+    if (is (Tulong == ulong))
     {
         if (data.length > maxBigDigits!Tulong)
             return 1;
@@ -501,8 +504,8 @@ public:
     }
 
     // return false if invalid character found
-    bool fromHexString(Range)(Range s) scope if (
-        isBidirectionalRange!Range && isSomeChar!(ElementType!Range))
+    bool fromHexString(Range)(Range s) scope
+    if (isBidirectionalRange!Range && isSomeChar!(ElementType!Range))
     {
         import std.range : walkLength;
 
@@ -570,8 +573,8 @@ public:
     }
 
     // return true if OK; false if erroneous characters found
-    bool fromDecimalString(Range)(Range s) scope if (
-        isForwardRange!Range && isSomeChar!(ElementType!Range))
+    bool fromDecimalString(Range)(Range s) scope
+    if (isForwardRange!Range && isSomeChar!(ElementType!Range))
     {
         import std.range : walkLength;
 
@@ -596,9 +599,9 @@ public:
     }
 
     void fromMagnitude(Range)(Range magnitude) scope
-        if (isInputRange!Range
-            && (isForwardRange!Range || hasLength!Range)
-            && isUnsigned!(ElementType!Range))
+    if (isInputRange!Range
+        && (isForwardRange!Range || hasLength!Range)
+        && isUnsigned!(ElementType!Range))
     {
         while (!magnitude.empty && magnitude.front == 0)
             magnitude.popFront;
@@ -711,7 +714,7 @@ public:
 
     // return x >> y
     BigUint opBinary(string op, Tulong)(Tulong y) pure nothrow @safe const return scope
-        if (op == ">>" && is (Tulong == ulong))
+    if (op == ">>" && is (Tulong == ulong))
     {
         assert(y > 0, "Can not right shift BigUint by 0");
         uint bits = cast(uint) y & BIGDIGITSHIFTMASK;
@@ -735,7 +738,7 @@ public:
 
     // return x << y
     BigUint opBinary(string op, Tulong)(Tulong y) pure nothrow @safe const scope
-        if (op == "<<" && is (Tulong == ulong))
+    if (op == "<<" && is (Tulong == ulong))
     {
         assert(y > 0, "Can not left shift BigUint by 0");
         if (isZero()) return this;
@@ -761,8 +764,8 @@ public:
 
     // If wantSub is false, return x + y, leaving sign unchanged
     // If wantSub is true, return abs(x - y), negating sign if x < y
-    static BigUint addOrSubInt(Tulong)(const scope BigUint x, Tulong y,
-            bool wantSub, ref bool sign) pure nothrow @safe if (is(Tulong == ulong))
+    static BigUint addOrSubInt(Tulong)(const scope BigUint x, Tulong y, bool wantSub, ref bool sign) pure nothrow @safe
+    if (is(Tulong == ulong))
     {
         BigUint r;
         if (wantSub)
@@ -921,7 +924,8 @@ public:
     }
 
     // return x % y
-    static uint modInt(T)(scope BigUint x, T y_) pure if ( is(immutable T == immutable uint) )
+    static uint modInt(T)(scope BigUint x, T y_) pure
+    if ( is(immutable T == immutable uint) )
     {
         import core.memory : GC;
         uint y = y_;
@@ -994,7 +998,8 @@ public:
 
     // return x op y
     static BigUint bitwiseOp(string op)(scope BigUint x, scope BigUint y, bool xSign, bool ySign, ref bool resultSign)
-    pure nothrow @safe if (op == "|" || op == "^" || op == "&")
+    pure nothrow @safe
+    if (op == "|" || op == "^" || op == "&")
     {
         auto d1 = includeSign(x.data, y.uintLength, xSign);
         auto d2 = includeSign(y.data, x.uintLength, ySign);
diff --git a/libphobos/src/std/internal/test/dummyrange.d b/libphobos/src/std/internal/test/dummyrange.d
index e07e27510214f82cd051fb4e1010c8b84e316918..42dc2646d872f73a30010d1051836b65edc554d1 100644
--- a/libphobos/src/std/internal/test/dummyrange.d
+++ b/libphobos/src/std/internal/test/dummyrange.d
@@ -255,10 +255,11 @@ class ReferenceInputRange(T)
 {
     import std.array : array;
 
-    this(Range)(Range r) if (isInputRange!Range) {_payload = array(r);}
-    final @property ref T front(){return _payload.front;}
-    final void popFront(){_payload.popFront();}
-    final @property bool empty(){return _payload.empty;}
+    this(Range)(Range r)
+    if (isInputRange!Range) {_payload = array(r);}
+    final @property ref T front() {return _payload.front;}
+    final void popFront() {_payload.popFront();}
+    final @property bool empty() {return _payload.empty;}
     protected T[] _payload;
 }
 
@@ -268,8 +269,8 @@ Infinite input range
 class ReferenceInfiniteInputRange(T)
 {
     this(T first = T.init) {_val = first;}
-    final @property T front(){return _val;}
-    final void popFront(){++_val;}
+    final @property T front() {return _val;}
+    final void popFront() {++_val;}
     enum bool empty = false;
     protected T _val;
 }
@@ -279,7 +280,8 @@ Reference forward range
 */
 class ReferenceForwardRange(T) : ReferenceInputRange!T
 {
-    this(Range)(Range r) if (isInputRange!Range) {super(r);}
+    this(Range)(Range r)
+    if (isInputRange!Range) {super(r);}
     final @property auto save(this This)() {return new This( _payload);}
 }
 
@@ -298,9 +300,10 @@ Reference bidirectional range
 */
 class ReferenceBidirectionalRange(T) : ReferenceForwardRange!T
 {
-    this(Range)(Range r) if (isInputRange!Range) {super(r);}
-    final @property ref T back(){return _payload.back;}
-    final void popBack(){_payload.popBack();}
+    this(Range)(Range r)
+    if (isInputRange!Range) {super(r);}
+    final @property ref T back() {return _payload.back;}
+    final void popBack() {_payload.popBack();}
 }
 
 @safe unittest
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index 9dcec89b2cea71ae359e2bcbed273646ad71ae46..7182f6ee80720f676d759f4ba47c9e987508a6a8 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -85,6 +85,7 @@ enum JSONOptions
     escapeNonAsciiChars = 0x2,  /// Encode non-ASCII characters with a Unicode escape sequence
     doNotEscapeSlashes = 0x4,   /// Do not escape slashes ('/')
     strictParsing = 0x8,        /// Strictly follow RFC-8259 grammar when parsing
+    preserveObjectOrder = 0x16, /// Preserve order of object keys when parsing
 }
 
 /**
@@ -126,13 +127,30 @@ struct JSONValue
 {
     import std.exception : enforce;
 
+    import std.typecons : Tuple;
+
+    alias OrderedObjectMember = Tuple!(
+        string, "key",
+        JSONValue, "value",
+    );
+
     union Store
     {
+        struct Object
+        {
+            bool isOrdered;
+            union
+            {
+                JSONValue[string] unordered;
+                OrderedObjectMember[] ordered;
+            }
+        }
+
         string                          str;
         long                            integer;
         ulong                           uinteger;
         double                          floating;
-        JSONValue[string]               object;
+        Object                          object;
         JSONValue[]                     array;
     }
     private Store store;
@@ -272,9 +290,9 @@ struct JSONValue
     }
 
     /***
-     * Value getter/setter for `JSONType.object`.
+     * Value getter/setter for unordered `JSONType.object`.
      * Throws: `JSONException` for read access if `type` is not
-     * `JSONType.object`.
+     * `JSONType.object` or the object is ordered.
      * Note: This is @system because of the following pattern:
        ---
        auto a = &(json.object());
@@ -286,7 +304,9 @@ struct JSONValue
     {
         enforce!JSONException(type == JSONType.object,
                                 "JSONValue is not an object");
-        return store.object;
+        enforce!JSONException(!store.object.isOrdered,
+                                "JSONValue object is ordered, cannot return by ref");
+        return store.object.unordered;
     }
     /// ditto
     @property JSONValue[string] object(return scope JSONValue[string] v) pure nothrow @nogc @trusted // TODO make @safe
@@ -296,7 +316,7 @@ struct JSONValue
     }
 
     /***
-     * Value getter for `JSONType.object`.
+     * Value getter for unordered `JSONType.object`.
      * Unlike `object`, this retrieves the object by value
      * and can be used in @safe code.
      *
@@ -316,7 +336,71 @@ struct JSONValue
     {
         enforce!JSONException(type == JSONType.object,
                                 "JSONValue is not an object");
-        return store.object;
+        if (store.object.isOrdered)
+        {
+            // Convert to unordered
+            JSONValue[string] result;
+            foreach (pair; store.object.ordered)
+                result[pair.key] = pair.value;
+            return cast(inout) result;
+        }
+        else
+            return store.object.unordered;
+    }
+
+    /***
+     * Value getter/setter for ordered `JSONType.object`.
+     * Throws: `JSONException` for read access if `type` is not
+     * `JSONType.object` or the object is unordered.
+     * Note: This is @system because of the following pattern:
+       ---
+       auto a = &(json.orderedObject());
+       json.uinteger = 0;        // overwrite AA pointer
+       (*a)["hello"] = "world";  // segmentation fault
+       ---
+     */
+    @property ref inout(OrderedObjectMember[]) orderedObject() inout pure @system return
+    {
+        enforce!JSONException(type == JSONType.object,
+                                "JSONValue is not an object");
+        enforce!JSONException(store.object.isOrdered,
+                                "JSONValue object is unordered, cannot return by ref");
+        return store.object.ordered;
+    }
+    /// ditto
+    @property OrderedObjectMember[] orderedObject(return scope OrderedObjectMember[] v) pure nothrow @nogc @trusted // TODO make @safe
+    {
+        assign(v);
+        return v;
+    }
+
+    /***
+     * Value getter for ordered `JSONType.object`.
+     * Unlike `orderedObject`, this retrieves the object by value
+     * and can be used in @safe code.
+     */
+    @property inout(OrderedObjectMember[]) orderedObjectNoRef() inout pure @trusted
+    {
+        enforce!JSONException(type == JSONType.object,
+                                "JSONValue is not an object");
+        if (store.object.isOrdered)
+            return store.object.ordered;
+        else
+        {
+            // Convert to ordered
+            OrderedObjectMember[] result;
+            foreach (key, value; store.object.unordered)
+                result ~= OrderedObjectMember(key, value);
+            return cast(inout) result;
+        }
+    }
+
+    /// Returns `true` if the order of keys of the represented object is being preserved.
+    @property bool isOrdered() const pure @trusted
+    {
+        enforce!JSONException(type == JSONType.object,
+                                "JSONValue is not an object");
+        return store.object.isOrdered;
     }
 
     /***
@@ -517,16 +601,30 @@ struct JSONValue
             static if (is(Value : JSONValue))
             {
                 JSONValue[string] t = arg;
-                () @trusted { store.object = t; }();
+                () @trusted {
+                    store.object.isOrdered = false;
+                    store.object.unordered = t;
+                }();
             }
             else
             {
                 JSONValue[string] aa;
                 foreach (key, value; arg)
                     aa[key] = JSONValue(value);
-                () @trusted { store.object = aa; }();
+                () @trusted {
+                    store.object.isOrdered = false;
+                    store.object.unordered = aa;
+                }();
             }
         }
+        else static if (is(T : OrderedObjectMember[]))
+        {
+            type_tag = JSONType.object;
+            () @trusted {
+                store.object.isOrdered = true;
+                store.object.ordered = arg;
+            }();
+        }
         else static if (isArray!T)
         {
             type_tag = JSONType.array;
@@ -554,7 +652,8 @@ struct JSONValue
         }
     }
 
-    private void assignRef(T)(ref T arg) if (isStaticArray!T)
+    private void assignRef(T)(ref T arg)
+    if (isStaticArray!T)
     {
         type_tag = JSONType.array;
         static if (is(ElementEncodingType!T : JSONValue))
@@ -582,12 +681,14 @@ struct JSONValue
      * and `K` i.e. a JSON object, any array or `bool`. The type will
      * be set accordingly.
      */
-    this(T)(T arg) if (!isStaticArray!T)
+    this(T)(T arg)
+    if (!isStaticArray!T)
     {
         assign(arg);
     }
     /// Ditto
-    this(T)(ref T arg) if (isStaticArray!T)
+    this(T)(ref T arg)
+    if (isStaticArray!T)
     {
         assignRef(arg);
     }
@@ -629,6 +730,33 @@ struct JSONValue
         assert(obj1 != obj2);
     }
 
+    /**
+     * An enum value that can be used to obtain a `JSONValue` representing
+     * an empty JSON object.
+     * Unlike `emptyObject`, the order of inserted keys is preserved.
+     */
+    enum emptyOrderedObject = {
+        JSONValue v = void;
+        v.orderedObject = null;
+        return v;
+    }();
+    ///
+    @system unittest
+    {
+        JSONValue obj = JSONValue.emptyOrderedObject;
+        assert(obj.type == JSONType.object);
+        assert(obj.isOrdered);
+        obj["b"] = JSONValue(2);
+        obj["a"] = JSONValue(1);
+        assert(obj["a"] == JSONValue(1));
+        assert(obj["b"] == JSONValue(2));
+
+        string[] keys;
+        foreach (string k, JSONValue v; obj)
+            keys ~= k;
+        assert(keys == ["b", "a"]);
+    }
+
     /**
      * An enum value that can be used to obtain a `JSONValue` representing
      * an empty JSON array.
@@ -649,12 +777,14 @@ struct JSONValue
         assert(arr1 != arr2);
     }
 
-    void opAssign(T)(T arg) if (!isStaticArray!T && !is(T : JSONValue))
+    void opAssign(T)(T arg)
+    if (!isStaticArray!T && !is(T : JSONValue))
     {
         assign(arg);
     }
 
-    void opAssign(T)(ref T arg) if (isStaticArray!T)
+    void opAssign(T)(ref T arg)
+    if (isStaticArray!T)
     {
         assignRef(arg);
     }
@@ -708,16 +838,33 @@ struct JSONValue
      */
     void opIndexAssign(T)(auto ref T value, string key)
     {
-        enforce!JSONException(type == JSONType.object || type == JSONType.null_,
-                                "JSONValue must be object or null");
-        JSONValue[string] aa = null;
-        if (type == JSONType.object)
+        enforce!JSONException(
+            type == JSONType.object ||
+            type == JSONType.null_,
+            "JSONValue must be object or null");
+        if (type == JSONType.object && isOrdered)
         {
-            aa = this.objectNoRef;
+            auto arr = this.orderedObjectNoRef;
+            foreach (ref pair; arr)
+                if (pair.key == key)
+                {
+                    pair.value = value;
+                    return;
+                }
+            arr ~= OrderedObjectMember(key, JSONValue(value));
+            this.orderedObject = arr;
         }
+        else
+        {
+            JSONValue[string] aa = null;
+            if (type == JSONType.object)
+            {
+                aa = this.objectNoRef;
+            }
 
-        aa[key] = value;
-        this.object = aa;
+            aa[key] = value;
+            this.object = aa;
+        }
     }
     ///
     @safe unittest
@@ -828,6 +975,8 @@ struct JSONValue
     /// ditto
     bool opEquals(ref const JSONValue rhs) const @nogc nothrow pure @trusted
     {
+        import std.algorithm.searching : canFind;
+
         // Default doesn't work well since store is a union.  Compare only
         // what should be in store.
         // This is @trusted to remain nogc, nothrow, fast, and usable from @safe code.
@@ -873,7 +1022,45 @@ struct JSONValue
         case JSONType.string:
             return type_tag == rhs.type_tag && store.str == rhs.store.str;
         case JSONType.object:
-            return type_tag == rhs.type_tag && store.object == rhs.store.object;
+            if (rhs.type_tag != JSONType.object)
+                return false;
+            if (store.object.isOrdered)
+            {
+                if (rhs.store.object.isOrdered)
+                {
+                    if (store.object.ordered.length != rhs.store.object.ordered.length)
+                        return false;
+                    foreach (ref pair; store.object.ordered)
+                        if (!rhs.store.object.ordered.canFind(pair))
+                            return false;
+                    return true;
+                }
+                else
+                {
+                    if (store.object.ordered.length != rhs.store.object.unordered.length)
+                        return false;
+                    foreach (ref pair; store.object.ordered)
+                        if (pair.key !in rhs.store.object.unordered ||
+                            rhs.store.object.unordered[pair.key] != pair.value)
+                            return false;
+                    return true;
+                }
+            }
+            else
+            {
+                if (rhs.store.object.isOrdered)
+                {
+                    if (store.object.unordered.length != rhs.store.object.ordered.length)
+                        return false;
+                    foreach (ref pair; rhs.store.object.ordered)
+                        if (pair.key !in store.object.unordered ||
+                            store.object.unordered[pair.key] != pair.value)
+                            return false;
+                    return true;
+                }
+                else
+                    return store.object.unordered == rhs.store.object.unordered;
+            }
         case JSONType.array:
             return type_tag == rhs.type_tag && store.array == rhs.store.array;
         case JSONType.true_:
@@ -914,14 +1101,27 @@ struct JSONValue
     int opApply(scope int delegate(string key, ref JSONValue) dg) @system
     {
         enforce!JSONException(type == JSONType.object,
-                                "JSONValue is not an object");
+            "JSONValue is not an object");
+
         int result;
 
-        foreach (string key, ref value; object)
+        if (isOrdered)
         {
-            result = dg(key, value);
-            if (result)
-                break;
+            foreach (ref pair; orderedObject)
+            {
+                result = dg(pair.key, pair.value);
+                if (result)
+                    break;
+            }
+        }
+        else
+        {
+            foreach (string key, ref value; object)
+            {
+                result = dg(key, value);
+                if (result)
+                    break;
+            }
         }
 
         return result;
@@ -1018,6 +1218,7 @@ if (isSomeFiniteCharInputRange!T)
     Nullable!Char next;
     int line = 1, pos = 0;
     immutable bool strict = (options & JSONOptions.strictParsing) != 0;
+    immutable bool ordered = (options & JSONOptions.preserveObjectOrder) != 0;
 
     void error(string msg)
     {
@@ -1258,31 +1459,62 @@ if (isSomeFiniteCharInputRange!T)
         switch (c)
         {
             case '{':
-                if (testChar('}'))
+                if (ordered)
                 {
-                    value.object = null;
-                    break;
-                }
+                    if (testChar('}'))
+                    {
+                        value.orderedObject = null;
+                        break;
+                    }
 
-                JSONValue[string] obj;
-                do
+                    JSONValue.OrderedObjectMember[] obj;
+                    do
+                    {
+                        skipWhitespace();
+                        if (!strict && peekChar() == '}')
+                        {
+                            break;
+                        }
+                        checkChar('"');
+                        string name = parseString();
+                        checkChar(':');
+                        JSONValue member;
+                        parseValue(member);
+                        obj ~= JSONValue.OrderedObjectMember(name, member);
+                    }
+                    while (testChar(','));
+                    value.orderedObject = obj;
+
+                    checkChar('}');
+                }
+                else
                 {
-                    skipWhitespace();
-                    if (!strict && peekChar() == '}')
+                    if (testChar('}'))
                     {
+                        value.object = null;
                         break;
                     }
-                    checkChar('"');
-                    string name = parseString();
-                    checkChar(':');
-                    JSONValue member;
-                    parseValue(member);
-                    obj[name] = member;
-                }
-                while (testChar(','));
-                value.object = obj;
 
-                checkChar('}');
+                    JSONValue[string] obj;
+                    do
+                    {
+                        skipWhitespace();
+                        if (!strict && peekChar() == '}')
+                        {
+                            break;
+                        }
+                        checkChar('"');
+                        string name = parseString();
+                        checkChar(':');
+                        JSONValue member;
+                        parseValue(member);
+                        obj[name] = member;
+                    }
+                    while (testChar(','));
+                    value.object = obj;
+
+                    checkChar('}');
+                }
                 break;
 
             case '[':
@@ -1638,49 +1870,82 @@ if (isOutputRange!(Out,char))
         final switch (value.type)
         {
             case JSONType.object:
-                auto obj = value.objectNoRef;
-                if (!obj.length)
+                if (value.isOrdered)
                 {
-                    json.put("{}");
-                }
-                else
-                {
-                    putCharAndEOL('{');
-                    bool first = true;
-
-                    void emit(R)(R names)
+                    auto obj = value.orderedObjectNoRef;
+                    if (!obj.length)
                     {
-                        foreach (name; names)
+                        json.put("{}");
+                    }
+                    else
+                    {
+                        putCharAndEOL('{');
+                        bool first = true;
+
+                        foreach (pair; obj)
                         {
-                            auto member = obj[name];
                             if (!first)
                                 putCharAndEOL(',');
                             first = false;
                             putTabs(1);
-                            toString(name);
+                            toString(pair.key);
                             json.put(':');
                             if (pretty)
                                 json.put(' ');
-                            toValueImpl(member, indentLevel + 1);
+                            toValueImpl(pair.value, indentLevel + 1);
                         }
-                    }
 
-                    import std.algorithm.sorting : sort;
-                    // https://issues.dlang.org/show_bug.cgi?id=14439
-                    // auto names = obj.keys;  // aa.keys can't be called in @safe code
-                    auto names = new string[obj.length];
-                    size_t i = 0;
-                    foreach (k, v; obj)
+                        putEOL();
+                        putTabs();
+                        json.put('}');
+                    }
+                }
+                else
+                {
+                    auto obj = value.objectNoRef;
+                    if (!obj.length)
                     {
-                        names[i] = k;
-                        i++;
+                        json.put("{}");
                     }
-                    sort(names);
-                    emit(names);
+                    else
+                    {
+                        putCharAndEOL('{');
+                        bool first = true;
 
-                    putEOL();
-                    putTabs();
-                    json.put('}');
+                        void emit(R)(R names)
+                        {
+                            foreach (name; names)
+                            {
+                                auto member = obj[name];
+                                if (!first)
+                                    putCharAndEOL(',');
+                                first = false;
+                                putTabs(1);
+                                toString(name);
+                                json.put(':');
+                                if (pretty)
+                                    json.put(' ');
+                                toValueImpl(member, indentLevel + 1);
+                            }
+                        }
+
+                        import std.algorithm.sorting : sort;
+                        // https://issues.dlang.org/show_bug.cgi?id=14439
+                        // auto names = obj.keys;  // aa.keys can't be called in @safe code
+                        auto names = new string[obj.length];
+                        size_t i = 0;
+                        foreach (k, v; obj)
+                        {
+                            names[i] = k;
+                            i++;
+                        }
+                        sort(names);
+                        emit(names);
+
+                        putEOL();
+                        putTabs();
+                        json.put('}');
+                    }
                 }
                 break;
 
@@ -2469,3 +2734,17 @@ pure nothrow @safe unittest
 
     assert(app.data == s, app.data);
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=24823 - JSONOptions.preserveObjectOrder
+@safe unittest
+{
+    import std.array : appender;
+
+    string s = `{"b":2,"a":1}`;
+    JSONValue j = parseJSON(s, -1, JSONOptions.preserveObjectOrder);
+
+    auto app = appender!string();
+    j.toString(app);
+
+    assert(app.data == s, app.data);
+}
diff --git a/libphobos/src/std/logger/core.d b/libphobos/src/std/logger/core.d
index 0633bddee81aeec218d2562e0b562277a78a29db..cc938d4fd34970d09bbbc9faeeb93b1317f4d86f 100644
--- a/libphobos/src/std/logger/core.d
+++ b/libphobos/src/std/logger/core.d
@@ -293,7 +293,7 @@ template defaultLogFunction(LogLevel ll)
         string funcName = __FUNCTION__,
         string prettyFuncName = __PRETTY_FUNCTION__,
         string moduleName = __MODULE__, A...)(lazy A args)
-        if ((args.length > 0 && !is(Unqual!(A[0]) : bool)) || args.length == 0)
+    if ((args.length > 0 && !is(Unqual!(A[0]) : bool)) || args.length == 0)
     {
             stdThreadLocalLog.memLogFunctions!(ll).logImpl!(line, file, funcName,
                 prettyFuncName, moduleName)(args);
@@ -446,7 +446,7 @@ private struct MsgRange
     }
 
     void put(T)(T msg) @safe
-        if (isSomeString!T)
+    if (isSomeString!T)
     {
         log.logMsgPart(msg);
     }
@@ -735,7 +735,7 @@ abstract class Logger
             string funcName = __FUNCTION__,
             string prettyFuncName = __PRETTY_FUNCTION__,
             string moduleName = __MODULE__, A...)(lazy A args)
-            if (args.length == 0 || (args.length > 0 && !is(A[0] : bool)))
+        if (args.length == 0 || (args.length > 0 && !is(A[0] : bool)))
         {
             synchronized (mutex)
             {
@@ -948,7 +948,7 @@ abstract class Logger
         string prettyFuncName = __PRETTY_FUNCTION__,
         string moduleName = __MODULE__, A...)(const LogLevel ll,
         lazy bool condition, lazy A args)
-        if (args.length != 1)
+    if (args.length != 1)
     {
         synchronized (mutex)
         {
@@ -1016,7 +1016,7 @@ abstract class Logger
         string funcName = __FUNCTION__,
         string prettyFuncName = __PRETTY_FUNCTION__,
         string moduleName = __MODULE__, A...)(const LogLevel ll, lazy A args)
-        if ((args.length > 1 && !is(Unqual!(A[0]) : bool)) || args.length == 0)
+    if ((args.length > 1 && !is(Unqual!(A[0]) : bool)) || args.length == 0)
     {
         synchronized (mutex)
         {
@@ -1085,7 +1085,7 @@ abstract class Logger
         string funcName = __FUNCTION__,
         string prettyFuncName = __PRETTY_FUNCTION__,
         string moduleName = __MODULE__, A...)(lazy bool condition, lazy A args)
-        if (args.length != 1)
+    if (args.length != 1)
     {
         synchronized (mutex)
         {
@@ -1154,10 +1154,10 @@ abstract class Logger
         string funcName = __FUNCTION__,
         string prettyFuncName = __PRETTY_FUNCTION__,
         string moduleName = __MODULE__, A...)(lazy A args)
-        if ((args.length > 1
-                && !is(Unqual!(A[0]) : bool)
-                && !is(immutable A[0] == immutable LogLevel))
-            || args.length == 0)
+    if ((args.length > 1
+        && !is(Unqual!(A[0]) : bool)
+        && !is(immutable A[0] == immutable LogLevel))
+        || args.length == 0)
     {
         synchronized (mutex)
         {
diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d
index 9f0fb564de378e28d02fbc8ee52db69779c63728..3fef8e4f1feaa9a5b08951886080575e38604124 100644
--- a/libphobos/src/std/numeric.d
+++ b/libphobos/src/std/numeric.d
@@ -496,7 +496,8 @@ public:
     static @property CustomFloat im() { return CustomFloat(0.0f); }
 
     /// Initialize from any `real` compatible type.
-    this(F)(F input) if (__traits(compiles, cast(real) input ))
+    this(F)(F input)
+    if (__traits(compiles, cast(real) input ))
     {
         this = input;
     }
@@ -512,7 +513,7 @@ public:
 
     /// Assigns from any `real` compatible type.
     void opAssign(F)(F input)
-        if (__traits(compiles, cast(real) input))
+    if (__traits(compiles, cast(real) input))
     {
         import std.conv : text;
 
@@ -546,7 +547,7 @@ public:
 
     /// Fetches the stored value either as a `float`, `double` or `real`.
     @property F get(F)()
-        if (staticIndexOf!(immutable F, immutable float, immutable double, immutable real) >= 0)
+    if (staticIndexOf!(immutable F, immutable float, immutable double, immutable real) >= 0)
     {
         import std.conv : text;
 
@@ -574,7 +575,7 @@ public:
 
     /// Convert the CustomFloat to a real and perform the relevant operator on the result
     real opUnary(string op)()
-        if (__traits(compiles, mixin(op~`(get!real)`)) || op=="++" || op=="--")
+    if (__traits(compiles, mixin(op~`(get!real)`)) || op=="++" || op=="--")
     {
         static if (op=="++" || op=="--")
         {
@@ -591,31 +592,31 @@ public:
     // do not match equally, which is disallowed by the spec:
     // https://dlang.org/spec/operatoroverloading.html#binary
     real opBinary(string op,T)(T b)
-         if (__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
-     {
-         return mixin(`get!real`~op~`b.get!real`);
-     }
+    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)
-        if ( __traits(compiles, mixin(`get!real`~op~`b`)) &&
-            !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
+    if ( __traits(compiles, mixin(`get!real`~op~`b`)) &&
+        !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
     {
         return mixin(`get!real`~op~`b`);
     }
 
     /// ditto
     real opBinaryRight(string op,T)(T a)
-        if ( __traits(compiles, mixin(`a`~op~`get!real`)) &&
-            !__traits(compiles, mixin(`get!real`~op~`b`)) &&
-            !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
+    if ( __traits(compiles, mixin(`a`~op~`get!real`)) &&
+        !__traits(compiles, mixin(`get!real`~op~`b`)) &&
+        !__traits(compiles, mixin(`get!real`~op~`b.get!real`)))
     {
         return mixin(`a`~op~`get!real`);
     }
 
     /// ditto
     int opCmp(T)(auto ref T b)
-        if (__traits(compiles, cast(real) b))
+    if (__traits(compiles, cast(real) b))
     {
         auto x = get!real;
         auto y = cast(real) b;
@@ -624,7 +625,7 @@ public:
 
     /// ditto
     void opOpAssign(string op, T)(auto ref T b)
-        if (__traits(compiles, mixin(`get!real`~op~`cast(real) b`)))
+    if (__traits(compiles, mixin(`get!real`~op~`cast(real) b`)))
     {
         return mixin(`this = this `~op~` cast(real) b`);
     }
@@ -3687,7 +3688,7 @@ public:
      *              i.e., output[j] := sum[ exp(-2 PI i j k / N) input[k] ].
      */
     Complex!F[] fft(F = double, R)(R range) const
-        if (isFloatingPoint!F && isRandomAccessRange!R)
+    if (isFloatingPoint!F && isRandomAccessRange!R)
     {
         enforceSize(range);
         Complex!F[] ret;
@@ -3710,7 +3711,7 @@ public:
      * property that can be both read and written and are floating point numbers.
      */
     void fft(Ret, R)(R range, Ret buf) const
-        if (isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret)
+    if (isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret)
     {
         assert(buf.length == range.length);
         enforceSize(range);
@@ -3759,7 +3760,7 @@ public:
      *              output[j] := (1 / N) sum[ exp(+2 PI i j k / N) input[k] ].
      */
     Complex!F[] inverseFft(F = double, R)(R range) const
-        if (isRandomAccessRange!R && isComplexLike!(ElementType!R) && isFloatingPoint!F)
+    if (isRandomAccessRange!R && isComplexLike!(ElementType!R) && isFloatingPoint!F)
     {
         enforceSize(range);
         Complex!F[] ret;
@@ -3781,7 +3782,7 @@ public:
      * must be some complex-like type.
      */
     void inverseFft(Ret, R)(R range, Ret buf) const
-        if (isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret)
+    if (isRandomAccessRange!Ret && isComplexLike!(ElementType!Ret) && hasSlicing!Ret)
     {
         enforceSize(range);
 
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index 7525d9b1491ce5287ee36c5c902d17bd4a48700d..bafdbb92f2c945cd5542321e36a174e3bd661ea8 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -2269,7 +2269,8 @@ public:
     call to `popFront` or, if thrown during construction, simply
     allowed to propagate to the caller.
     */
-    auto asyncBuf(S)(S source, size_t bufSize = 100) if (isInputRange!S)
+    auto asyncBuf(S)(S source, size_t bufSize = 100)
+    if (isInputRange!S)
     {
         static final class AsyncBuf
         {
diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d
index a45865a9f18136374fdcaf9cdf735fa764bb6097..9dae2a65530a3aa578762b828c14fda2d8bfb838 100644
--- a/libphobos/src/std/path.d
+++ b/libphobos/src/std/path.d
@@ -1446,9 +1446,8 @@ private auto _withDefaultExtension(R, C)(R path, C[] ext)
         of segments to assemble the path from.
     Returns: The assembled path.
 */
-immutable(ElementEncodingType!(ElementType!Range))[]
-    buildPath(Range)(scope Range segments)
-    if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))
+immutable(ElementEncodingType!(ElementType!Range))[] buildPath(Range)(scope Range segments)
+if (isInputRange!Range && !isInfinite!Range && isSomeString!(ElementType!Range))
 {
     if (segments.empty) return null;
 
@@ -3396,7 +3395,10 @@ do
     }
     else
     {
+        import core.memory : pureMalloc, pureFree;
         C[] pattmp;
+        scope(exit) if (pattmp !is null) (() @trusted => pureFree(pattmp.ptr))();
+
         for (size_t pi = 0; pi < pattern.length; pi++)
         {
             const pc = pattern[pi];
@@ -3482,9 +3484,12 @@ do
                              *   pattern[pi0 .. pi-1] ~ pattern[piRemain..$]
                              */
                             if (pattmp is null)
+                            {
                                 // Allocate this only once per function invocation.
-                                // Should do it with malloc/free, but that would make it impure.
-                                pattmp = new C[pattern.length];
+                                pattmp = (() @trusted =>
+                                    (cast(C*) pureMalloc(C.sizeof * pattern.length))[0 .. pattern.length])
+                                ();
+                            }
 
                             const len1 = pi - 1 - pi0;
                             pattmp[0 .. len1] = pattern[pi0 .. pi - 1];
@@ -3518,7 +3523,7 @@ do
 }
 
 ///
-@safe unittest
+@safe @nogc unittest
 {
     assert(globMatch("foo.bar", "*"));
     assert(globMatch("foo.bar", "*.*"));
diff --git a/libphobos/src/std/process.d b/libphobos/src/std/process.d
index 41f788d22901d84120d8d43789cbc7b50bac8a86..4f593bd067fe4970fc4eee0ec7f9b02d5c43e0ce 100644
--- a/libphobos/src/std/process.d
+++ b/libphobos/src/std/process.d
@@ -1050,54 +1050,103 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
 
                 static if (!__traits(compiles, closefrom))
                 {
-                    // FIXME: This implementation crashes the system when RLIMIT_NOFILE
-                    // has a big value. For a possible solution see:
-                    // https://github.com/dlang/phobos/pull/8990
-                    void fallback (int lowfd) {
-                        // NOTE: malloc() and getrlimit() are not on the POSIX async
-                        // signal safe functions list, but practically this should
-                        // not be a problem. Java VM and CPython also use malloc()
-                        // in its own implementation via opendir().
-                        import core.stdc.stdlib : malloc;
-                        import core.sys.posix.poll : pollfd, poll, POLLNVAL;
+                    void fallback (int lowfd)
+                    {
+                        import core.sys.posix.dirent : dirent, opendir, readdir, closedir, DIR;
+                        import core.sys.posix.unistd : close;
+                        import core.sys.posix.stdlib : atoi, malloc, free;
                         import core.sys.posix.sys.resource : rlimit, getrlimit, RLIMIT_NOFILE;
 
                         // Get the maximum number of file descriptors that could be open.
                         rlimit r;
                         if (getrlimit(RLIMIT_NOFILE, &r) != 0)
-                        {
                             abortOnError(forkPipeOut, InternalError.getrlimit, .errno);
-                        }
+
                         immutable maxDescriptors = cast(int) r.rlim_cur;
 
-                        immutable maxToClose = maxDescriptors - lowfd;
+                        // Missing druntime declaration
+                        pragma(mangle, "dirfd")
+                        extern(C) nothrow @nogc int dirfd(DIR* dir);
 
-                        // Call poll() to see which ones are actually open:
-                        auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
-                        if (pfds is null)
-                        {
-                            abortOnError(forkPipeOut, InternalError.malloc, .errno);
-                        }
-                        foreach (i; 0 .. maxToClose)
+                        DIR* dir = null;
+
+                        // We read from /dev/fd or /proc/self/fd only if the limit is high enough
+                        if (maxDescriptors > 128*1024)
                         {
-                            pfds[i].fd = i + lowfd;
-                            pfds[i].events = 0;
-                            pfds[i].revents = 0;
+                            // Try to open the directory /dev/fd or /proc/self/fd
+                            dir = opendir("/dev/fd");
+                            if (dir is null) dir = opendir("/proc/self/fd");
                         }
-                        if (poll(pfds, maxToClose, 0) >= 0)
+
+                        // If we have a directory, close all file descriptors except stdin, stdout, and stderr
+                        if (dir)
                         {
-                            foreach (i; 0 .. maxToClose)
+                            scope(exit) closedir(dir);
+
+                            int opendirfd = dirfd(dir);
+
+                            // Iterate over all file descriptors
+                            while (true)
                             {
-                                // POLLNVAL will be set if the file descriptor is invalid.
-                                if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
+                                dirent* entry = readdir(dir);
+
+                                if (entry is null) break;
+                                if (entry.d_name[0] == '.') continue;
+
+                                int fd = atoi(cast(char*) entry.d_name);
+
+                                // Don't close stdin, stdout, stderr, or the directory file descriptor
+                                if (fd < lowfd || fd == opendirfd) continue;
+
+                                close(fd);
                             }
                         }
                         else
                         {
-                            // Fall back to closing everything.
-                            foreach (i; lowfd .. maxDescriptors)
+                            // This is going to allocate 8 bytes for each possible file descriptor from lowfd to r.rlim_cur
+                            if (maxDescriptors <= 128*1024)
                             {
-                                close(i);
+                                // NOTE: malloc() and getrlimit() are not on the POSIX async
+                                // signal safe functions list, but practically this should
+                                // not be a problem. Java VM and CPython also use malloc()
+                                // in its own implementation via opendir().
+                                import core.stdc.stdlib : malloc;
+                                import core.sys.posix.poll : pollfd, poll, POLLNVAL;
+
+                                immutable maxToClose = maxDescriptors - lowfd;
+
+                                // Call poll() to see which ones are actually open:
+                                auto pfds = cast(pollfd*) malloc(pollfd.sizeof * maxToClose);
+                                if (pfds is null)
+                                {
+                                    abortOnError(forkPipeOut, InternalError.malloc, .errno);
+                                }
+
+                                foreach (i; 0 .. maxToClose)
+                                {
+                                    pfds[i].fd = i + lowfd;
+                                    pfds[i].events = 0;
+                                    pfds[i].revents = 0;
+                                }
+
+                                if (poll(pfds, maxToClose, 0) < 0)
+                                    // couldn't use poll, use the slow path.
+                                    goto LslowClose;
+
+                                foreach (i; 0 .. maxToClose)
+                                {
+                                    // POLLNVAL will be set if the file descriptor is invalid.
+                                    if (!(pfds[i].revents & POLLNVAL)) close(pfds[i].fd);
+                                }
+                            }
+                            else
+                            {
+                            LslowClose:
+                                // Fall back to closing everything.
+                                foreach (i; lowfd .. maxDescriptors)
+                                {
+                                    close(i);
+                                }
                             }
                         }
                     }
@@ -1106,6 +1155,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
                     // Until we find a way to perform this check we will try to use dlsym to
                     // check for the function. See: https://github.com/dlang/phobos/pull/9048
                     version (CRuntime_Glibc)
+                    {
                         void closefrom (int lowfd) {
                             static bool tryGlibcClosefrom (int lowfd) {
                                 import core.sys.posix.dlfcn : dlopen, dlclose, dlsym, dlerror, RTLD_LAZY;
@@ -1129,6 +1179,7 @@ private Pid spawnProcessPosix(scope const(char[])[] args,
                             if (!tryGlibcClosefrom(lowfd))
                                 fallback(lowfd);
                         }
+                    }
                     else
                         alias closefrom = fallback;
                 }
diff --git a/libphobos/src/std/random.d b/libphobos/src/std/random.d
index 87e63f3f6ee40a98c53d4213fa29e273c3feb36e..c2210248edf10f127bab18385288812f18b9dcf9 100644
--- a/libphobos/src/std/random.d
+++ b/libphobos/src/std/random.d
@@ -935,7 +935,8 @@ Parameters for the generator.
    `Exception` if the InputRange didn't provide enough elements to seed the generator.
    The number of elements required is the 'n' template parameter of the MersenneTwisterEngine struct.
  */
-    void seed(T)(T range) if (isInputRange!T && is(immutable ElementType!T == immutable UIntType))
+    void seed(T)(T range)
+    if (isInputRange!T && is(immutable ElementType!T == immutable UIntType))
     {
         this.seedImpl(range, this.state);
     }
@@ -945,7 +946,7 @@ Parameters for the generator.
        which can be used with an arbitrary `State` instance
     */
     private static void seedImpl(T)(T range, ref State mtState)
-        if (isInputRange!T && is(immutable ElementType!T == immutable UIntType))
+    if (isInputRange!T && is(immutable ElementType!T == immutable UIntType))
     {
         size_t j;
         for (j = 0; j < n && !range.empty; ++j, range.popFront())
@@ -2215,6 +2216,7 @@ at least that number won't be represented fairly.
 Hence, our condition to reroll is
 `bucketFront > (UpperType.max - (upperDist - 1))`
 +/
+/// ditto
 auto uniform(string boundaries = "[)", T1, T2, RandomGen)
 (T1 a, T2 b, ref RandomGen rng)
 if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) &&
@@ -2277,9 +2279,14 @@ if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) &&
     return cast(ResultType)(lower + offset);
 }
 
+///
 @safe unittest
 {
     import std.conv : to;
+    import std.meta : AliasSeq;
+    import std.range.primitives : isForwardRange;
+    import std.traits : isIntegral, isSomeChar;
+
     auto gen = Mt19937(123_456_789);
     static assert(isForwardRange!(typeof(gen)));
 
@@ -2290,7 +2297,7 @@ if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) &&
     auto c = uniform(0.0, 1.0);
     assert(0 <= c && c < 1);
 
-    static foreach (T; std.meta.AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort,
+    static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short, ushort,
                           int, uint, long, ulong, float, double, real))
     {{
         T lo = 0, hi = 100;
@@ -2344,7 +2351,7 @@ if ((isIntegral!(CommonType!(T1, T2)) || isSomeChar!(CommonType!(T1, T2))) &&
 
     auto reproRng = Xorshift(239842);
 
-    static foreach (T; std.meta.AliasSeq!(char, wchar, dchar, byte, ubyte, short,
+    static foreach (T; AliasSeq!(char, wchar, dchar, byte, ubyte, short,
                           ushort, int, uint, long, ulong))
     {{
         T lo = T.min + 10, hi = T.max - 10;
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index e2a2d7d2564da78c387974e8896e29e07bc638bf..3a135ebba5108925b10ec9364c4f9d26a02ba8d2 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -6095,8 +6095,10 @@ private struct LockstepMixin(Ranges...)
             {
                 indexDef = q{
                     size_t index = ranges[0].length - 1;
-                    enforce(this.stoppingPolicy == StoppingPolicy.requireSameLength,
-                            "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
+                    enforce(
+                        this.stoppingPolicy == StoppingPolicy.requireSameLength,
+                        "Indexed lockstep can only be used with foreach_reverse when " ~
+                        "stoppingPolicy == requireSameLength");
 
                     foreach (range; ranges[1 .. $])
                         enforce(range.length == ranges[0].length);
@@ -7490,7 +7492,8 @@ if (!isIntegral!(CommonType!(B, E)) &&
 
         bool opEquals(Cyclic c) const { return current == c.current; }
         bool opEquals(int i) const { return current == i; }
-        void opUnary(string op)() if (op == "++")
+        void opUnary(string op)()
+        if (op == "++")
         {
             current = (current + 1) % wrapAround;
         }
@@ -12444,7 +12447,7 @@ public:
             return (*_range).front;
         }
 
-        static if (is(typeof((*(cast(const R*)_range)).front))) @property auto front() const
+        static if (is(typeof(((const R* r) => (*r).front)(null)))) @property auto front() const
         {
             return (*_range).front;
         }
@@ -12470,7 +12473,7 @@ public:
             return (*_range).empty;
         }
 
-        static if (is(typeof((*cast(const R*)_range).empty))) @property bool empty() const
+        static if (is(typeof(((const R* r) => (*r).empty)(null)))) @property bool empty() const
         {
             return (*_range).empty;
         }
@@ -12500,10 +12503,11 @@ public:
     else static if (isForwardRange!R)
     {
         import std.traits : isSafe;
-        private alias S = typeof((*_range).save);
+        private alias S = typeof((() => (*_range).save)());
+
+        static if (is(typeof(((const R* r) => (*r).save)(null))))
+            private alias CS = typeof(((const R* r) => (*r).save)(null));
 
-        static if (is(typeof((*cast(const R*)_range).save)))
-            private alias CS = typeof((*cast(const R*)_range).save);
 
         static if (isSafe!((R* r) => (*r).save))
         {
@@ -12512,7 +12516,7 @@ public:
                 mixin(_genSave());
             }
 
-            static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() @trusted const
+            static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() @trusted const
             {
                 mixin(_genSave());
             }
@@ -12524,7 +12528,7 @@ public:
                 mixin(_genSave());
             }
 
-            static if (is(typeof((*cast(const R*)_range).save))) @property RefRange!CS save() const
+            static if (is(typeof(((const R* r) => (*r).save)(null)))) @property RefRange!CS save() const
             {
                 mixin(_genSave());
             }
@@ -12543,7 +12547,7 @@ public:
         private static string _genSave() @safe pure nothrow
         {
             return `import core.lifetime : emplace;` ~
-                   `alias S = typeof((*_range).save);` ~
+                   `alias S = typeof((() => (*_range).save)());` ~
                    `static assert(isForwardRange!S, S.stringof ~ " is not a forward range.");` ~
                    `auto mem = new void[S.sizeof];` ~
                    `emplace!S(mem, cast(S)(*_range).save);` ~
@@ -12572,7 +12576,7 @@ public:
             return (*_range).back;
         }
 
-        static if (is(typeof((*(cast(const R*)_range)).back))) @property auto back() const
+        static if (is(typeof(((const R* r) => (*r).back)(null)))) @property auto back() const
         {
             return (*_range).back;
         }
@@ -12604,13 +12608,13 @@ public:
     else static if (isRandomAccessRange!R)
     {
         auto ref opIndex(IndexType)(IndexType index)
-            if (is(typeof((*_range)[index])))
+        if (is(typeof((*_range)[index])))
         {
             return (*_range)[index];
         }
 
         auto ref opIndex(IndexType)(IndexType index) const
-            if (is(typeof((*cast(const R*)_range)[index])))
+        if (is(typeof((*cast(const R*)_range)[index])))
         {
             return (*_range)[index];
         }
@@ -12662,7 +12666,7 @@ public:
         {
             return (*_range).length;
         }
-        static if (is(typeof((*cast(const R*)_range).length))) @property auto length() const
+        static if (is(typeof(((const R* r) => (*r).length)(null)))) @property auto length() const
         {
             return (*_range).length;
         }
@@ -12692,14 +12696,14 @@ public:
 
         RefRange!T opSlice(IndexType1, IndexType2)
                     (IndexType1 begin, IndexType2 end)
-            if (is(typeof((*_range)[begin .. end])))
+        if (is(typeof((*_range)[begin .. end])))
         {
             mixin(_genOpSlice());
         }
 
         RefRange!CT opSlice(IndexType1, IndexType2)
                     (IndexType1 begin, IndexType2 end) const
-            if (is(typeof((*cast(const R*)_range)[begin .. end])))
+        if (is(typeof((*cast(const R*)_range)[begin .. end])))
         {
             mixin(_genOpSlice());
         }
@@ -13105,6 +13109,44 @@ private:
     auto rr2 = refRange(&r2);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24801
+@safe unittest
+{
+
+    {
+        static struct R
+        {
+            int front() => 0;
+            void popFront() {}
+            bool empty() => false;
+        }
+        R range;
+        auto r = RefRange!R(&range);
+    }
+
+    {
+        static struct R
+        {
+            size_t start, end;
+            size_t length() => end - start;
+            int opIndex(size_t i) => 0;
+
+
+            int front() => this[0];
+            int back() => this[length-1];
+            void popFront() { start++; }
+            void popBack() { end--; }
+            bool empty() => length == 0;
+            R save() const => R();
+        }
+
+        R range;
+        auto r = RefRange!R(&range);
+    }
+
+
+}
+
 /// ditto
 auto refRange(R)(R* range)
 if (isInputRange!R)
diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d
index dddcae9afd2ecde76e985d841d57b9156658c3b9..84366250e7817b06df5a3202bb876bd70042d0ae 100644
--- a/libphobos/src/std/range/primitives.d
+++ b/libphobos/src/std/range/primitives.d
@@ -474,7 +474,8 @@ void put(R, E)(ref R r, E e)
     {
         string data;
 
-        void put(C)(C c) if (isSomeChar!C)
+        void put(C)(C c)
+        if (isSomeChar!C)
         {
             data ~= c;
         }
diff --git a/libphobos/src/std/regex/internal/backtracking.d b/libphobos/src/std/regex/internal/backtracking.d
index a488e0660d035e6c21cf6cf58bdf304757ce06c6..605ec03c481e4ef6b081faa0c69ea73c8216b89f 100644
--- a/libphobos/src/std/regex/internal/backtracking.d
+++ b/libphobos/src/std/regex/internal/backtracking.d
@@ -702,7 +702,7 @@ final:
     }
 
     void stackPush(T)(T val)
-        if (!isDynamicArray!T)
+    if (!isDynamicArray!T)
     {
         *cast(T*)&memory[lastState] = val;
         enum delta = (T.sizeof+size_t.sizeof/2)/size_t.sizeof;
@@ -720,7 +720,7 @@ final:
     }
 
     void stackPop(T)(ref T val)
-        if (!isDynamicArray!T)
+    if (!isDynamicArray!T)
     {
         enum delta = (T.sizeof+size_t.sizeof/2)/size_t.sizeof;
         lastState -= delta;
diff --git a/libphobos/src/std/regex/internal/parser.d b/libphobos/src/std/regex/internal/parser.d
index ab2b297fb884d8088f00eb8c425d057d8ddf7aba..d8ebe59f0a6c31f46e7049fe6bb704eddaf89a7c 100644
--- a/libphobos/src/std/regex/internal/parser.d
+++ b/libphobos/src/std/regex/internal/parser.d
@@ -542,7 +542,7 @@ if (isForwardRange!R && is(ElementType!R : dchar))
     Generator g;
 
     @trusted this(S)(R pattern, S flags)
-        if (isSomeString!S)
+    if (isSomeString!S)
     {
         pat = origin = pattern;
         //reserve slightly more then avg as sampled from unittests
diff --git a/libphobos/src/std/regex/internal/thompson.d b/libphobos/src/std/regex/internal/thompson.d
index f4643ae1bcb7bb0b6a61fd71cb54796cbe98ba39..195625f15eaf76dabe2f0cfa7017305439babf49 100644
--- a/libphobos/src/std/regex/internal/thompson.d
+++ b/libphobos/src/std/regex/internal/thompson.d
@@ -276,7 +276,7 @@ template ThompsonOps(E, S, bool withInput:true)
     }
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.RepeatEnd || code == IR.RepeatQEnd)
+    if (code == IR.RepeatEnd || code == IR.RepeatQEnd)
     {
         with(e) with(state)
         {
@@ -331,7 +331,7 @@ template ThompsonOps(E, S, bool withInput:true)
     }
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.InfiniteEnd || code == IR.InfiniteQEnd)
+    if (code == IR.InfiniteEnd || code == IR.InfiniteQEnd)
     {
         with(e) with(state)
         {
@@ -366,7 +366,7 @@ template ThompsonOps(E, S, bool withInput:true)
     }
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.InfiniteBloomEnd)
+    if (code == IR.InfiniteBloomEnd)
     {
         with(e) with(state)
         {
@@ -507,7 +507,7 @@ template ThompsonOps(E, S, bool withInput:true)
 
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.LookbehindStart || code == IR.NeglookbehindStart)
+    if (code == IR.LookbehindStart || code == IR.NeglookbehindStart)
     {
         with(e) with(state)
         {
@@ -534,7 +534,7 @@ template ThompsonOps(E, S, bool withInput:true)
     }
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.LookaheadStart || code == IR.NeglookaheadStart)
+    if (code == IR.LookaheadStart || code == IR.NeglookaheadStart)
     {
         with(e) with(state)
         {
@@ -563,8 +563,8 @@ template ThompsonOps(E, S, bool withInput:true)
     }
 
     static bool op(IR code)(E e, S* state)
-        if (code == IR.LookaheadEnd || code == IR.NeglookaheadEnd ||
-            code == IR.LookbehindEnd || code == IR.NeglookbehindEnd)
+    if (code == IR.LookaheadEnd || code == IR.NeglookaheadEnd ||
+        code == IR.LookbehindEnd || code == IR.NeglookbehindEnd)
     {
         with(e) with(state)
         {
@@ -675,7 +675,7 @@ template ThompsonOps(E,S, bool withInput:false)
 @trusted:
     // can't match these without input
     static bool op(IR code)(E e, S* state)
-        if (code == IR.Char || code == IR.OrChar || code == IR.CodepointSet
+    if (code == IR.Char || code == IR.OrChar || code == IR.CodepointSet
         || code == IR.Trie || code == IR.Char || code == IR.Any)
     {
         return state.popState(e);
@@ -701,7 +701,7 @@ template ThompsonOps(E,S, bool withInput:false)
 
     // forward all control flow to normal versions
     static bool op(IR code)(E e, S* state)
-        if (code != IR.Char && code != IR.OrChar && code != IR.CodepointSet
+    if (code != IR.Char && code != IR.OrChar && code != IR.CodepointSet
         && code != IR.Trie && code != IR.Char && code != IR.Any && code != IR.Backref)
     {
         return ThompsonOps!(E,S,true).op!code(e,state);
diff --git a/libphobos/src/std/regex/package.d b/libphobos/src/std/regex/package.d
index d6a01e244865fa6b3decd746d1ac7a7072db2120..143b6835a58b5e15dabcb56c40da523206a6a1b8 100644
--- a/libphobos/src/std/regex/package.d
+++ b/libphobos/src/std/regex/package.d
@@ -688,7 +688,7 @@ public:
         ----
     +/
     R opIndex(String)(String i) /*const*/ //@@@BUG@@@
-        if (isSomeString!String)
+    if (isSomeString!String)
     {
         size_t index = lookupNamedGroup(_names, i);
         return getMatch(index);
diff --git a/libphobos/src/std/socket.d b/libphobos/src/std/socket.d
index e86a51fe2df3d66e886cb17cd00c1ff8f8f40aa1..52fd33b1dd1e32e0b0ebf7c52ed9b2ee95b140fd 100644
--- a/libphobos/src/std/socket.d
+++ b/libphobos/src/std/socket.d
@@ -702,7 +702,7 @@ class InternetHost
         // must synchronize across all threads
         private bool getHost(string opMixin, T)(T param) @system
         {
-            synchronized(this.classinfo)
+            synchronized(typeid(this))
                 return getHostNoSync!(opMixin, T)(param);
         }
     }
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index b4744600cd5958392de1ace9e21b4346ae0b382c..e844297b8dc4a28d9fc0af63caae999203d2d73f 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -447,7 +447,7 @@ Throws: `ErrnoException` if the file could not be opened.
 
     /// ditto
     this(R1, R2)(R1 name)
-        if (isSomeFiniteCharInputRange!R1)
+    if (isSomeFiniteCharInputRange!R1)
     {
         import std.conv : to;
         this(name.to!string, "rb");
@@ -455,8 +455,8 @@ Throws: `ErrnoException` if the file could not be opened.
 
     /// ditto
     this(R1, R2)(R1 name, R2 mode)
-        if (isSomeFiniteCharInputRange!R1 &&
-            isSomeFiniteCharInputRange!R2)
+    if (isSomeFiniteCharInputRange!R1 &&
+        isSomeFiniteCharInputRange!R2)
     {
         import std.conv : to;
         this(name.to!string, mode.to!string);
@@ -2340,6 +2340,24 @@ void main()
 Notice that neither example accesses the line data returned by
 `front` after the corresponding `popFront` call is made (because
 the contents may well have changed).
+----
+
+Windows specific Example:
+----
+import std.stdio;
+
+version (Windows)
+void main()
+{
+
+	foreach (line; File("file.txt").byLine(No.keepTerminator, "\r\n"))
+	{
+		writeln("|"~line~"|");
+		if (line == "HelloWorld")
+		    writeln("^This Line is here.");
+	}
+
+}
 */
     auto byLine(Terminator = char, Char = char)
             (KeepTerminator keepTerminator = No.keepTerminator,
@@ -2997,10 +3015,10 @@ is empty, throws an `Exception`. In case of an I/O error throws
 
         /// Range primitive implementations.
         void put(A)(scope A writeme)
-            if ((isSomeChar!(ElementType!A) ||
-                  is(ElementType!A : const(ubyte))) &&
-                isInputRange!A &&
-                !isInfinite!A)
+        if ((isSomeChar!(ElementType!A) ||
+            is(ElementType!A : const(ubyte))) &&
+            isInputRange!A &&
+            !isInfinite!A)
         {
             import std.exception : errnoEnforce;
 
@@ -3026,7 +3044,8 @@ is empty, throws an `Exception`. In case of an I/O error throws
         }
 
         /// ditto
-        void put(C)(scope C c) @safe if (isSomeChar!C || is(C : const(ubyte)))
+        void put(C)(scope C c) @safe
+        if (isSomeChar!C || is(C : const(ubyte)))
         {
             import std.utf : decodeFront, encode, stride;
 
diff --git a/libphobos/src/std/string.d b/libphobos/src/std/string.d
index 21e1ca356f8605f3fb01ee0b28ef952fb58b4d0d..bcc9d7c13afa4a85c16dd6d5321ba02442cbf71e 100644
--- a/libphobos/src/std/string.d
+++ b/libphobos/src/std/string.d
@@ -457,26 +457,26 @@ pure nothrow @system unittest // https://issues.dlang.org/show_bug.cgi?id=15136
 alias CaseSensitive = Flag!"caseSensitive";
 
 /++
-    Searches for character in range.
+    Searches for a character in a string or range.
 
     Params:
-        s = string or InputRange of characters to search in correct UTF format
-        c = character to search for
-        startIdx = starting index to a well-formed code point
-        cs = `Yes.caseSensitive` or `No.caseSensitive`
+        s = string or InputRange of characters to search for `c` in
+        c = character to search for in `s`
+        startIdx = index to a well-formed code point in `s` to start
+            searching from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`).
 
     Returns:
-        the index of the first occurrence of `c` in `s` with
-        respect to the start index `startIdx`. If `c`
-        is not found, then `-1` is returned.
-        If `c` is found the value of the returned index is at least
-        `startIdx`.
-        If the parameters are not valid UTF, the result will still
-        be in the range [-1 .. s.length], but will not be reliable otherwise.
+        If `c` is found in `s`, then the index of its first occurrence is
+        returned. If `c` is not found or `startIdx` is greater than or equal to
+        `s.length`, then -1 is returned. If the parameters are not valid UTF,
+        the result will still be either -1 or in the range [`startIdx` ..
+        `s.length`], but will not be reliable otherwise.
 
     Throws:
-        If the sequence starting at `startIdx` does not represent a well
-        formed codepoint, then a $(REF UTFException, std,utf) may be thrown.
+        If the sequence starting at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
 
     See_Also: $(REF countUntil, std,algorithm,searching)
   +/
@@ -901,30 +901,30 @@ private template _indexOfStr(CaseSensitive cs)
 }
 
 /++
-    Searches for substring in `s`.
+    Searches for a substring in a string or range.
 
     Params:
-        s = string or ForwardRange of characters to search in correct UTF format
-        sub = substring to search for
-        startIdx = the index into s to start searching from
-        cs = `Yes.caseSensitive` (default) or `No.caseSensitive`
+        s = string or ForwardRange of characters to search for `sub` in
+        sub = substring to search for in `s`
+        startIdx = index to a well-formed code point in `s` to start
+            searching from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
 
     Returns:
-        the index of the first occurrence of `sub` in `s` with
-        respect to the start index `startIdx`. If `sub` is not found,
-        then `-1` is returned.
-        If the arguments are not valid UTF, the result will still
-        be in the range [-1 .. s.length], but will not be reliable otherwise.
-        If `sub` is found the value of the returned index is at least
-        `startIdx`.
+        The index of the first occurrence of `sub` in `s`. If `sub` is not found
+        or `startIdx` is greater than or equal to `s.length`, then -1 is
+        returned. If the arguments are not valid UTF, the result will still be
+        either -1 or in the range [`startIdx` .. `s.length`], but will not be
+        reliable otherwise.
 
     Throws:
-        If the sequence starting at `startIdx` does not represent a well
-        formed codepoint, then a $(REF UTFException, std,utf) may be thrown.
+        If the sequence starting at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
 
     Bugs:
-        Does not work with case insensitive strings where the mapping of
-        tolower and toupper is not 1:1.
+        Does not work with case-insensitive strings where the mapping of
+        $(REF toLower, std,uni) and $(REF toUpper, std,uni) is not 1:1.
   +/
 ptrdiff_t indexOf(Range, Char)(Range s, const(Char)[] sub)
 if (isForwardRange!Range && isSomeChar!(ElementEncodingType!Range) &&
@@ -1156,23 +1156,26 @@ unittest
 }
 
 /++
+    Searches for the last occurrence of a character in a string.
+
     Params:
-        s = string to search
-        c = character to search for
-        startIdx = the index into s to start searching from
-        cs = `Yes.caseSensitive` or `No.caseSensitive`
+        s = string to search for `c` in
+        c = character to search for in `s`
+        startIdx = index of a well-formed code point in `s` to start searching
+            from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
 
     Returns:
-        The index of the last occurrence of `c` in `s`. If `c` is not
-        found, then `-1` is returned. The `startIdx` slices `s` in
-        the following way $(D s[0 .. startIdx]). `startIdx` represents a
-        codeunit index in `s`.
+        If `c` is found in `s`, then the index of its last occurrence is
+        returned. If `c` is not found or `startIdx` is greater than or equal to
+        `s.length`, then -1 is returned. If the parameters are not valid UTF,
+        the result will still be either -1 or in the range [`startIdx` ..
+        `s.length`], but will not be reliable otherwise.
 
     Throws:
-        If the sequence ending at `startIdx` does not represent a well
-        formed codepoint, then a $(REF UTFException, std,utf) may be thrown.
-
-    `cs` indicates whether the comparisons are case sensitive.
+        If the sequence ending at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
   +/
 ptrdiff_t lastIndexOf(Char)(const(Char)[] s, in dchar c,
         in CaseSensitive cs = Yes.caseSensitive) @safe pure
@@ -1345,23 +1348,30 @@ if (isSomeChar!Char)
 }
 
 /++
+    Searches for the last occurrence of a substring in a string.
+
     Params:
-        s = string to search
-        sub = substring to search for
-        startIdx = the index into s to start searching from
-        cs = `Yes.caseSensitive` or `No.caseSensitive`
+        s = string to search for `sub` in
+        sub = substring to search for in `s`
+        startIdx = index to a well-formed code point in `s` to start
+            searching from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
 
     Returns:
-        the index of the last occurrence of `sub` in `s`. If `sub` is
-        not found, then `-1` is returned. The `startIdx` slices `s`
-        in the following way $(D s[0 .. startIdx]). `startIdx` represents a
-        codeunit index in `s`.
+        The index of the last occurrence of `sub` in `s`. If `sub` is not found
+        or `startIdx` is greater than or equal to `s.length`, then -1 is
+        returned. If the parameters are not valid UTF, the result will still be
+        either -1 or in the range [`startIdx` .. `s.length`], but will not be
+        reliable otherwise.
 
     Throws:
-        If the sequence ending at `startIdx` does not represent a well
-        formed codepoint, then a $(REF UTFException, std,utf) may be thrown.
+        If the sequence starting at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
 
-    `cs` indicates whether the comparisons are case sensitive.
+    Bugs:
+        Does not work with case-insensitive strings where the mapping of
+        $(REF toLower, std,uni) and $(REF toUpper, std,uni) is not 1:1.
   +/
 ptrdiff_t lastIndexOf(Char1, Char2)(const(Char1)[] s, const(Char2)[] sub,
         in CaseSensitive cs = Yes.caseSensitive) @safe pure
@@ -1747,21 +1757,28 @@ if (isSomeChar!Char && isSomeChar!Char2)
 }
 
 /**
-    Returns the index of the first occurrence of any of the elements in $(D
-    needles) in `haystack`. If no element of `needles` is found,
-    then `-1` is returned. The `startIdx` slices `haystack` in the
-    following way $(D haystack[startIdx .. $]). `startIdx` represents a
-    codeunit index in `haystack`. If the sequence ending at `startIdx`
-    does not represent a well formed codepoint, then a $(REF UTFException, std,utf)
-    may be thrown.
+    Searches the string `haystack` for one of the characters in `needles`
+    starting at index `startIdx`. If `startIdx` is not given, it defaults to 0.
 
     Params:
-        haystack = String to search for needles in.
-        needles = Strings to search for in haystack.
-        startIdx = slices haystack like this $(D haystack[startIdx .. $]). If
-            the startIdx is greater than or equal to the length of haystack the
-            functions returns `-1`.
-        cs = Indicates whether the comparisons are case sensitive.
+        haystack = string to search for needles in
+        needles = characters to search for in `haystack`
+        startIdx = index of a well-formed code point in `haystack` to start
+            searching from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
+
+    Returns:
+        The index of the first occurrence of any of the elements of `needles` in
+        `haystack`. If no element of `needles` is found or `startIdx` is greater
+        than or equal to `haystack.length`, then -1 is returned. If the
+        parameters are not valid UTF, the result will still be either -1 or in
+        the range [`startIdx` .. `haystack.length`], but will not be reliable
+        otherwise.
+
+    Throws:
+        If the sequence starting at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
 */
 ptrdiff_t indexOfAny(Char,Char2)(const(Char)[] haystack, const(Char2)[] needles,
         in CaseSensitive cs = Yes.caseSensitive) @safe pure
@@ -1914,21 +1931,23 @@ if (isSomeChar!Char && isSomeChar!Char2)
 }
 
 /**
-    Returns the index of the last occurrence of any of the elements in $(D
-    needles) in `haystack`. If no element of `needles` is found,
-    then `-1` is returned. The `stopIdx` slices `haystack` in the
-    following way $(D s[0 .. stopIdx]). `stopIdx` represents a codeunit
-    index in `haystack`. If the sequence ending at `startIdx` does not
-    represent a well formed codepoint, then a $(REF UTFException, std,utf) may be
-    thrown.
+    Searches `haystack` for the last occurrence of any of the
+    characters in `needles`.
 
     Params:
-        haystack = String to search for needles in.
-        needles = Strings to search for in haystack.
-        stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]). If
-            the stopIdx is greater than or equal to the length of haystack the
-            functions returns `-1`.
-        cs = Indicates whether the comparisons are case sensitive.
+        haystack = string to search needles in
+        needles = characters to search for in `haystack`
+        stopIdx = index in `haystack` to stop searching at (exclusive); defaults
+            to `haystack.length`
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
+
+    Returns:
+        The index of the last occurrence of any of the characters of `needles`
+        in `haystack`. If no character of `needles` is found or `stopIdx` is 0,
+        then -1 is returned. If the parameters are not valid UTF, the result
+        will still be in the range [-1 .. `stopIdx`], but will not be reliable
+        otherwise.
 */
 ptrdiff_t lastIndexOfAny(Char,Char2)(const(Char)[] haystack,
         const(Char2)[] needles, in CaseSensitive cs = Yes.caseSensitive)
@@ -2097,17 +2116,27 @@ if (isSomeChar!Char && isSomeChar!Char2)
 }
 
 /**
-    Returns the index of the first occurrence of any character not an elements
-    in `needles` in `haystack`. If all element of `haystack` are
-    element of `needles` `-1` is returned.
+    Searches `haystack` for a character not in `needles`.
 
     Params:
-        haystack = String to search for needles in.
-        needles = Strings to search for in haystack.
-        startIdx = slices haystack like this $(D haystack[startIdx .. $]). If
-            the startIdx is greater than or equal to the length of haystack the
-            functions returns `-1`.
-        cs = Indicates whether the comparisons are case sensitive.
+        haystack = string to search for needles in
+        needles = characters to search for in `haystack`
+        startIdx = index of a well-formed code point in `haystack` to start
+            searching from; defaults to 0
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
+
+    Returns:
+        The index of the first character in `haystack` that is not an element of
+        `needles`. If all characters of `haystack` are elements of `needles` or
+        `startIdx` is greater than or equal to `haystack.length`, then -1 is
+        returned. If the parameters are not valid UTF, the result will still be
+        either -1 or in the range [`startIdx` .. `haystack.length`], but will
+        not be reliable otherwise.
+
+    Throws:
+        If the sequence starting at `startIdx` does not represent a well-formed
+        code point, then a $(REF UTFException, std,utf) may be thrown.
 */
 ptrdiff_t indexOfNeither(Char,Char2)(const(Char)[] haystack,
         const(Char2)[] needles, in CaseSensitive cs = Yes.caseSensitive)
@@ -2257,17 +2286,22 @@ if (isSomeChar!Char && isSomeChar!Char2)
 }
 
 /**
-    Returns the last index of the first occurence of any character that is not
-    an elements in `needles` in `haystack`. If all element of
-    `haystack` are element of `needles` `-1` is returned.
+    Searches for the last character in `haystack` that is not in `needles`.
 
     Params:
-        haystack = String to search for needles in.
-        needles = Strings to search for in haystack.
-        stopIdx = slices haystack like this $(D haystack[0 .. stopIdx]) If
-            the stopIdx is greater than or equal to the length of haystack the
-            functions returns `-1`.
-        cs = Indicates whether the comparisons are case sensitive.
+        haystack = string to search for needles in
+        needles = characters to search for in `haystack`
+        stopIdx = index in `haystack` to stop searching at (exclusive);
+            defaults to `haystack.length`
+        cs = specifies whether comparisons are case-sensitive
+            (`Yes.caseSensitive`) or not (`No.caseSensitive`)
+
+    Returns:
+        The index of the last character in `haystack` that is not an element of
+        `needles`. If all characters of `haystack` are in `needles` or `stopIdx`
+        is 0, then -1 is returned. If the parameters are not valid UTF, the
+        result will still be in the range [-1 .. `stopIdx`], but will not be
+        reliable otherwise.
 */
 ptrdiff_t lastIndexOfNeither(Char,Char2)(const(Char)[] haystack,
         const(Char2)[] needles, in CaseSensitive cs = Yes.caseSensitive)
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 5ed37a1f41838bdaf60d54bc1d0b7b8895b68308..69362c08695dd9d645a58232a705ad2db51f05ef 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -7367,10 +7367,12 @@ template isInstanceOf(alias S, alias T)
     static struct A(T = void)
     {
         // doesn't work as expected, only accepts A when T = void
-        void func(B)(B b) if (isInstanceOf!(A, B)) {}
+        void func(B)(B b)
+        if (isInstanceOf!(A, B)) {}
 
         // correct behavior
-        void method(B)(B b) if (isInstanceOf!(TemplateOf!(A), B)) {}
+        void method(B)(B b)
+        if (isInstanceOf!(TemplateOf!(A), B)) {}
     }
 
     A!(void) a1;
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index aceb2878d49cc76eb24656408cb2c20fd364d4fd..c874c0ff81166b822773efbdcc046d6232b050fc 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -2235,12 +2235,14 @@ template tuple(Names...)
             // e.g. Tuple!(int, "x", string, "y")
             template Interleave(A...)
             {
-                template and(B...) if (B.length == 1)
+                template and(B...)
+                if (B.length == 1)
                 {
                     alias and = AliasSeq!(A[0], B[0]);
                 }
 
-                template and(B...) if (B.length != 1)
+                template and(B...)
+                if (B.length != 1)
                 {
                     alias and = AliasSeq!(A[0], B[0],
                         Interleave!(A[1..$]).and!(B[1..$]));
@@ -5134,7 +5136,7 @@ Params:
             non-release mode.
  */
     void opAssign()(T value)
-        if (isAssignable!T) //@@@9416@@@
+    if (isAssignable!T) //@@@9416@@@
     {
         enum message = "Called `opAssign' on null NullableRef!" ~ T.stringof ~ ".";
         assert(!isNull, message);
@@ -5469,15 +5471,17 @@ nothrow pure @safe unittest
     }
 }
 
-// / ditto
+/// ditto
 class NotImplementedError : Error
 {
+    ///
     this(string method) nothrow pure @safe
     {
         super(method ~ " is not implemented");
     }
 }
 
+///
 @system unittest
 {
     import std.exception : assertThrown;
@@ -7498,7 +7502,8 @@ Constructor that initializes the payload.
 
 Postcondition: `refCountedStore.isInitialized`
  */
-    this(A...)(auto ref A args) if (A.length > 0)
+    this(A...)(auto ref A args)
+    if (A.length > 0)
     out
     {
         assert(refCountedStore.isInitialized);
@@ -7931,7 +7936,8 @@ template borrow(alias fun)
 {
     import std.functional : unaryFun;
 
-    auto ref borrow(RC)(RC refCount) if
+    auto ref borrow(RC)(RC refCount)
+    if
     (
         isInstanceOf!(SafeRefCounted, RC)
         && is(typeof(unaryFun!fun(refCount.refCountedPayload)))
@@ -8140,7 +8146,7 @@ mixin template Proxy(alias a)
         }
 
         bool opEquals(T)(T b)
-            if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
+        if (is(ValueType : T) || is(typeof(a.opEquals(b))) || is(typeof(b.opEquals(a))))
         {
             static if (is(typeof(a.opEquals(b))))
                 return a.opEquals(b);
@@ -8164,7 +8170,7 @@ mixin template Proxy(alias a)
         }
 
         int opCmp(T)(auto ref const T b)
-            if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
+        if (is(ValueType : T) || is(typeof(a.opCmp(b))) || is(typeof(b.opCmp(a))))
         {
             static if (is(typeof(a.opCmp(b))))
                 return a.opCmp(b);
@@ -8274,7 +8280,8 @@ mixin template Proxy(alias a)
         }
     }
 
-    auto ref opAssign     (this X, V      )(auto ref V v) if (!is(V == typeof(this))) { return a       = v; }
+    auto ref opAssign     (this X, V      )(auto ref V v)
+    if (!is(V == typeof(this))) { return a       = v; }
     auto ref opIndexAssign(this X, V, D...)(auto ref V v, auto ref D i)               { return a[i]    = v; }
     auto ref opSliceAssign(this X, V      )(auto ref V v)                             { return a[]     = v; }
     auto ref opSliceAssign(this X, V, B, E)(auto ref V v, auto ref B b, auto ref E e) { return a[b .. e] = v; }
@@ -9793,6 +9800,7 @@ Flag!"encryption".no).
 */
 struct Yes
 {
+    ///
     template opDispatch(string name)
     {
         enum opDispatch = Flag!name.yes;
@@ -9803,6 +9811,7 @@ struct Yes
 /// Ditto
 struct No
 {
+    ///
     template opDispatch(string name)
     {
         enum opDispatch = Flag!name.no;
@@ -9941,7 +9950,7 @@ public:
     }
 
     this(T...)(T flags)
-        if (allSatisfy!(isBaseEnumType, T))
+    if (allSatisfy!(isBaseEnumType, T))
     {
         this = flags;
     }
@@ -9952,19 +9961,19 @@ public:
     }
 
     Base opCast(B)() const
-        if (is(Base : B))
+    if (is(Base : B))
     {
         return mValue;
     }
 
     auto opUnary(string op)() const
-        if (op == "~")
+    if (op == "~")
     {
         return BitFlags(cast(E) cast(Base) ~mValue);
     }
 
     auto ref opAssign(T...)(T flags)
-        if (allSatisfy!(isBaseEnumType, T))
+    if (allSatisfy!(isBaseEnumType, T))
     {
         mValue = 0;
         foreach (E flag; flags)
@@ -10005,7 +10014,7 @@ public:
     }
 
     auto opBinary(string op)(BitFlags flags) const
-        if (op == "|" || op == "&")
+    if (op == "|" || op == "&")
     {
         BitFlags result = this;
         result.opOpAssign!op(flags);
@@ -10013,7 +10022,7 @@ public:
     }
 
     auto opBinary(string op)(E flag) const
-        if (op == "|" || op == "&")
+    if (op == "|" || op == "&")
     {
         BitFlags result = this;
         result.opOpAssign!op(flag);
@@ -10021,7 +10030,7 @@ public:
     }
 
     auto opBinaryRight(string op)(E flag) const
-        if (op == "|" || op == "&")
+    if (op == "|" || op == "&")
     {
         return opBinary!op(flag);
     }
@@ -10653,25 +10662,29 @@ struct Ternary
       $(TR $(TD `unknown`) $(TD `unknown`) $(TD) $(TD `unknown`) $(TD `unknown`) $(TD `unknown`))
     )
     */
-    Ternary opUnary(string s)() if (s == "~")
+    Ternary opUnary(string s)()
+    if (s == "~")
     {
         return make((386 >> value) & 6);
     }
 
     /// ditto
-    Ternary opBinary(string s)(Ternary rhs) if (s == "|")
+    Ternary opBinary(string s)(Ternary rhs)
+    if (s == "|")
     {
         return make((25_512 >> (value + rhs.value)) & 6);
     }
 
     /// ditto
-    Ternary opBinary(string s)(Ternary rhs) if (s == "&")
+    Ternary opBinary(string s)(Ternary rhs)
+    if (s == "&")
     {
         return make((26_144 >> (value + rhs.value)) & 6);
     }
 
     /// ditto
-    Ternary opBinary(string s)(Ternary rhs) if (s == "^")
+    Ternary opBinary(string s)(Ternary rhs)
+    if (s == "^")
     {
         return make((26_504 >> (value + rhs.value)) & 6);
     }
@@ -10937,7 +10950,8 @@ struct RefCounted(T, RefCountedAutoInitialize autoInit =
         return _refCounted;
     }
 
-    this(A...)(auto ref A args) if (A.length > 0)
+    this(A...)(auto ref A args)
+    if (A.length > 0)
     out
     {
         assert(refCountedStore.isInitialized);
diff --git a/libphobos/src/std/uni/package.d b/libphobos/src/std/uni/package.d
index f7610c022eb43baa35dfaad6f0d7664c074326fa..34d15e034ba1dc61ed555d4641e64c8d7b2ae96c 100644
--- a/libphobos/src/std/uni/package.d
+++ b/libphobos/src/std/uni/package.d
@@ -16,6 +16,7 @@ $(TR $(TD Decode) $(TD
     $(LREF byGrapheme)
     $(LREF decodeGrapheme)
     $(LREF graphemeStride)
+    $(LREF popGrapheme)
 ))
 $(TR $(TD Comparison) $(TD
     $(LREF icmp)
@@ -708,8 +709,8 @@ import std.meta : AliasSeq;
 import std.range.primitives : back, ElementEncodingType, ElementType, empty,
     front, hasLength, hasSlicing, isForwardRange, isInputRange,
     isRandomAccessRange, popFront, put, save;
-import std.traits : isConvertibleToString, isIntegral, isSomeChar,
-    isSomeString, Unqual, isDynamicArray;
+import std.traits : isAutodecodableString, isConvertibleToString, isIntegral,
+    isSomeChar, isSomeString, Unqual, isDynamicArray;
 // debug = std_uni;
 
 import std.internal.unicode_tables; // generated file
@@ -961,7 +962,7 @@ struct MultiArray(Types...)
     }
 
     void store(OutRange)(scope OutRange sink) const
-        if (isOutputRange!(OutRange, char))
+    if (isOutputRange!(OutRange, char))
     {
         import std.format.write : formattedWrite;
         formattedWrite(sink, "[%( 0x%x, %)]", offsets[]);
@@ -1652,7 +1653,7 @@ if (is(T : ElementType!Range))
 template sharMethod(alias uniLowerBound)
 {
     size_t sharMethod(alias _pred="a<b", Range, T)(Range range, T needle)
-        if (is(T : ElementType!Range))
+    if (is(T : ElementType!Range))
     {
         import std.functional : binaryFun;
         import std.math.algebraic : nextPow2, truncPow2;
@@ -1768,19 +1769,19 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
     }
 
     static void append(T, V)(ref T[] arr, V value)
-        if (!isInputRange!V)
+    if (!isInputRange!V)
     {
         arr ~= force!T(value);
     }
 
     static void append(T, V)(ref T[] arr, V value)
-        if (isInputRange!V)
+    if (isInputRange!V)
     {
         insertInPlace(arr, arr.length, value);
     }
 
     static void destroy(T)(ref T arr) pure // pure required for -dip25, inferred for -dip1000
-        if (isDynamicArray!T && is(Unqual!T == T))
+    if (isDynamicArray!T && is(Unqual!T == T))
     {
         debug
         {
@@ -1790,7 +1791,7 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
     }
 
     static void destroy(T)(ref T arr) pure // pure required for -dip25, inferred for -dip1000
-        if (isDynamicArray!T && !is(Unqual!T == T))
+    if (isDynamicArray!T && !is(Unqual!T == T))
     {
         arr = null;
     }
@@ -1845,7 +1846,7 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
     }
 
     static void append(T, V)(ref T[] arr, V value)
-        if (!isInputRange!V)
+    if (!isInputRange!V)
     {
         if (arr.length == size_t.max) assert(0);
         arr = realloc(arr, arr.length+1);
@@ -1862,7 +1863,7 @@ alias sharSwitchLowerBound = sharMethod!switchUniformLowerBound;
     }
 
     static void append(T, V)(ref T[] arr, V value)
-        if (isInputRange!V && hasLength!V)
+    if (isInputRange!V && hasLength!V)
     {
         import core.checkedint : addu;
         bool overflow;
@@ -2058,7 +2059,7 @@ public struct InversionList(SP=GcPolicy)
         Construct from another code point set of any type.
     */
     this(Set)(Set set) pure
-        if (isCodepointSet!Set)
+    if (isCodepointSet!Set)
     {
         uint[] arr;
         foreach (v; set.byInterval)
@@ -2073,7 +2074,7 @@ public struct InversionList(SP=GcPolicy)
         Construct a set from a forward range of code point intervals.
     */
     this(Range)(Range intervals) pure
-        if (isForwardRange!Range && isIntegralPair!(ElementType!Range))
+    if (isForwardRange!Range && isIntegralPair!(ElementType!Range))
     {
         uint[] arr;
         foreach (v; intervals)
@@ -2245,7 +2246,7 @@ public:
         )
     */
     This opBinary(string op, U)(U rhs)
-        if (isCodepointSet!U || is(U:dchar))
+    if (isCodepointSet!U || is(U:dchar))
     {
         static if (op == "&" || op == "|" || op == "~")
         {// symmetric ops thus can swap arguments to reuse r-value
@@ -2310,7 +2311,7 @@ public:
 
     /// The 'op=' versions of the above overloaded operators.
     ref This opOpAssign(string op, U)(U rhs)
-        if (isCodepointSet!U || is(U:dchar))
+    if (isCodepointSet!U || is(U:dchar))
     {
         static if (op == "|")    // union
         {
@@ -2342,7 +2343,7 @@ public:
         the same as $(LREF opIndex).
     */
     bool opBinaryRight(string op: "in", U)(U ch) const
-        if (is(U : dchar))
+    if (is(U : dchar))
     {
         return this[ch];
     }
@@ -2522,7 +2523,7 @@ private:
 
   package(std)  // used from: std.regex.internal.parser
     ref intersect(U)(U rhs)
-        if (isCodepointSet!U)
+    if (isCodepointSet!U)
     {
         Marker mark;
         foreach ( i; rhs.byInterval)
@@ -2556,7 +2557,7 @@ private:
     // same as the above except that skip & drop parts are swapped
   package(std)  // used from: std.regex.internal.parser
     ref sub(U)(U rhs)
-        if (isCodepointSet!U)
+    if (isCodepointSet!U)
     {
         Marker mark;
         foreach (i; rhs.byInterval)
@@ -2569,7 +2570,7 @@ private:
 
   package(std)  // used from: std.regex.internal.parse
     ref add(U)(U rhs)
-        if (isCodepointSet!U)
+    if (isCodepointSet!U)
     {
         Marker start;
         foreach (i; rhs.byInterval)
@@ -3206,7 +3207,7 @@ struct CowArray(SP=GcPolicy)
     }
 
     this(Range)(Range range)
-        if (isInputRange!Range && hasLength!Range)
+    if (isInputRange!Range && hasLength!Range)
     {
         import std.algorithm.mutation : copy;
         length = range.length;
@@ -3214,7 +3215,7 @@ struct CowArray(SP=GcPolicy)
     }
 
     this(Range)(Range range)
-        if (isForwardRange!Range && !hasLength!Range)
+    if (isForwardRange!Range && !hasLength!Range)
     {
         import std.algorithm.mutation : copy;
         import std.range.primitives : walkLength;
@@ -3336,7 +3337,7 @@ struct CowArray(SP=GcPolicy)
     }
 
     void append(Range)(Range range)
-        if (isInputRange!Range && hasLength!Range && is(ElementType!Range : uint))
+    if (isInputRange!Range && hasLength!Range && is(ElementType!Range : uint))
     {
         size_t nl = length + range.length;
         length = nl;
@@ -3793,7 +3794,7 @@ auto arrayRepr(T)(T x)
 template mapTrieIndex(Prefix...)
 {
     size_t mapTrieIndex(Key)(Key key)
-        if (isValidPrefixForTrie!(Key, Prefix))
+    if (isValidPrefixForTrie!(Key, Prefix))
     {
         alias p = Prefix;
         size_t idx;
@@ -4184,7 +4185,7 @@ if (isValidPrefixForTrie!(Key, Args)
 
     ///
     void store(OutRange)(scope OutRange sink) const
-        if (isOutputRange!(OutRange, char))
+    if (isOutputRange!(OutRange, char))
     {
         _table.store(sink);
     }
@@ -4285,7 +4286,7 @@ public template codepointSetTrie(sizes...)
 if (sumOfIntegerTuple!sizes == 21)
 {
     auto codepointSetTrie(Set)(Set set)
-        if (isCodepointSet!Set)
+    if (isCodepointSet!Set)
     {
         auto builder = TrieBuilder!(bool, dchar, lastDchar+1, GetBitSlicing!(21, sizes))(false);
         foreach (ival; set.byInterval)
@@ -4322,7 +4323,7 @@ if (sumOfIntegerTuple!sizes == 21)
     static if (is(TypeOfBitPacked!T == bool))
     {
         auto codepointTrie(Set)(const scope Set set)
-            if (isCodepointSet!Set)
+        if (isCodepointSet!Set)
         {
             return codepointSetTrie(set);
         }
@@ -4337,9 +4338,9 @@ if (sumOfIntegerTuple!sizes == 21)
     // unsorted range of pairs
     ///
     auto codepointTrie(R)(R range, T defValue=T.init)
-        if (isInputRange!R
-            && is(typeof(ElementType!R.init[0]) : T)
-            && is(typeof(ElementType!R.init[1]) : dchar))
+    if (isInputRange!R
+        && is(typeof(ElementType!R.init[0]) : T)
+        && is(typeof(ElementType!R.init[1]) : dchar))
     {
         // build from unsorted array of pairs
         // TODO: expose index sorting functions for Trie
@@ -4467,8 +4468,8 @@ if (isValidArgsForTrie!(Key, Args))
         $(REF setUnion, std,_algorithm).
     */
     auto buildTrie(Range)(Range range, Value filler=Value.init)
-        if (isInputRange!Range && is(typeof(Range.init.front[0]) : Value)
-            && is(typeof(Range.init.front[1]) : Key))
+    if (isInputRange!Range && is(typeof(Range.init.front[0]) : Value)
+        && is(typeof(Range.init.front[1]) : Key))
     {
         auto builder = TrieBuilder!(Value, Key, Prefix)(filler);
         foreach (v; range)
@@ -4487,9 +4488,9 @@ if (isValidArgsForTrie!(Key, Args))
         and `filler` is false.
     */
     auto buildTrie(Range)(Range range, Value filler=Value.init)
-        if (is(TypeOfBitPacked!Value ==  bool)
-            && isInputRange!Range && is(typeof(Range.init.front[0]) : Key)
-            && is(typeof(Range.init.front[1]) : Key))
+    if (is(TypeOfBitPacked!Value ==  bool)
+        && isInputRange!Range && is(typeof(Range.init.front[0]) : Key)
+        && is(typeof(Range.init.front[1]) : Key))
     {
         auto builder = TrieBuilder!(Value, Key, Prefix)(filler);
         foreach (ival; range)
@@ -4498,9 +4499,9 @@ if (isValidArgsForTrie!(Key, Args))
     }
 
     auto buildTrie(Range)(Range range, Value filler, bool unsorted)
-        if (isInputRange!Range
-            && is(typeof(Range.init.front[0]) : Value)
-            && is(typeof(Range.init.front[1]) : Key))
+    if (isInputRange!Range
+        && is(typeof(Range.init.front[0]) : Value)
+        && is(typeof(Range.init.front[1]) : Key))
     {
         import std.algorithm.sorting : multiSort;
         alias Comps = GetComparators!(Prefix.length);
@@ -4519,8 +4520,8 @@ if (isValidArgsForTrie!(Key, Args))
         If no filler provided keys map to true, and `filler` is false.
     */
     auto buildTrie(Range)(Range range, Value filler=Value.init)
-        if (is(TypeOfBitPacked!Value ==  bool)
-            && isInputRange!Range && is(typeof(Range.init.front) : Key))
+    if (is(TypeOfBitPacked!Value ==  bool)
+        && isInputRange!Range && is(typeof(Range.init.front) : Key))
     {
         auto builder = TrieBuilder!(Value, Key, Prefix)(filler);
         foreach (v; range)
@@ -4533,7 +4534,7 @@ if (isValidArgsForTrie!(Key, Args))
         of values where array index serves as key.
     */
     auto buildTrie()(Value[] array, Value filler=Value.init)
-        if (isUnsigned!Key)
+    if (isUnsigned!Key)
     {
         auto builder = TrieBuilder!(Value, Key, Prefix)(filler);
         foreach (idx, v; array)
@@ -4595,21 +4596,21 @@ public struct MatcherConcept
         of the result of test.)
     */
     public bool match(Range)(ref Range inp)
-        if (isRandomAccessRange!Range && is(ElementType!Range : char))
+    if (isRandomAccessRange!Range && is(ElementType!Range : char))
     {
        assert(false);
     }
 
     ///ditto
     public bool skip(Range)(ref Range inp)
-        if (isRandomAccessRange!Range && is(ElementType!Range : char))
+    if (isRandomAccessRange!Range && is(ElementType!Range : char))
     {
         assert(false);
     }
 
     ///ditto
     public bool test(Range)(ref Range inp)
-        if (isRandomAccessRange!Range && is(ElementType!Range : char))
+    if (isRandomAccessRange!Range && is(ElementType!Range : char))
     {
         assert(false);
     }
@@ -4765,7 +4766,7 @@ template Utf8Matcher()
     }
 
     static auto encode(size_t sz)(dchar ch)
-        if (sz > 1)
+    if (sz > 1)
     {
         import std.utf : encodeUTF = encode;
         char[4] buf;
@@ -4821,8 +4822,8 @@ template Utf8Matcher()
         enum dispatch = genDispatch();
 
         public bool match(Range)(ref Range inp) const
-            if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
-                !isDynamicArray!Range)
+        if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
+            !isDynamicArray!Range)
         {
             enum mode = Mode.skipOnMatch;
             assert(!inp.empty);
@@ -4846,8 +4847,8 @@ template Utf8Matcher()
         static if (Sizes.length == 4) // can skip iff can detect all encodings
         {
             public bool skip(Range)(ref Range inp) const
-                if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
-                    !isDynamicArray!Range)
+            if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
+                !isDynamicArray!Range)
             {
                 enum mode = Mode.alwaysSkip;
                 assert(!inp.empty);
@@ -4868,8 +4869,8 @@ template Utf8Matcher()
         }
 
         public bool test(Range)(ref Range inp) const
-            if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
-                !isDynamicArray!Range)
+        if (isRandomAccessRange!Range && is(ElementType!Range : char) &&
+            !isDynamicArray!Range)
         {
             enum mode = Mode.neverSkip;
             assert(!inp.empty);
@@ -4887,19 +4888,19 @@ template Utf8Matcher()
         }
 
         bool match(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"match"(str);
         }
 
         bool skip(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"skip"(str);
         }
 
         bool test(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"test"(str);
         }
@@ -5056,8 +5057,8 @@ template Utf16Matcher()
     mixin template DefMatcher()
     {
         public bool match(Range)(ref Range inp) const
-            if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
-                !isDynamicArray!Range)
+        if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
+            !isDynamicArray!Range)
         {
             enum mode = Mode.skipOnMatch;
             assert(!inp.empty);
@@ -5083,8 +5084,8 @@ template Utf16Matcher()
         static if (Sizes.length == 2)
         {
             public bool skip(Range)(ref Range inp) const
-                if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
-                    !isDynamicArray!Range)
+            if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
+                !isDynamicArray!Range)
             {
                 enum mode = Mode.alwaysSkip;
                 assert(!inp.empty);
@@ -5105,8 +5106,8 @@ template Utf16Matcher()
         }
 
         public bool test(Range)(ref Range inp) const
-            if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
-                !isDynamicArray!Range)
+        if (isRandomAccessRange!Range && is(ElementType!Range : wchar) &&
+            !isDynamicArray!Range)
         {
             enum mode = Mode.neverSkip;
             assert(!inp.empty);
@@ -5118,19 +5119,19 @@ template Utf16Matcher()
         }
 
         bool match(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"match"(str);
         }
 
         bool skip(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"skip"(str);
         }
 
         bool test(C)(ref C[] str) const
-            if (isSomeChar!C)
+        if (isSomeChar!C)
         {
             return fwdStr!"test"(str);
         }
@@ -5139,7 +5140,7 @@ template Utf16Matcher()
     }
 
     struct Impl(Sizes...)
-        if (Sizes.length >= 1 && Sizes.length <= 2)
+    if (Sizes.length >= 1 && Sizes.length <= 2)
     {
     private:
         import std.meta : allSatisfy;
@@ -5229,7 +5230,7 @@ template Utf16Matcher()
     }
 
     struct CherryPick(I, Sizes...)
-        if (Sizes.length >= 1 && Sizes.length <= 2)
+    if (Sizes.length >= 1 && Sizes.length <= 2)
     {
     private:
         import std.meta : allSatisfy;
@@ -6105,7 +6106,7 @@ template SetSearcher(alias table, string kind)
 {
     /// Run-time checked search.
     static auto opCall(C)(const scope C[] name)
-        if (is(C : dchar))
+    if (is(C : dchar))
     {
         import std.conv : to;
         CodepointSet set;
@@ -6765,7 +6766,7 @@ struct UnicodeSetParser(Range)
         sets.
     */
     static auto opCall(C)(const scope C[] name)
-        if (is(C : dchar))
+    if (is(C : dchar))
     {
         return loadAny(name);
     }
@@ -7148,17 +7149,25 @@ private immutable TransformRes
             TransformRes.goOn
 ];
 
-template genericDecodeGrapheme(bool getValue)
-{
-    static if (getValue)
+enum GraphemeRet { none, step, value }
+
+template genericDecodeGrapheme(GraphemeRet retType)
+{   alias Ret = GraphemeRet;
+
+    static if (retType == Ret.value)
         alias Value = Grapheme;
-    else
+    else static if (retType == Ret.step)
+        alias Value = size_t;
+    else static if (retType == Ret.none)
         alias Value = void;
 
     Value genericDecodeGrapheme(Input)(ref Input range)
     {
-        static if (getValue)
-            Grapheme grapheme;
+        static if (retType == Ret.value)
+            Grapheme result;
+        else static if (retType == Ret.step)
+            size_t result = 0;
+
         auto state = GraphemeState.Start;
         dchar ch;
 
@@ -7173,8 +7182,10 @@ template genericDecodeGrapheme(bool getValue)
                 with(TransformRes)
             {
             case goOn:
-                static if (getValue)
-                    grapheme ~= ch;
+                static if (retType == Ret.value)
+                    result ~= ch;
+                else static if (retType == Ret.step)
+                    result++;
                 range.popFront();
                 continue;
 
@@ -7182,8 +7193,10 @@ template genericDecodeGrapheme(bool getValue)
                 goto rerun;
 
             case retInclude:
-                static if (getValue)
-                    grapheme ~= ch;
+                static if (retType == Ret.value)
+                    result ~= ch;
+                else static if (retType == Ret.step)
+                    result++;
                 range.popFront();
                 break outer;
 
@@ -7192,8 +7205,8 @@ template genericDecodeGrapheme(bool getValue)
             }
         }
 
-        static if (getValue)
-            return grapheme;
+        static if (retType != Ret.none)
+            return result;
     }
 }
 
@@ -7217,7 +7230,7 @@ if (is(C : dchar))
 {
     auto src = input[index..$];
     auto n = src.length;
-    genericDecodeGrapheme!(false)(src);
+    genericDecodeGrapheme!(GraphemeRet.none)(src);
     return n - src.length;
 }
 
@@ -7279,7 +7292,7 @@ if (is(C : dchar))
 Grapheme decodeGrapheme(Input)(ref Input inp)
 if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar))
 {
-    return genericDecodeGrapheme!true(inp);
+    return genericDecodeGrapheme!(GraphemeRet.value)(inp);
 }
 
 @safe unittest
@@ -7304,6 +7317,73 @@ if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar))
     assert(equal(decodeGrapheme(s)[], "\U0001F1EC\U0001F1E7"));
 }
 
+/++
+    Reads one full grapheme cluster from an
+    $(REF_ALTTEXT input range, isInputRange, std,range,primitives) of dchar `inp`,
+    but doesn't return it. Instead returns the number of code units read.
+    This differs from number of code points read only if `input` is an
+    autodecodable string.
+
+    Note:
+    This function modifies `inp` and thus `inp`
+    must be an L-value.
++/
+size_t popGrapheme(Input)(ref Input inp)
+if (isInputRange!Input && is(immutable ElementType!Input == immutable dchar))
+{
+    static if (isAutodecodableString!Input || hasLength!Input)
+    {
+        // Why count each step in the decoder when you can just
+        // measure the grapheme in one go?
+        auto n = inp.length;
+        genericDecodeGrapheme!(GraphemeRet.none)(inp);
+        return n - inp.length;
+    }
+    else return genericDecodeGrapheme!(GraphemeRet.step)(inp);
+}
+
+///
+@safe pure unittest
+{
+    // Two Union Jacks of the Great Britain in each
+    string s = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7";
+    wstring ws = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7";
+    dstring ds = "\U0001F1EC\U0001F1E7\U0001F1EC\U0001F1E7";
+
+    // String pop length in code units, not points.
+    assert(s.popGrapheme() == 8);
+    assert(ws.popGrapheme() == 4);
+    assert(ds.popGrapheme() == 2);
+
+    assert(s == "\U0001F1EC\U0001F1E7");
+    assert(ws == "\U0001F1EC\U0001F1E7");
+    assert(ds == "\U0001F1EC\U0001F1E7");
+
+    import std.algorithm.comparison : equal;
+    import std.algorithm.iteration : filter;
+
+    // Also works for non-random access ranges as long as the
+    // character type is 32-bit.
+    auto testPiece = "\r\nhello!"d.filter!(x => !x.isAlpha);
+    // Windows-style line ending is two code points in a single grapheme.
+    assert(testPiece.popGrapheme() == 2);
+    assert(testPiece.equal("!"d));
+}
+
+// Attribute compliance test. Should be nothrow `@nogc` when
+// no autodecoding needed.
+@safe pure nothrow @nogc unittest
+{
+    import std.algorithm.iteration : filter;
+
+    auto str = "abcdef"d;
+    assert(str.popGrapheme() == 1);
+
+    // also test with non-random access
+    auto filtered = "abcdef"d.filter!(x => x%2);
+    assert(filtered.popGrapheme() == 1);
+}
+
 /++
     $(P Iterate a string by $(LREF Grapheme).)
 
@@ -7556,15 +7636,15 @@ if (isInputRange!Range && is(immutable ElementType!Range == immutable dchar))
 public:
     /// Ctor
     this(C)(const scope C[] chars...)
-        if (is(C : dchar))
+    if (is(C : dchar))
     {
         this ~= chars;
     }
 
     ///ditto
     this(Input)(Input seq)
-        if (!isDynamicArray!Input
-            && isInputRange!Input && is(ElementType!Input : dchar))
+    if (!isDynamicArray!Input
+        && isInputRange!Input && is(ElementType!Input : dchar))
     {
         this ~= seq;
     }
@@ -7683,7 +7763,7 @@ public:
 
     /// Append all $(CHARACTERS) from the input range `inp` to this Grapheme.
     ref opOpAssign(string op, Input)(scope Input inp)
-        if (isInputRange!Input && is(ElementType!Input : dchar))
+    if (isInputRange!Input && is(ElementType!Input : dchar))
     {
         static if (op == "~")
         {
@@ -7722,7 +7802,7 @@ public:
     @property bool valid()() /*const*/
     {
         auto r = this[];
-        genericDecodeGrapheme!false(r);
+        genericDecodeGrapheme!(GraphemeRet.none)(r);
         return r.length == 0;
     }
 
@@ -9868,7 +9948,7 @@ private template toCaseInPlaceAlloc(alias indexFn, uint maxIdx, alias tableFn)
 {
     void toCaseInPlaceAlloc(C)(ref C[] s, size_t curIdx,
         size_t destIdx) @trusted pure
-        if (is(C == char) || is(C == wchar) || is(C == dchar))
+    if (is(C == char) || is(C == wchar) || is(C == dchar))
     {
         import std.utf : decode;
         alias caseLength = toCaseLength!(indexFn, maxIdx, tableFn);
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index 9a326a5ac3aff8ed471f0fbce3388b7f9c0e591c..7db120befd5ec74fdc0310ca511831f27b304e3a 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -4303,13 +4303,13 @@ if (isSomeChar!C)
     else:
 
     auto ref byUTF(R)(R r)
-        if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R))
+    if (isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R))
     {
         return byUTF(r.byCodeUnit());
     }
 
     auto ref byUTF(R)(R r)
-        if (!isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R))
+    if (!isAutodecodableString!R && isInputRange!R && isSomeChar!(ElementEncodingType!R))
     {
         static if (is(immutable ElementEncodingType!R == immutable RC, RC) && is(RC == C))
         {
diff --git a/libphobos/src/std/uuid.d b/libphobos/src/std/uuid.d
index b8cac6ecdd7e6e5b3d6e78d4f32c1e6cb894f6ee..09ce2f73f380c1da4da4714210d8d47b9c25c900 100644
--- a/libphobos/src/std/uuid.d
+++ b/libphobos/src/std/uuid.d
@@ -275,7 +275,7 @@ public struct UUID
          * You need to pass exactly 16 ubytes.
          */
         @safe pure this(T...)(T uuidData)
-            if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
+        if (uuidData.length == 16 && allSatisfy!(isIntegral, T))
         {
             import std.conv : to;
 
@@ -331,7 +331,8 @@ public struct UUID
          *
          * For a less strict parser, see $(LREF parseUUID)
          */
-        this(T)(in T[] uuid) if (isSomeChar!T)
+        this(T)(in T[] uuid)
+        if (isSomeChar!T)
         {
             import std.conv : to, parse;
             if (uuid.length < 36)
diff --git a/libphobos/src/std/variant.d b/libphobos/src/std/variant.d
index f7832104d701b6ae9bbcbf1167a22ae5d566fd3d..a0b564440120ed0ca96b8fdfee0f4161f8519565 100644
--- a/libphobos/src/std/variant.d
+++ b/libphobos/src/std/variant.d
@@ -658,7 +658,7 @@ public:
 
     /// Allows assignment from a subset algebraic type
     this(T : VariantN!(tsize, Types), size_t tsize, Types...)(T value)
-        if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
+    if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
     {
         opAssign(value);
     }
@@ -735,7 +735,7 @@ public:
 
     // Allow assignment from another variant which is a subset of this one
     VariantN opAssign(T : VariantN!(tsize, Types), size_t tsize, Types...)(T rhs)
-        if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
+    if (!is(T : VariantN) && Types.length > 0 && allSatisfy!(allowed, Types))
     {
         // discover which type rhs is actually storing
         foreach (V; T.AllowedTypes)
@@ -1098,7 +1098,7 @@ public:
     { return opLogic!(T, op)(lhs); }
     ///ditto
     VariantN opBinary(string op, T)(T rhs)
-        if (op == "~")
+    if (op == "~")
     {
         auto temp = this;
         temp ~= rhs;
@@ -1191,7 +1191,8 @@ public:
        If the `VariantN` contains an array, applies `dg` to each
        element of the array in turn. Otherwise, throws an exception.
      */
-    int opApply(Delegate)(scope Delegate dg) if (is(Delegate == delegate))
+    int opApply(Delegate)(scope Delegate dg)
+    if (is(Delegate == delegate))
     {
         alias A = Parameters!(Delegate)[0];
         if (type == typeid(A[]))
@@ -2410,7 +2411,7 @@ if (Handlers.length > 0)
 {
     ///
     auto visit(VariantType)(VariantType variant)
-        if (isAlgebraic!VariantType)
+    if (isAlgebraic!VariantType)
     {
         return visitImpl!(true, VariantType, Handlers)(variant);
     }
@@ -2553,7 +2554,7 @@ if (Handlers.length > 0)
 {
     ///
     auto tryVisit(VariantType)(VariantType variant)
-        if (isAlgebraic!VariantType)
+    if (isAlgebraic!VariantType)
     {
         return visitImpl!(false, VariantType, Handlers)(variant);
     }