[committed] d: Merge dmd, druntime 34875cd6e1, phobos ebd24da8a

Message ID 20250110211247.438525-1-ibuclaw@gdcproject.org
State New
Headers
Series [committed] d: Merge dmd, druntime 34875cd6e1, phobos ebd24da8a |

Checks

Context Check Description
linaro-tcwg-bot/tcwg_gcc_build--master-aarch64 fail Patch failed to apply
linaro-tcwg-bot/tcwg_gcc_build--master-arm fail Patch failed to apply

Commit Message

Iain Buclaw Jan. 10, 2025, 9:12 p.m. UTC
  Hi,

This patch merges the D front-end and runtime library with upstream dmd
34875cd6e1, and the standard library with phobos ebd24da8a.

Synchronizing with the upstream release of v2.110.0-beta.1.

D front-end changes:

        - Import dmd v2.110.0-beta.1.
        - `ref' can now be applied to local, static, extern, and global
	  variables.

D runtime changes:

        - Import druntime v2.110.0-beta.1.

Phobos changes:

        - Import phobos v2.110.0-beta.1.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 34875cd6e1.
	* dmd/VERSION: Bump version to v2.110.0-beta.1.
	* Make-lang.in (D_FRONTEND_OBJS): Add d/deps.o, d/timetrace.o.
	* decl.cc (class DeclVisitor): Update for new front-end interface.
	* expr.cc (class ExprVisitor): Likewise
	* typeinfo.cc (check_typeinfo_type): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 34875cd6e1.
	* src/MERGE: Merge upstream phobos ebd24da8a.
---
 gcc/d/Make-lang.in                            |   2 +
 gcc/d/decl.cc                                 |   4 +-
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/README.md                           |   2 +
 gcc/d/dmd/VERSION                             |   2 +-
 gcc/d/dmd/access.d                            |   2 +-
 gcc/d/dmd/arrayop.d                           |   9 +-
 gcc/d/dmd/attrib.d                            |   5 +-
 gcc/d/dmd/canthrow.d                          |   6 +-
 gcc/d/dmd/clone.d                             |   5 +-
 gcc/d/dmd/common/bitfields.d                  |  72 +-
 gcc/d/dmd/cppmangle.d                         |   6 +-
 gcc/d/dmd/cxxfrontend.d                       |  12 +
 gcc/d/dmd/dcast.d                             |  26 +-
 gcc/d/dmd/dclass.d                            |   3 +-
 gcc/d/dmd/declaration.d                       |  15 +-
 gcc/d/dmd/declaration.h                       |   7 +-
 gcc/d/dmd/delegatize.d                        |   9 +-
 gcc/d/dmd/deps.d                              | 141 +++
 gcc/d/dmd/dinterpret.d                        |  25 +
 gcc/d/dmd/dmacro.d                            |   8 +-
 gcc/d/dmd/dmodule.d                           |   5 +
 gcc/d/dmd/dscope.d                            | 135 ++-
 gcc/d/dmd/dsymbol.d                           |  16 +-
 gcc/d/dmd/dsymbol.h                           |   3 +-
 gcc/d/dmd/dsymbolsem.d                        | 214 ++--
 gcc/d/dmd/dtemplate.d                         |  22 +-
 gcc/d/dmd/enumsem.d                           |  10 +-
 gcc/d/dmd/escape.d                            | 926 ++++++------------
 gcc/d/dmd/expressionsem.d                     | 148 ++-
 gcc/d/dmd/func.d                              |  26 +-
 gcc/d/dmd/funcsem.d                           |  17 +-
 gcc/d/dmd/globals.d                           |   5 +
 gcc/d/dmd/globals.h                           |   3 +
 gcc/d/dmd/hdrgen.d                            |  27 +-
 gcc/d/dmd/importc.d                           |   8 +-
 gcc/d/dmd/initsem.d                           |  14 +-
 gcc/d/dmd/lexer.d                             |  18 +-
 gcc/d/dmd/mtype.d                             | 328 +------
 gcc/d/dmd/mtype.h                             |  28 +-
 gcc/d/dmd/nogc.d                              |   6 +-
 gcc/d/dmd/ob.d                                |   2 +-
 gcc/d/dmd/opover.d                            |  14 +-
 gcc/d/dmd/root/filename.d                     |   8 +-
 gcc/d/dmd/root/rmem.d                         |   3 +
 gcc/d/dmd/safe.d                              |   4 +-
 gcc/d/dmd/scope.h                             |  61 +-
 gcc/d/dmd/semantic2.d                         |  95 +-
 gcc/d/dmd/semantic3.d                         |  31 +-
 gcc/d/dmd/sideeffect.d                        |   2 +-
 gcc/d/dmd/statementsem.d                      |  35 +-
 gcc/d/dmd/templatesem.d                       |   8 +-
 gcc/d/dmd/timetrace.d                         |  82 ++
 gcc/d/dmd/traits.d                            |  17 +-
 gcc/d/dmd/typesem.d                           | 385 +++++++-
 gcc/d/dmd/typinf.d                            |   2 +-
 gcc/d/dmd/utils.d                             |  74 +-
 gcc/d/expr.cc                                 |   2 +-
 gcc/d/typeinfo.cc                             |   4 +-
 .../gdc.test/compilable/header18365.d         |   2 +-
 gcc/testsuite/gdc.test/compilable/scope.d     | 113 +++
 .../gdc.test/fail_compilation/bug9631.d       |   2 +-
 .../gdc.test/fail_compilation/diag9679.d      |  66 +-
 .../gdc.test/fail_compilation/fail13902.d     |  25 +-
 .../gdc.test/fail_compilation/fail19948.d     |   4 +-
 .../gdc.test/fail_compilation/fail20183.d     |  14 +-
 .../gdc.test/fail_compilation/fail347.d       |  13 +-
 .../gdc.test/fail_compilation/retscope.d      |  22 +-
 .../gdc.test/fail_compilation/retscope3.d     |   2 +-
 .../gdc.test/fail_compilation/retscope6.d     |  38 +-
 .../fail_compilation/staticassert_sema1.d     |  39 +
 .../gdc.test/fail_compilation/test14238.d     |  18 +-
 .../gdc.test/fail_compilation/test18644.d     |   6 +-
 .../gdc.test/fail_compilation/test22977.d     |   2 +-
 .../gdc.test/fail_compilation/test23022.d     |   2 +-
 .../gdc.test/fail_compilation/test24680.d     |  20 +
 .../gdc.test/fail_compilation/typeerrors.d    |  11 +-
 .../gdc.test/fail_compilation/verrors5.d      |   1 +
 gcc/testsuite/gdc.test/runnable/declaration.d |  29 +
 gcc/testsuite/gdc.test/runnable/link11069a.d  |   2 +-
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/core/cpuid.d            |   6 +-
 libphobos/libdruntime/core/demangle.d         |   6 +-
 .../core/internal/array/concatenation.d       |   2 +-
 .../core/internal/array/construction.d        |   2 +-
 libphobos/libdruntime/core/internal/atomic.d  |   2 +-
 libphobos/libdruntime/core/internal/convert.d |   4 +-
 libphobos/libdruntime/core/internal/gc/bits.d |   2 +-
 .../core/internal/gc/impl/conservative/gc.d   |  23 +-
 libphobos/libdruntime/core/stdc/fenv.d        |   2 +-
 libphobos/libdruntime/core/stdc/stdatomic.d   |   5 +-
 libphobos/libdruntime/core/stdc/stdint.d      |   8 +
 libphobos/libdruntime/core/stdc/wctype.d      |  54 +-
 .../libdruntime/core/stdcpp/string_view.d     |   2 +-
 libphobos/libdruntime/core/sys/posix/signal.d |   8 +-
 .../libdruntime/core/sys/posix/sys/resource.d |  16 +-
 libphobos/libdruntime/core/sys/windows/dll.d  |  26 +-
 libphobos/libdruntime/core/time.d             |   5 +-
 libphobos/libdruntime/object.d                |  19 +-
 libphobos/libdruntime/rt/aaA.d                |  10 +-
 libphobos/libdruntime/rt/cast_.d              |   2 +-
 libphobos/libdruntime/rt/config.d             |   3 +-
 libphobos/libdruntime/rt/dmain2.d             |  27 +-
 libphobos/libdruntime/rt/lifetime.d           |  14 +-
 libphobos/libdruntime/rt/monitor_.d           |   8 +-
 libphobos/libdruntime/rt/util/typeinfo.d      |  12 +-
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/algorithm/mutation.d        |  23 +
 libphobos/src/std/algorithm/sorting.d         |   6 +-
 libphobos/src/std/array.d                     |  29 +
 libphobos/src/std/bitmanip.d                  |   2 +-
 libphobos/src/std/datetime/date.d             |  18 +-
 libphobos/src/std/datetime/timezone.d         |   8 +-
 libphobos/src/std/exception.d                 |   4 +-
 .../allocator/building_blocks/package.d       |   4 +-
 .../allocator/building_blocks/region.d        |   4 +-
 .../building_blocks/stats_collector.d         |   2 +-
 .../std/experimental/allocator/mallocator.d   |   2 +-
 .../experimental/allocator/mmap_allocator.d   |   2 +-
 libphobos/src/std/format/internal/read.d      |   9 +-
 libphobos/src/std/format/package.d            |   2 +-
 libphobos/src/std/json.d                      |  29 +-
 libphobos/src/std/math/exponential.d          | 422 ++++----
 libphobos/src/std/numeric.d                   |   2 +-
 libphobos/src/std/outbuffer.d                 |   9 +-
 libphobos/src/std/parallelism.d               |  19 +-
 libphobos/src/std/range/package.d             | 224 +++--
 libphobos/src/std/stdio.d                     | 117 +--
 libphobos/src/std/typecons.d                  |  72 +-
 libphobos/src/std/utf.d                       |   2 +-
 130 files changed, 2633 insertions(+), 2232 deletions(-)
 create mode 100644 gcc/d/dmd/deps.d
 create mode 100644 gcc/d/dmd/timetrace.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/staticassert_sema1.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24680.d
  

Patch

diff --git a/gcc/d/Make-lang.in b/gcc/d/Make-lang.in
index 914d54b0bb2..679ef579a11 100644
--- a/gcc/d/Make-lang.in
+++ b/gcc/d/Make-lang.in
@@ -113,6 +113,7 @@  D_FRONTEND_OBJS = \
 	d/declaration.o \
 	d/delegatize.o \
 	d/denum.o \
+	d/deps.o \
 	d/dimport.o \
 	d/dinterpret.o \
 	d/dmacro.o \
@@ -201,6 +202,7 @@  D_FRONTEND_OBJS = \
 	d/target.o \
 	d/templateparamsem.o \
 	d/templatesem.o \
+	d/timetrace.o \
 	d/tokens.o \
 	d/traits.o \
 	d/transitivevisitor.o \
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 6f1be64ba04..b20f6844c14 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -727,7 +727,7 @@  public:
       create_typeinfo (d->type, NULL);
 
     TypeEnum *tc = d->type->isTypeEnum ();
-    if (tc->sym->members && !d->type->isZeroInit ())
+    if (tc->sym->members && !dmd::isZeroInit (d->type))
       {
 	/* Generate static initializer.  */
 	d->sinit = enum_initializer_decl (d);
@@ -821,7 +821,7 @@  public:
 		DECL_INITIAL (decl) = build_expr (e, true);
 	      }
 	  }
-	else if (!d->type->isZeroInit ())
+	else if (!dmd::isZeroInit (d->type))
 	  {
 	    /* Use default initializer for the type.  */
 	    if (TypeStruct *ts = d->type->isTypeStruct ())
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index d458bea5e1a..a6072c4570d 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
+34875cd6e1faa42e84ae953c0485ef524fe67e38
 
 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 07875943151..00bbf84b6a1 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -43,6 +43,8 @@ 
 | [errorsink.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/errorsink.d) | Error reporting interface                                             |
 | [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                        |
+| [timetrace.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/timetrace.d) | Build time profiling utility                                          |
 
 ### Lexing / parsing
 
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index ffc1c3e86df..eef25e22dee 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.109.1
+v2.110.0-beta.1
diff --git a/gcc/d/dmd/access.d b/gcc/d/dmd/access.d
index 8d022030173..f29755bbfdf 100644
--- a/gcc/d/dmd/access.d
+++ b/gcc/d/dmd/access.d
@@ -163,7 +163,7 @@  private bool hasProtectedAccess(Scope *sc, Dsymbol s)
  */
 bool checkAccess(Loc loc, Scope* sc, Expression e, Dsymbol d)
 {
-    if (sc.flags & SCOPE.noaccesscheck)
+    if (sc.noAccessCheck)
         return false;
     static if (LOG)
     {
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index e30160d72b9..5fe5273d5ad 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -287,9 +287,8 @@  bool isUnaArrayOp(EXP op) @safe
     case EXP.tilde:
         return true;
     default:
-        break;
+        return false;
     }
-    return false;
 }
 
 /***********************************************
@@ -310,9 +309,8 @@  bool isBinArrayOp(EXP op) @safe
     case EXP.pow:
         return true;
     default:
-        break;
+        return false;
     }
-    return false;
 }
 
 /***********************************************
@@ -333,9 +331,8 @@  bool isBinAssignArrayOp(EXP op) @safe
     case EXP.powAssign:
         return true;
     default:
-        break;
+        return false;
     }
-    return false;
 }
 
 /***********************************************
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 1c8eb577261..db14f9a1cc3 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -237,8 +237,7 @@  extern (C++) class StorageClassDeclaration : AttribDeclaration
              * before the semantic analysis of 'to', so that template overloading based on the
              * 'this' pointer can be successful.
              */
-            FuncDeclaration fd = ps.isFuncDeclaration();
-            if (fd)
+            if (FuncDeclaration fd = ps.isFuncDeclaration())
             {
                 /* Use storage_class2 instead of storage_class otherwise when we do .di generation
                  * we'll wind up with 'const const' rather than 'const'.
@@ -984,7 +983,7 @@  extern (C++) final class StaticForeachDeclaration : AttribDeclaration
  *          pragma(msg, mixin("x" ~ to!string(i))); // ok, all 10 symbols are visible as they were forwarded to the global scope
  *      }
  *
- *      static assert (!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
+ *      static assert(!is(typeof(i))); // loop index variable is not visible outside of the static foreach loop
  *
  * A StaticForeachDeclaration generates one
  * ForwardingAttribDeclaration for each expansion of its body.  The
diff --git a/gcc/d/dmd/canthrow.d b/gcc/d/dmd/canthrow.d
index 31155f188dc..c96a65b8d40 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -111,11 +111,9 @@  CT canThrow(Expression e, FuncDeclaration func, ErrorSink eSink)
             if (ce.f && ce.arguments.length > 0)
             {
                 Type tb = (*ce.arguments)[0].type.toBasetype();
-                auto tbNext = tb.nextOf();
-                if (tbNext)
+                if (auto tbNext = tb.nextOf())
                 {
-                    auto ts = tbNext.baseElemOf().isTypeStruct();
-                    if (ts)
+                    if (auto ts = tbNext.baseElemOf().isTypeStruct())
                     {
                         auto sd = ts.sym;
                         const id = ce.f.ident;
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 17b33d839df..4ebe332d224 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -99,8 +99,7 @@  StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
  */
 FuncDeclaration hasIdentityOpAssign(AggregateDeclaration ad, Scope* sc)
 {
-    Dsymbol assign = search_function(ad, Id.assign);
-    if (assign)
+    if (Dsymbol assign = search_function(ad, Id.assign))
     {
         /* check identity opAssign exists
          */
@@ -825,7 +824,7 @@  FuncDeclaration buildXtoHash(StructDeclaration sd, Scope* sc)
      * Note that it would only be necessary if it has floating point fields.
      * For now, we'll just not generate a toHash() for C files.
      */
-    if (sc.flags & SCOPE.Cfile)
+    if (sc.inCfile)
         return null;
 
     //printf("StructDeclaration::buildXtoHash() %s\n", sd.toPrettyChars());
diff --git a/gcc/d/dmd/common/bitfields.d b/gcc/d/dmd/common/bitfields.d
index 01aa56d1809..926cdf87eca 100644
--- a/gcc/d/dmd/common/bitfields.d
+++ b/gcc/d/dmd/common/bitfields.d
@@ -20,43 +20,79 @@  module dmd.common.bitfields;
 extern (D) string generateBitFields(S, T)()
 if (__traits(isUnsigned, T))
 {
+    import core.bitop: bsr;
+
     string result = "extern (C++) pure nothrow @nogc @safe final {";
-    enum structName = __traits(identifier, S);
 
-    string initialValue = "";
+    struct BitInfo
+    {
+        int[] offset;
+        int[] size;
+        T initialValue;
+        int totalSize;
+    }
+
+    // Iterate over members to compute bit offset and bit size for each of them
+    enum BitInfo bitInfo = () {
+        BitInfo result;
+        int bitOffset = 0;
+        foreach (size_t i, mem; __traits(allMembers, S))
+        {
+            alias memType = typeof(__traits(getMember, S, mem));
+            enum int bitSize = bsr(memType.max | 1) + 1;
+            result.offset ~= bitOffset;
+            result.size ~= bitSize;
+            result.initialValue |= cast(T) __traits(getMember, S.init, mem) << bitOffset;
+            bitOffset += bitSize;
+        }
+        result.totalSize = bitOffset;
+        return result;
+    } ();
+
+    alias TP = typeof(T.init + 0u); // type that `T` gets promoted to, uint or ulong
+    enum string toString(TP i) = i.stringof; // compile time 'integer to string'
+
+    static assert(bitInfo.totalSize <= T.sizeof * 8,
+        "sum of bit field size "~toString!(bitInfo.totalSize)~" exceeds storage type `"~T.stringof~"`");
+
     foreach (size_t i, mem; __traits(allMembers, S))
     {
-        static assert(is(typeof(__traits(getMember, S, mem)) == bool));
-        static assert(i < T.sizeof * 8, "too many fields for bit field storage of type `"~T.stringof~"`");
-        enum mask = "(1 << "~i.stringof~")";
+        enum typeName = typeof(__traits(getMember, S, mem)).stringof;
+        enum shift = toString!(bitInfo.offset[i]);
+        enum sizeMask = toString!((1 << bitInfo.size[i]) - 1); // 0x01 for bool, 0xFF for ubyte etc.
         result ~= "
-        /// set or get the corresponding "~structName~" member
-        bool "~mem~"() const scope { return !!(bitFields & "~mask~"); }
-        /// ditto
-        bool "~mem~"(bool v)
+        "~typeName~" "~mem~"() const scope { return cast("~typeName~") ((bitFields >>> "~shift~") & "~sizeMask~"); }
+        "~typeName~" "~mem~"("~typeName~" v) scope
         {
-            v ? (bitFields |= "~mask~") : (bitFields &= ~"~mask~");
+            bitFields &= ~("~sizeMask~" << "~shift~");
+            bitFields |= v << "~shift~";
             return v;
         }";
-
-        initialValue = (__traits(getMember, S.init, mem) ? "1" : "0") ~ initialValue;
     }
-    return result ~ "}\n private "~T.stringof~" bitFields = 0b" ~ initialValue ~ ";\n";
+    enum TP initVal = bitInfo.initialValue;
+    return result ~ "\n}\n private "~T.stringof~" bitFields = " ~ toString!(initVal) ~ ";\n";
 }
 
 ///
 unittest
 {
+    enum E
+    {
+        a, b, c,
+    }
+
     static struct B
     {
         bool x;
         bool y;
+        E e = E.c;
         bool z = 1;
+        private ubyte w = 77;
     }
 
     static struct S
     {
-        mixin(generateBitFields!(B, ubyte));
+        mixin(generateBitFields!(B, ushort));
     }
 
     S s;
@@ -69,5 +105,13 @@  unittest
     s.y = true;
     assert(s.y);
     assert(!s.x);
+
+    assert(s.e == E.c);
+    s.e = E.a;
+    assert(s.e == E.a);
+
     assert(s.z);
+    assert(s.w == 77);
+    s.w = 3;
+    assert(s.w == 3);
 }
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 0609778e4c7..2991545faac 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -725,8 +725,7 @@  private final class CppMangleVisitor : Visitor
      */
     static Dsymbol getInstance(Dsymbol s)
     {
-        Dsymbol p = s.toParent();
-        if (p)
+        if (Dsymbol p = s.toParent())
         {
             if (TemplateInstance ti = p.isTemplateInstance())
                 return ti;
@@ -827,8 +826,7 @@  private final class CppMangleVisitor : Visitor
             return buf.writestring("St");
 
         auto si = getInstance(s);
-        Dsymbol p = getQualifier(si);
-        if (p)
+        if (Dsymbol p = getQualifier(si))
         {
             if (isStd(p))
             {
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index 0b3096d1f5c..09e364d7cbf 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -495,6 +495,12 @@  Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool
     return dmd.typesem.covariant(src, t, pstc, cppCovariant);
 }
 
+bool isZeroInit(Type t, const ref Loc loc)
+{
+    import dmd.typesem;
+    return dmd.typesem.isZeroInit(t, loc);
+}
+
 bool isBaseOf(Type tthis, Type t, int* poffset)
 {
     import dmd.typesem;
@@ -651,6 +657,12 @@  MATCH implicitConvTo(Type from, Type to)
     return dmd.dcast.implicitConvTo(from, to);
 }
 
+MATCH constConv(Type from, Type to)
+{
+    import dmd.typesem;
+    return dmd.typesem.constConv(from, to);
+}
+
 /***********************************************************
  * typinf.d
  */
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 29059678fc2..cda50cd078a 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -71,7 +71,7 @@  Expression implicitCastTo(Expression e, Scope* sc, Type t)
     Expression visit(Expression e)
     {
         //printf("Expression.implicitCastTo(%s of type %s) => %s\n", e.toChars(), e.type.toChars(), t.toChars());
-        if (const match = (sc && sc.flags & SCOPE.Cfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
+        if (const match = (sc && sc.inCfile) ? e.cimplicitConvTo(t) : e.implicitConvTo(t))
         {
             // no need for an extra cast when matching is exact
 
@@ -2140,8 +2140,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         {
             if (hasAliasThis)
             {
-                auto result = tryAliasThisCast();
-                if (result)
+                if (auto result = tryAliasThisCast())
                     return result;
             }
 
@@ -2235,8 +2234,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
              */
             if (hasAliasThis)
             {
-                auto result = tryAliasThisCast();
-                if (result)
+                if (auto result = tryAliasThisCast())
                     return result;
             }
             error(e.loc, "cannot cast expression `%s` of type `%s` to `%s`", e.toChars(), e.type.toChars(), t.toChars());
@@ -2306,7 +2304,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         //printf("StringExp::castTo(t = %s), '%s' committed = %d\n", t.toChars(), e.toChars(), e.committed);
 
         if (!e.committed && t.ty == Tpointer && t.nextOf().ty == Tvoid &&
-            (!sc || !(sc.flags & SCOPE.Cfile)))
+            (!sc || !sc.inCfile))
         {
             error(e.loc, "cannot convert string literal to `void*`");
             return ErrorExp.get();
@@ -2437,9 +2435,9 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         if (e.committed)
             goto Lcast;
 
-        auto X(T, U)(T tf, U tt)
+        static auto X(T, U)(T tf, U tt)
         {
-            return (cast(int)tf * 256 + cast(int)tt);
+            return cast(int)tf * 256 + cast(int)tt;
         }
 
         {
@@ -2557,7 +2555,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         // See if need to truncate or extend the literal
         if (auto tsa = tb.isTypeSArray())
         {
-            size_t dim2 = cast(size_t)tsa.dim.toInteger();
+            const dim2 = cast(size_t)tsa.dim.toInteger();
             //printf("dim from = %d, to = %d\n", cast(int)se.len, cast(int)dim2);
 
             // Changing dimensions
@@ -2637,8 +2635,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             tb.ty == Tpointer && tb.nextOf().ty == Tfunction)
         {
             auto ve = e.e1.isVarExp();
-            auto f = ve.var.isFuncDeclaration();
-            if (f)
+            if (auto f = ve.var.isFuncDeclaration())
             {
                 assert(f.isImportedSymbol());
                 f = f.overloadExactMatch(tb.nextOf());
@@ -2946,8 +2943,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         {
             if (e.func)
             {
-                auto f = e.func.overloadExactMatch(tb.nextOf());
-                if (f)
+                if (auto f = e.func.overloadExactMatch(tb.nextOf()))
                 {
                     int offset;
                     if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
@@ -3360,7 +3356,7 @@  Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
     Type t1b = e1.type.toBasetype();
     Type t2b = e2.type.toBasetype();
 
-    if (sc && sc.flags & SCOPE.Cfile)
+    if (sc && sc.inCfile)
     {
         // Integral types can be implicitly converted to pointers
         if ((t1b.ty == Tpointer) != (t2b.ty == Tpointer))
@@ -4220,7 +4216,7 @@  Expression integralPromotions(Expression e, Scope* sc)
 
 void fix16997(Scope* sc, UnaExp ue)
 {
-    if (global.params.fix16997 || sc.flags & SCOPE.Cfile)
+    if (global.params.fix16997 || sc.inCfile)
         ue.e1 = integralPromotions(ue.e1, sc);          // desired C-like behavor
     else
     {
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 2199d5d1a77..74074d7078c 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -490,8 +490,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
                 return null;
             if (cdb.ident.equals(ident))
                 return cdb;
-            auto result = cdb.searchBase(ident);
-            if (result)
+            if (auto result = cdb.searchBase(ident))
                 return result;
         }
         return null;
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index a1202ed628a..d35857b22a7 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -353,8 +353,7 @@  extern (C++) abstract class Declaration : Dsymbol
         // is an overload in the overload set that isn't
         if (isAliasedDeclaration)
         {
-            FuncDeclaration fd = isFuncDeclaration();
-            if (fd)
+            if (FuncDeclaration fd = isFuncDeclaration())
             {
                 for (FuncDeclaration ovl = fd; ovl; ovl = cast(FuncDeclaration)ovl.overnext)
                     if (!(ovl.storage_class & STC.disable))
@@ -397,7 +396,7 @@  extern (C++) abstract class Declaration : Dsymbol
         {
             for (Scope* scx = sc; scx; scx = scx.enclosing)
             {
-                if (scx.func == parent && (scx.flags & SCOPE.contract))
+                if (scx.func == parent && scx.contract != Contract.none)
                 {
                     const(char)* s = isParameter() && parent.ident != Id.ensure ? "parameter" : "result";
                     if (!(flag & ModifyFlags.noError))
@@ -412,7 +411,7 @@  extern (C++) abstract class Declaration : Dsymbol
             VarDeclaration vthis = e1.isThisExp().var;
             for (Scope* scx = sc; scx; scx = scx.enclosing)
             {
-                if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
+                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);
@@ -1137,7 +1136,6 @@  extern (C++) class VarDeclaration : Declaration
     VarDeclaration lastVar;         // Linked list of variables for goto-skips-init detection
     Expression edtor;               // if !=null, does the destruction of the variable
     IntRange* range;                // if !=null, the variable is known to be within the range
-    VarDeclarations* maybes;        // maybeScope variables that are assigned to this maybeScope variable
 
     uint endlinnum;                 // line number of end of scope that this var lives in
     uint offset;
@@ -1239,8 +1237,7 @@  extern (C++) class VarDeclaration : Declaration
              */
             for (auto s = cast(Dsymbol)this; s; s = s.parent)
             {
-                auto ad = (cast(inout)s).isMember();
-                if (ad)
+                if (auto ad = (cast(inout)s).isMember())
                     return ad;
                 if (!s.parent || !s.parent.isTemplateMixin())
                     break;
@@ -1580,7 +1577,7 @@  extern (C++) class VarDeclaration : Declaration
     extern (D) final bool checkNestedReference(Scope* sc, Loc loc)
     {
         //printf("VarDeclaration::checkNestedReference() %s\n", toChars());
-        if (sc.intypeof == 1 || (sc.flags & SCOPE.ctfe))
+        if (sc.intypeof == 1 || sc.ctfe)
             return false;
         if (!parent || parent == sc.parent)
             return false;
@@ -1615,7 +1612,7 @@  extern (C++) class VarDeclaration : Declaration
         }
 
         // Add this VarDeclaration to fdv.closureVars[] if not already there
-        if (!sc.intypeof && !(sc.flags & SCOPE.compile) &&
+        if (!sc.intypeof && !sc.traitsCompiles &&
             // https://issues.dlang.org/show_bug.cgi?id=17605
             (fdv.skipCodegen || !fdthis.skipCodegen))
         {
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 8f706fba332..4ac22b93588 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -237,7 +237,6 @@  public:
     VarDeclaration *lastVar;    // Linked list of variables for goto-skips-init detection
     Expression *edtor;          // if !=NULL, does the destruction of the variable
     IntRange *range;            // if !NULL, the variable is known to be within the range
-    VarDeclarations *maybes;    // STCmaybescope variables that are assigned to this STCmaybescope variable
 
     unsigned endlinnum;         // line number of end of scope that this var lives in
     unsigned offset;
@@ -639,12 +638,10 @@  public:
     bool nothrowInprocess(bool v);
     bool nogcInprocess() const;
     bool nogcInprocess(bool v);
-    bool returnInprocess() const;
-    bool returnInprocess(bool v);
+    bool scopeInprocess() const;
+    bool scopeInprocess(bool v);
     bool inlineScanned() const;
     bool inlineScanned(bool v);
-    bool inferScope() const;
-    bool inferScope(bool v);
     bool hasCatches() const;
     bool hasCatches(bool v);
     bool skipCodegen() const;
diff --git a/gcc/d/dmd/delegatize.d b/gcc/d/dmd/delegatize.d
index 62800d3fdb7..95064b0d16d 100644
--- a/gcc/d/dmd/delegatize.d
+++ b/gcc/d/dmd/delegatize.d
@@ -215,15 +215,13 @@  bool lambdaCheckForNestedRef(Expression e, Scope* sc)
 
         override void visit(SymOffExp e)
         {
-            VarDeclaration v = e.var.isVarDeclaration();
-            if (v)
+            if (VarDeclaration v = e.var.isVarDeclaration())
                 result = v.checkNestedReference(sc, Loc.initial);
         }
 
         override void visit(VarExp e)
         {
-            VarDeclaration v = e.var.isVarDeclaration();
-            if (v)
+            if (VarDeclaration v = e.var.isVarDeclaration())
                 result = v.checkNestedReference(sc, Loc.initial);
         }
 
@@ -235,8 +233,7 @@  bool lambdaCheckForNestedRef(Expression e, Scope* sc)
 
         override void visit(DeclarationExp e)
         {
-            VarDeclaration v = e.declaration.isVarDeclaration();
-            if (v)
+            if (VarDeclaration v = e.declaration.isVarDeclaration())
             {
                 result = v.checkNestedReference(sc, Loc.initial);
                 if (result)
diff --git a/gcc/d/dmd/deps.d b/gcc/d/dmd/deps.d
new file mode 100644
index 00000000000..efb4b0d4319
--- /dev/null
+++ b/gcc/d/dmd/deps.d
@@ -0,0 +1,141 @@ 
+/**
+ * Implement the `-deps` and `-makedeps` switches, which output dependencies of modules for build tools.
+ *
+ * The grammar of the `-deps` output is:
+ * ---
+ *      ImportDeclaration
+ *          ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
+ *      ModuleAliasIdentifier ] "\n"
+ *
+ *      BasicImportDeclaration
+ *          ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
+ *              " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
+ *
+ *      FilePath
+ *          - any string with '(', ')' and '\' escaped with the '\' character
+ * ---
+ *
+ * Make dependencies as generated by `-makedeps` look like this:
+ * ---
+ * source/app.d:
+ *   source/importa.d \
+ *   source/importb.d
+ * ---
+ *
+ * Copyright:   Copyright (C) 1999-2024 by The D Language Foundation, All Rights Reserved
+ * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/deps.d, makedeps.d)
+ * Documentation:  https://dlang.org/phobos/dmd_deps.html
+ * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/deps.d
+ */
+module dmd.deps;
+
+import core.stdc.stdio : printf;
+import core.stdc.string : strcmp;
+import dmd.common.outbuffer;
+import dmd.dimport : Import;
+import dmd.dmodule : Module;
+import dmd.globals : Param, Output;
+import dmd.hdrgen : visibilityToBuffer;
+import dmd.id : Id;
+import dmd.utils : escapePath;
+
+/**
+ * Add an import expression to module dependencies
+ * Params:
+ *   moduleDeps = output settings for `-deps`
+ *   makeDeps = output settings for `-makedeps`
+ *   fileNameZ = 0-termminated string containing the import expression's resolved filename
+ *   importString = raw string passed to import exp
+ *   imod = module import exp is in
+ */
+void addImportExpDep(ref Output moduleDeps, ref Output makeDeps, const(char)[] fileNameZ, const(char)[] importString, Module imod)
+{
+    if (moduleDeps.buffer !is null)
+    {
+        OutBuffer* ob = moduleDeps.buffer;
+
+        if (!moduleDeps.name)
+            ob.writestring("depsFile ");
+        ob.writestring(imod.toPrettyChars());
+        ob.writestring(" (");
+        escapePath(ob, imod.srcfile.toChars());
+        ob.writestring(") : ");
+        if (moduleDeps.name)
+            ob.writestring("string : ");
+        ob.write(importString);
+        ob.writestring(" (");
+        escapePath(ob, fileNameZ.ptr);
+        ob.writestring(")");
+        ob.writenl();
+    }
+    if (makeDeps.doOutput)
+    {
+        makeDeps.files.push(fileNameZ.ptr);
+    }
+}
+
+/**
+ * Add an import statement to module dependencies
+ * Params:
+ *   moduleDeps = output settings
+ *   imp = import to add
+ *   imod = module that the import is in
+ */
+void addImportDep(ref Output moduleDeps, Import imp, Module imod)
+{
+    // object self-imports itself, so skip that
+    // https://issues.dlang.org/show_bug.cgi?id=7547
+    // don't list pseudo modules __entrypoint.d, __main.d
+    // https://issues.dlang.org/show_bug.cgi?id=11117
+    // https://issues.dlang.org/show_bug.cgi?id=11164
+    if (moduleDeps.buffer is null || (imp.id == Id.object && imod.ident == Id.object) ||
+        strcmp(imod.ident.toChars(), "__main") == 0)
+        return;
+
+    OutBuffer* ob = moduleDeps.buffer;
+    if (!moduleDeps.name)
+        ob.writestring("depsImport ");
+    ob.writestring(imod.toPrettyChars());
+    ob.writestring(" (");
+    escapePath(ob, imod.srcfile.toChars());
+    ob.writestring(") : ");
+    // use visibility instead of sc.visibility because it couldn't be
+    // resolved yet, see the comment above
+    visibilityToBuffer(*ob, imp.visibility);
+    ob.writeByte(' ');
+    if (imp.isstatic)
+    {
+        ob.writestring("static ");
+    }
+    ob.writestring(": ");
+    foreach (pid; imp.packages)
+    {
+        ob.printf("%s.", pid.toChars());
+    }
+    ob.writestring(imp.id.toString());
+    ob.writestring(" (");
+    if (imp.mod)
+        escapePath(ob, imp.mod.srcfile.toChars());
+    else
+        ob.writestring("???");
+    ob.writeByte(')');
+    foreach (i, name; imp.names)
+    {
+        if (i == 0)
+            ob.writeByte(':');
+        else
+            ob.writeByte(',');
+        auto _alias = imp.aliases[i];
+        if (!_alias)
+        {
+            ob.printf("%s", name.toChars());
+            _alias = name;
+        }
+        else
+            ob.printf("%s=%s", _alias.toChars(), name.toChars());
+    }
+    if (imp.aliasId)
+        ob.printf(" -> %s", imp.aliasId.toChars());
+    ob.writenl();
+}
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 52520be01df..0f900c934e3 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -100,6 +100,10 @@  public Expression ctfeInterpret(Expression e)
 
     auto rgnpos = ctfeGlobals.region.savePos();
 
+    import dmd.timetrace;
+    timeTraceBeginEvent(TimeTraceEventType.ctfe);
+    scope (exit) timeTraceEndEvent(TimeTraceEventType.ctfe, e);
+
     Expression result = interpret(e, null);
 
     // Report an error if the expression contained a `ThrowException` and
@@ -432,6 +436,27 @@  private Expression interpretFunction(UnionExp* pue, FuncDeclaration fd, InterSta
         printf("\n********\n%s FuncDeclaration::interpret(istate = %p) %s\n", fd.loc.toChars(), istate, fd.toChars());
     }
 
+    scope dlg = () {
+        import dmd.common.outbuffer;
+        auto strbuf = OutBuffer(20);
+        strbuf.writestring(fd.toPrettyChars());
+        strbuf.write("(");
+        if (arguments)
+        {
+            foreach (i, arg; *arguments)
+            {
+                if (i > 0)
+                    strbuf.write(", ");
+                strbuf.writestring(arg.toChars());
+            }
+        }
+        strbuf.write(")");
+        return strbuf.extractSlice();
+    };
+    import dmd.timetrace;
+    timeTraceBeginEvent(TimeTraceEventType.ctfeCall);
+    scope (exit) timeTraceEndEvent(TimeTraceEventType.ctfeCall, fd, dlg);
+
     void fdError(const(char)* msg)
     {
         error(fd.loc, "%s `%s` %s", fd.kind, fd.toPrettyChars, msg);
diff --git a/gcc/d/dmd/dmacro.d b/gcc/d/dmd/dmacro.d
index c04fbec731d..9d702502ad1 100644
--- a/gcc/d/dmd/dmacro.d
+++ b/gcc/d/dmd/dmacro.d
@@ -16,8 +16,6 @@  import core.stdc.string;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
 
-@trusted:
-
 struct MacroTable
 {
     /**********************************
@@ -303,7 +301,7 @@  struct Macro
  *      copy allocated with mem.xmalloc()
  */
 
-char[] memdup(const(char)[] p) nothrow pure
+char[] memdup(const(char)[] p) nothrow pure @trusted
 {
     size_t len = p.length;
     return (cast(char*)memcpy(mem.xmalloc(len), p.ptr, len))[0 .. len];
@@ -318,7 +316,7 @@  char[] memdup(const(char)[] p) nothrow pure
  *              1..9:   get nth argument
  *              -1:     get 2nd through end
  */
-size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothrow pure
+size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothrow pure @safe
 {
     /* Scan forward for matching right parenthesis.
      * Nest parentheses.
@@ -334,7 +332,7 @@  size_t extractArgN(const(char)[] buf, out const(char)[] marg, int n) @nogc nothr
     uint inexp = 0;
     uint argn = 0;
     size_t v = 0;
-    const p = buf.ptr;
+    const p = buf;
     const end = buf.length;
 Largstart:
     // Skip first space, if any, to find the start of the macro argument
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 005f1c9d0e2..583b4679f0b 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -715,6 +715,11 @@  extern (C++) final class Module : Package
     {
         const(char)* srcname = srcfile.toChars();
         //printf("Module::parse(srcname = '%s')\n", srcname);
+
+        import dmd.timetrace;
+        timeTraceBeginEvent(TimeTraceEventType.parse);
+        scope (exit) timeTraceEndEvent(TimeTraceEventType.parse, this);
+
         isPackageFile = isPackageFileName(srcfile);
         const(char)[] buf = processSource(src, this);
         // an error happened on UTF conversion
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 47195295547..7936086bdd0 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -45,37 +45,45 @@  import dmd.tokens;
 
 //version=LOGSEARCH;
 
-
-// List of flags that can be applied to this `Scope`
-enum SCOPE
+/// What kind of contract function we're in, if any
+enum Contract : ubyte
 {
-    ctor          = 0x0001,   /// constructor type
-    noaccesscheck = 0x0002,   /// don't do access checks
-    condition     = 0x0004,   /// inside static if/assert condition
-    debug_        = 0x0008,   /// inside debug conditional
-    constraint    = 0x0010,   /// inside template constraint
-    invariant_    = 0x0020,   /// inside invariant code
-    require       = 0x0040,   /// inside in contract code
-    ensure        = 0x0060,   /// inside out contract code
-    contract      = 0x0060,   /// [mask] we're inside contract code
-    ctfe          = 0x0080,   /// inside a ctfe-only expression
-    compile       = 0x0100,   /// inside __traits(compile)
-    ignoresymbolvisibility    = 0x0200,   /// ignore symbol visibility
-                                          /// https://issues.dlang.org/show_bug.cgi?id=15907
-    Cfile         = 0x0800,   /// C semantics apply
-    free          = 0x8000,   /// is on free list
-
-    fullinst      = 0x10000,  /// fully instantiate templates
-    ctfeBlock     = 0x20000,  /// inside a `if (__ctfe)` block
-    dip1000       = 0x40000,  /// dip1000 errors enabled for this scope
-    dip25         = 0x80000,  /// dip25 errors enabled for this scope
+    none = 0,
+    invariant_ = 1,
+    require = 2, // in contract
+    ensure = 3, // out contract
 }
 
-/// Flags that are carried along with a scope push()
-private enum PersistentFlags =
-    SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
-    SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
-    SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25;
+private extern (D) struct BitFields
+{
+    bool ctor;              /// constructor type
+    bool noAccessCheck;     /// don't do access checks
+    bool condition;         /// inside static if/assert condition
+    bool debug_;            /// inside debug conditional
+    bool inTemplateConstraint; /// inside template constraint
+    Contract contract;
+    bool ctfe;              /// inside a ctfe-only expression
+    bool traitsCompiles;    /// inside __traits(compile)
+
+    /// ignore symbol visibility
+    /// https://issues.dlang.org/show_bug.cgi?id=15907
+    bool ignoresymbolvisibility;
+
+    bool _padding0; // To keep the layout the same as when the old `SCOPE` enum bitflags were used
+
+    bool inCfile;            /// C semantics apply
+
+    bool _padding1;
+    bool _padding2;
+    bool _padding3;
+
+    bool canFree;            /// is on free list
+
+    bool fullinst;          /// fully instantiate templates
+    bool ctfeBlock;         /// inside a `if (__ctfe)` block
+    bool dip1000;           /// dip1000 errors enabled for this scope
+    bool dip25;             /// dip25 errors enabled for this scope
+}
 
 extern (C++) struct Scope
 {
@@ -136,7 +144,8 @@  extern (C++) struct Scope
 
     DeprecatedDeclaration depdecl;  /// customized deprecation message
 
-    uint flags;
+    import dmd.common.bitfields : generateBitFields;
+    mixin(generateBitFields!(BitFields, uint));
 
     // user defined attributes
     UserAttributeDeclaration userAttribDecl;
@@ -157,8 +166,8 @@  extern (C++) struct Scope
             Scope* s = freelist;
             freelist = s.enclosing;
             //printf("freelist %p\n", s);
-            assert(s.flags & SCOPE.free);
-            s.flags &= ~SCOPE.free;
+            assert(s.canFree);
+            s.canFree = false;
             return s;
         }
         return new Scope();
@@ -181,11 +190,11 @@  extern (C++) struct Scope
         m.addMember(null, sc.scopesym);
         m.parent = null; // got changed by addMember()
         if (global.params.useDIP1000 == FeatureState.enabled)
-            sc.flags |= SCOPE.dip1000;
+            sc.dip1000 = true;
         if (global.params.useDIP25 == FeatureState.enabled)
-            sc.flags |= SCOPE.dip25;
+            sc.dip25 = true;
         if (_module.filetype == FileType.c)
-            sc.flags |= SCOPE.Cfile;
+            sc.inCfile = true;
         // Create the module scope underneath the global scope
         sc = sc.push(_module);
         sc.parent = _module;
@@ -207,13 +216,13 @@  extern (C++) struct Scope
     {
         Scope* s = copy();
         //printf("Scope::push(this = %p) new = %p\n", this, s);
-        assert(!(flags & SCOPE.free));
+        assert(!this.canFree);
         s.scopesym = null;
         s.enclosing = &this;
         debug
         {
             if (enclosing)
-                assert(!(enclosing.flags & SCOPE.free));
+                assert(!enclosing.canFree);
             if (s == enclosing)
             {
                 printf("this = %p, enclosing = %p, enclosing.enclosing = %p\n", s, &this, enclosing);
@@ -223,12 +232,38 @@  extern (C++) struct Scope
         s.slabel = null;
         s.nofree = false;
         s.ctorflow.fieldinit = ctorflow.fieldinit.arraydup;
-        s.flags = (flags & PersistentFlags);
+
+        // Only keep persistent flags
+        s.resetAllFlags();
+        s.contract = this.contract;
+        s.debug_ = this.debug_;
+        s.ctfe = this.ctfe;
+        s.traitsCompiles = this.traitsCompiles;
+        s.inTemplateConstraint = this.inTemplateConstraint;
+        s.noAccessCheck = this.noAccessCheck;
+        s.ignoresymbolvisibility = this.ignoresymbolvisibility;
+        s.inCfile = this.inCfile;
+        s.ctfeBlock = this.ctfeBlock;
+        s.dip1000 = this.dip1000;
+        s.dip25 = this.dip25;
+
         s.lastdc = null;
         assert(&this != s);
         return s;
     }
 
+    /// Copy flags from scope `other`
+    extern(D) void copyFlagsFrom(Scope* other)
+    {
+        this.bitFields = other.bitFields;
+    }
+
+    /// Set all scope flags to their initial value
+    extern(D) void resetAllFlags()
+    {
+        this.bitFields = 0;
+    }
+
     extern (D) Scope* push(ScopeDsymbol ss)
     {
         //printf("Scope::push(%s)\n", ss.toChars());
@@ -251,7 +286,7 @@  extern (C++) struct Scope
                 this = this.init;
             enclosing = freelist;
             freelist = &this;
-            flags |= SCOPE.free;
+            this.canFree = true;
         }
         return enc;
     }
@@ -270,7 +305,8 @@  extern (C++) struct Scope
     extern (D) Scope* startCTFE()
     {
         Scope* sc = this.push();
-        sc.flags = this.flags | SCOPE.ctfe;
+        sc.copyFlagsFrom(&this);
+        sc.ctfe = true;
         version (none)
         {
             /* TODO: Currently this is not possible, because we need to
@@ -300,7 +336,7 @@  extern (C++) struct Scope
 
     extern (D) Scope* endCTFE()
     {
-        assert(flags & SCOPE.ctfe);
+        assert(this.ctfe);
         return pop();
     }
 
@@ -470,7 +506,7 @@  extern (C++) struct Scope
 
                 if (sc.scopesym.isModule())
                     flags |= SearchOpt.unqualifiedModule;    // tell Module.search() that SearchOpt.localsOnly is to be obeyed
-                else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
+                else if (sc.inCfile && sc.scopesym.isStructDeclaration())
                     continue;                                // C doesn't have struct scope
 
                 if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
@@ -495,8 +531,7 @@  extern (C++) struct Scope
                 if (global.params.fixAliasThis)
                 {
                     Expression exp = new ThisExp(loc);
-                    Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp);
-                    if (aliasSym)
+                    if (Dsymbol aliasSym = checkAliasThis(sc.scopesym.isAggregateDeclaration(), ident, flags, &exp))
                     {
                         //printf("found aliassym: %s\n", aliasSym.toChars());
                         pscopesym = new ExpressionDsymbol(exp);
@@ -511,7 +546,7 @@  extern (C++) struct Scope
             return null;
         }
 
-        if (this.flags & SCOPE.ignoresymbolvisibility)
+        if (this.ignoresymbolvisibility)
             flags |= SearchOpt.ignoreVisibility;
 
         // First look in local scopes
@@ -658,7 +693,7 @@  extern (C++) struct Scope
         //printf("\t\tscopesym = %p\n", scopesym);
         if (!scopesym.symtab)
             scopesym.symtab = new DsymbolTable();
-        if (!(flags & SCOPE.Cfile))
+        if (!this.inCfile)
             return scopesym.symtabInsert(s);
 
         // ImportC insert
@@ -753,7 +788,7 @@  extern (C++) struct Scope
         {
             //printf("\tsc = %p\n", sc);
             sc.nofree = true;
-            assert(!(flags & SCOPE.free));
+            assert(!this.canFree);
             //assert(sc != sc.enclosing);
             //assert(!sc.enclosing || sc != sc.enclosing.enclosing);
             //if (++i == 10)
@@ -814,7 +849,7 @@  extern (C++) struct Scope
      */
     extern (D) bool isFromSpeculativeSemanticContext() scope
     {
-        return this.intypeof || this.flags & SCOPE.compile;
+        return this.intypeof || this.traitsCompiles;
     }
 
 
@@ -824,19 +859,19 @@  extern (C++) struct Scope
      */
     extern (D) bool needsCodegen()
     {
-        return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0;
+        return !this.ctfe && !this.ctfeBlock && !this.traitsCompiles;
     }
 
     /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
     extern (D) FeatureState useDIP1000()
     {
-        return (flags & SCOPE.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+        return (this.dip1000 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
     }
 
     /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
     extern (D) FeatureState useDIP25()
     {
-        return (flags & SCOPE.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
+        return (this.dip25 || hasEdition(Edition.v2024)) ? FeatureState.enabled : FeatureState.disabled;
     }
 
     /// Returns: whether this scope compiles with `edition` or later
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 90b2d9fda6b..f5ec1ce1251 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -265,10 +265,9 @@  extern (C++) class Dsymbol : ASTNode
     Identifier ident;
     Dsymbol parent;
     Symbol* csym;           // symbol for code generator
-    const Loc loc;          // where defined
     Scope* _scope;          // !=null means context to use for semantic()
-    const(char)* prettystring;  // cached value of toPrettyChars()
     private DsymbolAttributes* atts; /// attached attribute declarations
+    const Loc loc;          // where defined
     bool errors;            // this symbol failed to pass semantic()
     PASS semanticRun = PASS.initial;
     ushort localNum;        /// perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
@@ -396,8 +395,7 @@  extern (C++) class Dsymbol : ASTNode
         while (s)
         {
             //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
-            Module m = s.isModule();
-            if (m)
+            if (Module m = s.isModule())
                 return m;
             s = s.parent;
         }
@@ -428,8 +426,7 @@  extern (C++) class Dsymbol : ASTNode
         while (s)
         {
             //printf("\ts = %s '%s'\n", s.kind(), s.toPrettyChars());
-            Module m = s.isModule();
-            if (m)
+            if (Module m = s.isModule())
                 return m;
             TemplateInstance ti = s.isTemplateInstance();
             if (ti && ti.enclosing)
@@ -657,15 +654,10 @@  extern (C++) class Dsymbol : ASTNode
 
     const(char)* toPrettyChars(bool QualifyTypes = false)
     {
-        if (prettystring && !QualifyTypes)
-            return prettystring; // value cached for speed
-
         //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
         if (!parent)
         {
             auto s = toChars();
-            if (!QualifyTypes)
-                prettystring = s;
             return s;
         }
 
@@ -685,8 +677,6 @@  extern (C++) class Dsymbol : ASTNode
         addQualifiers(this);
         auto s = buf.extractSlice(true).ptr;
 
-        if (!QualifyTypes)
-            prettystring = s;
         return s;
     }
 
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index ce29073e2ea..2c5f0e579b3 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -192,12 +192,11 @@  public:
     Identifier *ident;
     Dsymbol *parent;
     Symbol *csym;               // symbol for code generator
-    Loc loc;                    // where defined
     Scope *_scope;               // !=NULL means context to use for semantic()
-    const utf8_t *prettystring;
 private:
     DsymbolAttributes* atts;
 public:
+    Loc loc;                    // where defined
     d_bool errors;                // this symbol failed to pass semantic()
     PASS semanticRun;
     unsigned short localNum;        // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index e32f5fa221c..711ab122609 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -24,10 +24,12 @@  import dmd.attrib;
 import dmd.attribsem;
 import dmd.clone;
 import dmd.cond;
+import dmd.timetrace;
 import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.denum;
+import dmd.deps;
 import dmd.dimport;
 import dmd.dinterpret;
 import dmd.dmodule;
@@ -59,6 +61,7 @@  import dmd.objc;
 import dmd.opover;
 import dmd.optimize;
 import dmd.parse;
+debug import dmd.printast;
 import dmd.root.array;
 import dmd.root.filename;
 import dmd.common.outbuffer;
@@ -127,7 +130,7 @@  AlignDeclaration getAlignment(AlignDeclaration ad, Scope* sc)
         else
         {
             auto n = e.toInteger();
-            if (sc.flags & SCOPE.Cfile && n == 0)       // C11 6.7.5-6 allows 0 for alignment
+            if (sc.inCfile && n == 0)       // C11 6.7.5-6 allows 0 for alignment
                 continue;
 
             if (n < 1 || n & (n - 1) || ushort.max < n || !e.type.isintegral())
@@ -179,7 +182,7 @@  bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
         return false;
     // Don't complain if we're inside a template constraint
     // https://issues.dlang.org/show_bug.cgi?id=21831
-    if (sc.flags & SCOPE.constraint)
+    if (sc.inTemplateConstraint)
         return false;
 
     const(char)* message = null;
@@ -596,7 +599,17 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
 
         if (dsym.storage_class & STC.extern_ && dsym._init)
-            .error(dsym.loc, "%s `%s` extern symbols cannot have initializers", dsym.kind, dsym.toPrettyChars);
+        {
+            if (sc.inCfile)
+            {
+                // https://issues.dlang.org/show_bug.cgi?id=24447
+                // extern int x = 3; is allowed in C
+                dsym.storage_class &= ~STC.extern_;
+            }
+            else
+                .error(dsym.loc, "%s `%s` extern symbols cannot have initializers", dsym.kind, dsym.toPrettyChars);
+
+        }
 
         AggregateDeclaration ad = dsym.isThis();
         if (ad)
@@ -614,12 +627,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             bool needctfe = (dsym.storage_class & (STC.manifest | STC.static_)) != 0 || !sc.func;
             if (needctfe)
             {
-                sc.flags |= SCOPE.condition;
+                sc.condition = true;
                 sc = sc.startCTFE();
             }
             //printf("inferring type for %s with init %s\n", dsym.toChars(), dsym._init.toChars());
             dsym._init = dsym._init.inferType(sc);
-            dsym.type = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0).type;
+            dsym.type = dsym._init.initializerToExpression(null, sc.inCfile).type;
             if (needctfe)
                 sc = sc.endCTFE();
 
@@ -728,7 +741,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
              * and add those.
              */
             size_t nelems = Parameter.dim(tt.arguments);
-            Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0) : null;
+            Expression ie = (dsym._init && !dsym._init.isVoidInitializer()) ? dsym._init.initializerToExpression(null, sc.inCfile) : null;
             if (ie)
                 ie = ie.expressionSemantic(sc);
             if (nelems > 0 && ie)
@@ -1001,9 +1014,9 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
-        if ((dsym.storage_class & (STC.ref_ | STC.parameter | STC.foreach_ | STC.temp | STC.result)) == STC.ref_ && dsym.ident != Id.This)
+        if ((dsym.storage_class & (STC.ref_ | STC.field)) == (STC.ref_ | STC.field) && dsym.ident != Id.This)
         {
-            .error(dsym.loc, "%s `%s` - only parameters, functions and `foreach` declarations can be `ref`", dsym.kind, dsym.toPrettyChars);
+            .error(dsym.loc, "%s `%s` - field declarations cannot be `ref`", dsym.kind, dsym.toPrettyChars);
         }
 
         if (dsym.type.hasWild())
@@ -1052,8 +1065,15 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
         }
 
+        bool dsymIsRef = (dsym.storage_class & (STC.ref_ | STC.field | STC.parameter | STC.temp | STC.foreach_)) == STC.ref_;
+        if (dsymIsRef)
+        {
+            if (!dsym._init && dsym.ident != Id.This)
+                .error(dsym.loc, "%s `%s` - initializer is required for `ref` variable", dsym.kind, dsym.toPrettyChars);
+        }
+
         FuncDeclaration fd = parent.isFuncDeclaration();
-        if (dsym.type.isscope() && !(dsym.storage_class & STC.nodtor))
+        if (dsym.type.isScopeClass() && !(dsym.storage_class & STC.nodtor))
         {
             if (dsym.storage_class & (STC.field | STC.out_ | STC.ref_ | STC.static_ | STC.manifest | STC.gshared) || !fd)
             {
@@ -1122,7 +1142,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         bool isBlit = false;
         uinteger_t sz;
-        if (sc.flags & SCOPE.Cfile && !dsym._init)
+        if (sc.inCfile && !dsym._init)
         {
             addDefaultCInitializer(dsym);
         }
@@ -1187,7 +1207,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             sc = sc.push();
             sc.stc &= ~(STC.TYPECTOR | STC.pure_ | STC.nothrow_ | STC.nogc | STC.ref_ | STC.disable);
 
-            if (sc.flags & SCOPE.Cfile &&
+            if (sc.inCfile &&
                 dsym.type.isTypeSArray() &&
                 dsym.type.isTypeSArray().isIncomplete() &&
                 dsym._init.isVoidInitializer() &&
@@ -1217,12 +1237,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         if (ai && tb.ty == Taarray)
                             e = ai.toAssocArrayLiteral();
                         else
-                            e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+                            e = dsym._init.initializerToExpression(null, sc.inCfile);
                         if (!e)
                         {
                             // Run semantic, but don't need to interpret
                             dsym._init = dsym._init.initializerSemantic(sc, dsym.type, INITnointerpret);
-                            e = dsym._init.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+                            e = dsym._init.initializerToExpression(null, sc.inCfile);
                             if (!e)
                             {
                                 .error(dsym.loc, "%s `%s` is not a static and cannot have static initializer", dsym.kind, dsym.toPrettyChars);
@@ -1232,7 +1252,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         ei = new ExpInitializer(dsym._init.loc, e);
                         dsym._init = ei;
                     }
-                    else if (sc.flags & SCOPE.Cfile && dsym.type.isTypeSArray() &&
+                    else if (sc.inCfile && dsym.type.isTypeSArray() &&
                              dsym.type.isTypeSArray().isIncomplete())
                     {
                         // C11 6.7.9-22 determine the size of the incomplete array,
@@ -1283,21 +1303,48 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
                     Expression exp = ei.exp;
                     Expression e1 = new VarExp(dsym.loc, dsym);
-                    if (isBlit)
-                        exp = new BlitExp(dsym.loc, e1, exp);
+                    if (dsymIsRef) // follow logic similar to typesem.argumentMatchParameter() and statementsem.visitForeach()
+                    {
+                        dsym.storage_class |= STC.nodtor;
+                        exp = exp.expressionSemantic(sc);
+                        Type tp = dsym.type;
+                        Type ta = exp.type;
+                        if (!exp.isLvalue())
+                        {
+                            .error(dsym.loc, "rvalue `%s` cannot be assigned to `ref %s`", exp.toChars(), dsym.toChars());
+                            exp = ErrorExp.get();
+                        }
+                        else if (!ta.constConv(tp))
+                        {
+                            .error(dsym.loc, "type `%s` cannot be assigned to `ref %s %s`", ta.toChars(), tp.toChars(), dsym.toChars());
+                            exp = ErrorExp.get();
+                        }
+                        else
+                        {
+                            exp = new ConstructExp(dsym.loc, e1, exp);
+                            dsym.canassign++;
+                            exp = exp.expressionSemantic(sc);
+                            dsym.canassign--;
+                        }
+                    }
                     else
-                        exp = new ConstructExp(dsym.loc, e1, exp);
-                    dsym.canassign++;
-                    exp = exp.expressionSemantic(sc);
-                    dsym.canassign--;
-                    exp = exp.optimize(WANTvalue);
+                    {
+                        if (isBlit)
+                            exp = new BlitExp(dsym.loc, e1, exp);
+                        else
+                            exp = new ConstructExp(dsym.loc, e1, exp);
+                        dsym.canassign++;
+                        exp = exp.expressionSemantic(sc);
+                        dsym.canassign--;
+                    }
+
                     if (exp.op == EXP.error)
                     {
                         dsym._init = new ErrorInitializer();
                         ei = null;
                     }
                     else
-                        ei.exp = exp;
+                        ei.exp = exp.optimize(WANTvalue);
                 }
                 else
                 {
@@ -1321,7 +1368,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             }
             else if (dsym.storage_class & (STC.const_ | STC.immutable_ | STC.manifest) ||
                      dsym.type.isConst() || dsym.type.isImmutable() ||
-                     sc.flags & SCOPE.Cfile)
+                     sc.inCfile)
             {
                 /* Because we may need the results of a const declaration in a
                  * subsequent type, such as an array dimension, before semantic2()
@@ -1466,7 +1513,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if (dsym.errors)
             return;
 
-        if (!(global.params.bitfields || sc.flags & SCOPE.Cfile))
+        if (!(global.params.bitfields || sc.inCfile))
         {
             version (IN_GCC)
                 .error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars);
@@ -1514,6 +1561,8 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
     override void visit(Import imp)
     {
+        timeTraceBeginEvent(TimeTraceEventType.sema1Import);
+        scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Import, imp);
         static if (LOG)
         {
             printf("Import::semantic('%s') %s\n", imp.toPrettyChars(), imp.id.toChars());
@@ -1635,75 +1684,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
 
         imp.semanticRun = PASS.semanticdone;
-
-        // object self-imports itself, so skip that
-        // https://issues.dlang.org/show_bug.cgi?id=7547
-        // don't list pseudo modules __entrypoint.d, __main.d
-        // https://issues.dlang.org/show_bug.cgi?id=11117
-        // https://issues.dlang.org/show_bug.cgi?id=11164
-        if (global.params.moduleDeps.buffer is null || (imp.id == Id.object && sc._module.ident == Id.object) ||
-            strcmp(sc._module.ident.toChars(), "__main") == 0)
-            return;
-
-        /* The grammar of the file is:
-         *      ImportDeclaration
-         *          ::= BasicImportDeclaration [ " : " ImportBindList ] [ " -> "
-         *      ModuleAliasIdentifier ] "\n"
-         *
-         *      BasicImportDeclaration
-         *          ::= ModuleFullyQualifiedName " (" FilePath ") : " Protection|"string"
-         *              " [ " static" ] : " ModuleFullyQualifiedName " (" FilePath ")"
-         *
-         *      FilePath
-         *          - any string with '(', ')' and '\' escaped with the '\' character
-         */
-        OutBuffer* ob = global.params.moduleDeps.buffer;
-        Module imod = sc._module;
-        if (!global.params.moduleDeps.name)
-            ob.writestring("depsImport ");
-        ob.writestring(imod.toPrettyChars());
-        ob.writestring(" (");
-        escapePath(ob, imod.srcfile.toChars());
-        ob.writestring(") : ");
-        // use visibility instead of sc.visibility because it couldn't be
-        // resolved yet, see the comment above
-        visibilityToBuffer(*ob, imp.visibility);
-        ob.writeByte(' ');
-        if (imp.isstatic)
-        {
-            stcToBuffer(*ob, STC.static_);
-            ob.writeByte(' ');
-        }
-        ob.writestring(": ");
-        foreach (pid; imp.packages)
-        {
-            ob.printf("%s.", pid.toChars());
-        }
-        ob.writestring(imp.id.toString());
-        ob.writestring(" (");
-        if (imp.mod)
-            escapePath(ob, imp.mod.srcfile.toChars());
-        else
-            ob.writestring("???");
-        ob.writeByte(')');
-        foreach (i, name; imp.names)
-        {
-            if (i == 0)
-                ob.writeByte(':');
-            else
-                ob.writeByte(',');
-            Identifier _alias = imp.aliases[i];
-            if (!_alias)
-            {
-                ob.printf("%s", name.toChars());
-                _alias = name;
-            }
-            else
-                ob.printf("%s=%s", _alias.toChars(), name.toChars());
-        }
-        if (imp.aliasId)
-            ob.printf(" -> %s", imp.aliasId.toChars());
-        ob.writenl();
+        addImportDep(global.params.moduleDeps, imp, sc._module);
     }
 
     void attribSemantic(AttribDeclaration ad)
@@ -1754,7 +1735,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         sc = sc.push();
         sc.stc &= ~(STC.auto_ | STC.scope_ | STC.static_ | STC.gshared);
         sc.inunion = scd.isunion ? scd : null;
-        sc.flags = 0;
+        sc.resetAllFlags();
         for (size_t i = 0; i < scd.decl.length; i++)
         {
             Dsymbol s = (*scd.decl)[i];
@@ -1911,6 +1892,25 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
     {
         if (sa.semanticRun < PASS.semanticdone)
             sa.semanticRun = PASS.semanticdone;
+        else
+            return;
+
+        // https://issues.dlang.org/show_bug.cgi?id=24645
+        // This is a short-circuit. Usually, static assert conditions are evaluated
+        // in semantic2, but it's not uncommon to use this pattern:
+        // ---
+        // version(X)
+        // {}
+        // else
+        //   static assert(false, "unsupported platform");
+        // ---
+        // However, without this short-circuit, the static assert error may get drowned
+        // out by subsequent semantic1 (import) errors. Only short-circuit at module scope though,
+        // inside mixin templates you want an instantiation trace (which you don't get here).
+        if (sc.parent && sc.parent.isModule())
+            if (auto i = sa.exp.isIntegerExp())
+                if (i.toInteger() == 0)
+                    staticAssertFail(sa, sc);
     }
 
     override void visit(DebugSymbol ds)
@@ -1936,6 +1936,10 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
     {
         if (m.semanticRun != PASS.initial)
             return;
+
+        timeTraceBeginEvent(TimeTraceEventType.sema1Module);
+        scope (exit) timeTraceEndEvent(TimeTraceEventType.sema1Module, m);
+
         //printf("+Module::semantic(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
         m.semanticRun = PASS.semantic;
         // Note that modules get their own scope, from scratch.
@@ -2782,7 +2786,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         sc = sc.push();
         sc.stc &= ~STC.static_; // not a static invariant
         sc.stc |= STC.const_; // invariant() is always const
-        sc.flags = (sc.flags & ~SCOPE.contract) | SCOPE.invariant_;
+        sc.contract = Contract.invariant_;
         sc.linkage = LINK.d;
 
         funcDeclarationSemantic(sc, invd);
@@ -3001,7 +3005,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         buildOpAssign(sd, sc2);
         buildOpEquals(sd, sc2);
 
-        if (!(sc2.flags & SCOPE.Cfile) &&
+        if (!sc2.inCfile &&
             global.params.useTypeInfo && Type.dtypeinfo)  // these functions are used for TypeInfo
         {
             sd.xeq = buildXopEquals(sd, sc2);
@@ -4137,7 +4141,7 @@  private extern(C++) class AddMemberVisitor : Visitor
             }
 
             // If using C tag/prototype/forward declaration rules
-            if (sc.flags & SCOPE.Cfile && !dsym.isImport())
+            if (sc.inCfile && !dsym.isImport())
             {
                 if (handleTagSymbols(*sc, dsym, s2, sds))
                     return;
@@ -4158,7 +4162,7 @@  private extern(C++) class AddMemberVisitor : Visitor
         if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
         {
             if (dsym.ident == Id.__sizeof ||
-                !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
+                !(sc && sc.inCfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
             {
                 .error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars());
                 dsym.errors = true;
@@ -4434,7 +4438,7 @@  private extern(C++) class AddMemberVisitor : Visitor
  */
 void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
 {
-    const bool isCEnum = (sc.flags & SCOPE.Cfile) != 0; // it's an ImportC enum
+    const bool isCEnum = sc.inCfile; // it's an ImportC enum
     //printf("addEnumMembersToSymtab(ed: %s added: %d Cfile: %d)\n", ed.toChars(), ed.added, isCEnum);
     if (ed.added)
         return;
@@ -4465,6 +4469,8 @@  void addEnumMembersToSymtab(EnumDeclaration ed, Scope* sc, ScopeDsymbol sds)
                  * the enum members to both symbol tables.
                  */
                 em.addMember(sc, ed);   // add em to ed's symbol table
+                if (em.errors)
+                    return;
                 em.addMember(sc, sds);  // add em to symbol table that ed is in
                 em.parent = ed; // restore it after previous addMember() changed it
             }
@@ -4970,7 +4976,7 @@  void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
     if (global.errors != errorsave)
         goto Laftersemantic;
 
-    if ((sc.func || (sc.flags & SCOPE.fullinst)) && !tempinst.tinst)
+    if ((sc.func || sc.fullinst) && !tempinst.tinst)
     {
         /* If a template is instantiated inside function, the whole instantiation
          * should be done at that position. But, immediate running semantic3 of
@@ -7267,9 +7273,11 @@  private extern(C++) class SetFieldOffsetVisitor : Visitor
         }
         else if (style == TargetC.BitFieldStyle.Gcc_Clang)
         {
-            // If the bit-field spans more units of alignment than its type,
-            // start a new field at the next alignment boundary.
-            if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
+            // If the bit-field spans more units of alignment than its type
+            // and is at the alignment boundary, start a new field at the
+            // next alignment boundary. This affects when offsetof reports
+            // a higher number and bitoffsetof starts at zero again.
+            if (fieldState.bitOffset % (memalignsize * 8) == 0 &&
                 fieldState.bitOffset + bfd.fieldWidth > memsize * 8)
             {
                 if (log) printf("more units of alignment than its type\n");
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 8fcbbad2f76..6883180107a 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -423,8 +423,7 @@  private size_t arrayObjectHash(ref Objects oa1)
             hash = mixHash(hash, expressionHash(e1));
         else if (auto s1 = isDsymbol(o1))
         {
-            auto fa1 = s1.isFuncAliasDeclaration();
-            if (fa1)
+            if (auto fa1 = s1.isFuncAliasDeclaration())
                 s1 = fa1.toAliasFunc();
             hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
         }
@@ -1012,6 +1011,11 @@  size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
     return IDX_NOTFOUND;
 }
 
+private auto X(T, U)(T m, U n)
+{
+    return (m << 4) | n;
+}
+
 ubyte deduceWildHelper(Type t, Type* at, Type tparam)
 {
     if ((tparam.mod & MODFlags.wild) == 0)
@@ -1019,11 +1023,6 @@  ubyte deduceWildHelper(Type t, Type* at, Type tparam)
 
     *at = null;
 
-    auto X(T, U)(T U, U T)
-    {
-        return (U << 4) | T;
-    }
-
     switch (X(tparam.mod, t.mod))
     {
     case X(MODFlags.wild, 0):
@@ -1098,12 +1097,6 @@  private Type rawTypeMerge(Type t1, Type t2)
 MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
 {
     // 9*9 == 81 cases
-
-    auto X(T, U)(T U, U T)
-    {
-        return (U << 4) | T;
-    }
-
     switch (X(tparam.mod, t.mod))
     {
     case X(0, 0):
@@ -2557,8 +2550,7 @@  MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters pa
  */
 private void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, ref Objects best, ref int numBaseClassMatches)
 {
-    TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
-    if (parti)
+    if (TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null)
     {
         // Make a temporary copy of dedtypes so we don't destroy it
         auto tmpdedtypes = new Objects(dedtypes.length);
diff --git a/gcc/d/dmd/enumsem.d b/gcc/d/dmd/enumsem.d
index c67ac618ec3..e1eadc531f1 100644
--- a/gcc/d/dmd/enumsem.d
+++ b/gcc/d/dmd/enumsem.d
@@ -192,7 +192,7 @@  void enumSemantic(Scope* sc, EnumDeclaration ed)
         return;
     }
 
-    if (!(sc.flags & SCOPE.Cfile))  // C enum remains incomplete until members are done
+    if (!sc.inCfile)  // C enum remains incomplete until members are done
         ed.semanticRun = PASS.semanticdone;
 
     version (none)
@@ -219,8 +219,7 @@  void enumSemantic(Scope* sc, EnumDeclaration ed)
      */
     ed.members.foreachDsymbol( (s)
     {
-        EnumMember em = s.isEnumMember();
-        if (em)
+        if (EnumMember em = s.isEnumMember())
             em._scope = sce;
     });
 
@@ -230,7 +229,7 @@  void enumSemantic(Scope* sc, EnumDeclaration ed)
      */
     addEnumMembersToSymtab(ed, sc, sc.getScopesym());
 
-    if (sc.flags & SCOPE.Cfile)
+    if (sc.inCfile)
     {
         /* C11 6.7.2.2
          */
@@ -386,8 +385,7 @@  Expression getDefaultValue(EnumDeclaration ed, const ref Loc loc)
 
     foreach (const i; 0 .. ed.members.length)
     {
-        EnumMember em = (*ed.members)[i].isEnumMember();
-        if (em)
+        if (EnumMember em = (*ed.members)[i].isEnumMember())
         {
             if (em.semanticRun < PASS.semanticdone)
             {
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 08bd6fd2fdd..fd2bd00ee48 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -378,32 +378,24 @@  bool checkParamArgumentEscape(ref Scope sc, FuncDeclaration fdc, Identifier parI
     void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue %s\n", v.toChars());
-        if (parStc & STC.scope_ || v.isDataseg())
+        if (parStc & STC.scope_)
             return;
 
-        Dsymbol p = v.toParent2();
-
-        notMaybeScope(v, vPar);
+        doNotInferScope(v, vPar);
 
         if (v.isScope())
         {
             unsafeAssign!"scope variable"(v);
         }
-        else if (v.isTypesafeVariadicArray && p == sc.func)
-        {
-            unsafeAssign!"variadic variable"(v);
-        }
     }
 
     void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log) printf("byref %s\n", v.toChars());
-        if (v.isDataseg())
-            return;
 
         Dsymbol p = v.toParent2();
 
-        notMaybeScope(v, arg);
+        doNotInferScope(v, arg);
         if (checkScopeVarAddr(v, arg, sc, gag))
         {
             result = true;
@@ -432,7 +424,7 @@  bool checkParamArgumentEscape(ref Scope sc, FuncDeclaration fdc, Identifier parI
 
             Dsymbol p = v.toParent2();
 
-            notMaybeScope(v, arg);
+            doNotInferScope(v, arg);
 
             if ((v.isReference() || v.isScope()) && p == sc.func)
             {
@@ -667,6 +659,13 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
         va = null;
     }
 
+    if (e.op == EXP.construct && va && (va.storage_class & STC.temp) && va._init)
+    {
+        // Initializing a temporary is safe, `escapeExp` will forward such vars
+        // to their `va._init` if needed.
+        return false;
+    }
+
     if (log && va) printf("va: %s\n", va.toChars());
 
     FuncDeclaration fd = sc.func;
@@ -701,32 +700,19 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
     void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue: %s\n", v.toChars());
-        if (v.isDataseg())
-            return;
 
         if (v == va)
             return;
 
         Dsymbol p = v.toParent2();
 
-        if (va && !vaIsRef && !va.isScope() && !v.isScope() &&
-            !v.isTypesafeVariadicArray && !va.isTypesafeVariadicArray &&
-            (va.isParameter() && va.maybeScope && v.isParameter() && v.maybeScope) &&
-            p == fd)
-        {
-            /* Add v to va's list of dependencies
-             */
-            va.addMaybe(v);
-            return;
-        }
-
         if (vaIsFirstRef && p == fd)
         {
             inferReturn(fd, v, /*returnScope:*/ true);
         }
 
         if (!(va && va.isScope()) || vaIsRef)
-            notMaybeScope(v, e);
+            doNotInferScope(v, e);
 
         if (v.isScope())
         {
@@ -785,27 +771,20 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
             }
             result |= sc.setUnsafeDIP1000(gag, ae.loc, "scope variable `%s` assigned to non-scope `%s`", v, e1);
         }
-        else if (v.isTypesafeVariadicArray && p == fd)
-        {
-            if (inferScope(va))
-                return;
-            result |= sc.setUnsafeDIP1000(gag, ae.loc, "variadic variable `%s` assigned to non-scope `%s`", v, e1);
-        }
         else
         {
             /* v is not 'scope', and we didn't check the scope of where we assigned it to.
              * It may escape via that assignment, therefore, v can never be 'scope'.
              */
             //printf("no infer for %s in %s, %d\n", v.toChars(), fd.ident.toChars(), __LINE__);
-            doNotInferScope(v, e);
+            if (!v.isParameter)
+                doNotInferScope(v, e);
         }
     }
 
     void onRef(VarDeclaration v, bool retRefTransition)
     {
         if (log) printf("byref: %s\n", v.toChars());
-        if (v.isDataseg())
-            return;
 
         if (checkScopeVarAddr(v, ae, sc, gag))
         {
@@ -845,7 +824,7 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
         }
 
         if (!(va && va.isScope()))
-            notMaybeScope(v, e);
+            doNotInferScope(v, e);
 
         if (p != sc.func)
             return;
@@ -856,8 +835,6 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
                 va.storage_class |= STC.return_ | STC.returninferred;
             return;
         }
-        if (e1.op == EXP.structLiteral)
-            return;
 
         result |= sc.setUnsafeDIP1000(gag, ae.loc, "reference to local variable `%s` assigned to non-scope `%s`", v, e1);
     }
@@ -884,7 +861,7 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
             Dsymbol p = v.toParent2();
 
             if (!(va && va.isScope()))
-                notMaybeScope(v, e);
+                doNotInferScope(v, e);
 
             if (!(v.isReference() || v.isScope()) || p != fd)
                 return;
@@ -909,8 +886,7 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
 
         /* Do not allow slicing of a static array returned by a function
          */
-        if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray() &&
-            !(va && va.storage_class & STC.temp))
+        if (ee.op == EXP.call && ee.type.toBasetype().isTypeSArray() && e1.type.toBasetype().isTypeDArray())
         {
             if (!gag)
                 sc.eSink.deprecation(ee.loc, "slice of static array temporary returned by `%s` assigned to longer lived variable `%s`",
@@ -919,31 +895,11 @@  bool checkAssignEscape(ref Scope sc, Expression e, bool gag, bool byRef)
             return;
         }
 
-        if (ee.op == EXP.call && ee.type.toBasetype().isTypeStruct() &&
-            (!va || !(va.storage_class & STC.temp) && !va.isScope()))
-        {
-            if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct temporary returned by `%s` assigned to longer lived variable `%s`", ee, e1))
-            {
-                result = true;
-                return;
-            }
-        }
-
-        if (ee.op == EXP.structLiteral &&
-            (!va || !(va.storage_class & STC.temp)))
-        {
-            if (sc.setUnsafeDIP1000(gag, ee.loc, "address of struct literal `%s` assigned to longer lived variable `%s`", ee, e1))
-            {
-                result = true;
-                return;
-            }
-        }
-
-        if (inferScope(va))
-            return;
+        const(char)* msg = (ee.op == EXP.structLiteral) ?
+            "address of struct literal `%s` assigned to `%s` with longer lifetime" :
+            "address of expression temporary returned by `%s` assigned to `%s` with longer lifetime";
 
-        result |= sc.setUnsafeDIP1000(gag, ee.loc,
-            "reference to stack allocated value returned by `%s` assigned to non-scope `%s`", ee, e1);
+        result |= sc.setUnsafeDIP1000(gag, ee.loc, msg, ee, e1);
     }
 
     scope EscapeByResults er = EscapeByResults(&onRef, &onValue, &onFunc, &onExp);
@@ -977,9 +933,6 @@  bool checkThrowEscape(ref Scope sc, Expression e, bool gag)
     void onValue(VarDeclaration v)
     {
         //printf("byvalue %s\n", v.toChars());
-        if (v.isDataseg())
-            return;
-
         if (v.isScope() && !v.iscatchvar)       // special case: allow catch var to be rethrown
                                                 // despite being `scope`
         {
@@ -989,7 +942,7 @@  bool checkThrowEscape(ref Scope sc, Expression e, bool gag)
         }
         else
         {
-            notMaybeScope(v, new ThrowExp(e.loc, e));
+            doNotInferScope(v, new ThrowExp(e.loc, e));
         }
     }
     void onFunc(FuncDeclaration fd, bool called) {}
@@ -1025,8 +978,6 @@  bool checkNewEscape(ref Scope sc, Expression e, bool gag)
     void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue `%s`\n", v.toChars());
-        if (v.isDataseg())
-            return;
 
         Dsymbol p = v.toParent2();
 
@@ -1049,15 +1000,10 @@  bool checkNewEscape(ref Scope sc, Expression e, bool gag)
                 return;
             }
         }
-        else if (v.isTypesafeVariadicArray && p == sc.func)
-        {
-            result |= sc.setUnsafeDIP1000(gag, e.loc,
-                "copying `%s` into allocated memory escapes a reference to variadic parameter `%s`", e, v);
-        }
         else
         {
             //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
-            notMaybeScope(v, e);
+            doNotInferScope(v, e);
         }
     }
 
@@ -1075,9 +1021,6 @@  bool checkNewEscape(ref Scope sc, Expression e, bool gag)
             return setUnsafePreview(&sc, fs, gag, e.loc, msg, e, v);
         }
 
-        if (v.isDataseg())
-            return;
-
         Dsymbol p = v.toParent2();
 
         if (!v.isReference())
@@ -1124,7 +1067,12 @@  bool checkNewEscape(ref Scope sc, Expression e, bool gag)
         }
     }
 
-    void onFunc(FuncDeclaration fd, bool called) {}
+    void onFunc(FuncDeclaration fd, bool called)
+    {
+        if (called)
+            result |= sc.setUnsafeDIP1000(gag, e.loc,
+                "nested function `%s` returns `scope` values and escapes them into allocated memory", fd);
+    }
 
     void onExp(Expression ee, bool retRefTransition)
     {
@@ -1203,8 +1151,6 @@  private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool g
     void onValue(VarDeclaration v)
     {
         if (log) printf("byvalue `%s`\n", v.toChars());
-        if (v.isDataseg())
-            return;
 
         const vsr = buildScopeRef(v.storage_class);
 
@@ -1215,7 +1161,13 @@  private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool g
             return;
         }
 
-        if (v.isScope())
+        if (v.isTypesafeVariadicArray && p == sc.func)
+        {
+            if (!gag)
+                sc.eSink.error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
+            result = false;
+        }
+        else if (v.isScope())
         {
             /* If `return scope` applies to v.
              */
@@ -1270,13 +1222,7 @@  private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool g
                 }
             }
         }
-        else if (v.isTypesafeVariadicArray && p == sc.func)
-        {
-            if (!gag)
-                sc.eSink.error(e.loc, "returning `%s` escapes a reference to variadic parameter `%s`", e.toChars(), v.toChars());
-            result = false;
-        }
-        else
+        else if (p == sc.func || !v.isParameter())
         {
             //printf("no infer for %s in %s, %d\n", v.toChars(), sc.func.ident.toChars(), __LINE__);
             doNotInferScope(v, e);
@@ -1332,24 +1278,15 @@  private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool g
             }
         }
 
-        if (v.isDataseg())
-            return;
-
         const vsr = buildScopeRef(v.storage_class);
 
         Dsymbol p = v.toParent2();
 
         // https://issues.dlang.org/show_bug.cgi?id=19965
-        if (!refs)
+        if (!refs && checkScopeVarAddr(v, e, sc, gag))
         {
-            if (sc.func.vthis == v)
-                notMaybeScope(v, e);
-
-            if (checkScopeVarAddr(v, e, sc, gag))
-            {
-                result = true;
-                return;
-            }
+            result = true;
+            return;
         }
 
         if (!v.isReference())
@@ -1360,7 +1297,7 @@  private bool checkReturnEscapeImpl(ref Scope sc, Expression e, bool refs, bool g
                 return;
             }
             FuncDeclaration fd = p.isFuncDeclaration();
-            if (fd && sc.func.returnInprocess)
+            if (fd && sc.func.scopeInprocess)
             {
                 /* Code like:
                  *   int x;
@@ -1488,7 +1425,7 @@  private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
     if (!v.isParameter() || v.isTypesafeVariadicArray || (returnScope && v.doNotInferReturn))
         return false;
 
-    if (!fd.returnInprocess)
+    if (!fd.scopeInprocess)
         return false;
 
     if (returnScope && !(v.isScope() || v.maybeScope))
@@ -1546,10 +1483,20 @@  private bool inferReturn(FuncDeclaration fd, VarDeclaration v, bool returnScope)
  * Params:
  *      e = expression to be returned by value
  *      er = where to place collected data
-  *     retRefTransition = if `e` is returned through a `return (ref) scope` function call
  */
 public
-void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransition = false)
+void escapeByValue(Expression e, ref scope EscapeByResults er)
+{
+    escapeExp(e, er, 0);
+}
+
+// Unified implementation of `escapeByValue` and `escapeByRef`
+// deref = derference level, if `p` has deref 0, then `*p` has deref 1, `&p` has -1, and `**p` has 2 etc.
+// For escapeByValue, deref = 0
+// For escapeByRef, deref = -1
+// Currently, `scope` is not transitive, so deref > 0 means no escaping, but `@live` does do transitive checking,
+// and future enhancements might add some form of transitive scope.
+void escapeExp(Expression e, ref scope EscapeByResults er, int deref)
 {
     //printf("[%s] escapeByValue, e: %s\n", e.loc.toChars(), e.toChars());
 
@@ -1563,55 +1510,92 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
          * allowed, but CTFE can generate one out of a new expression,
          * but it'll be placed in static data so no need to check it.
          */
-        if (e.e1.op != EXP.structLiteral)
-            escapeByRef(e.e1, er, retRefTransition);
+        if (deref == 0 && e.e1.op != EXP.structLiteral)
+            escapeExp(e.e1, er, deref - 1);
     }
 
     void visitSymOff(SymOffExp e)
     {
-        VarDeclaration v = e.var.isVarDeclaration();
-        if (v)
-            er.byRef(v, retRefTransition);
+        if (VarDeclaration v = e.var.isVarDeclaration())
+            er.varDeref(v, deref - 1);
     }
 
     void visitVar(VarExp e)
     {
         if (auto v = e.var.isVarDeclaration())
         {
-            if (v.type.hasPointers() || // not tracking non-pointers
-                v.storage_class & STC.lazy_) // lazy variables are actually pointers
-                er.byValue(v);
+            const refAddr = deref < 0 && v.storage_class & STC.ref_ ;
+            const tempVar = deref == 0 && v.storage_class & STC.temp;
+            if ((refAddr || tempVar) && v._init && v != er.lastTemp)
+            {
+                // If compiler generated ref temporary
+                //   (ref v = ex; ex)
+                // e.g. to extract side effects of `Tuple!(int, int).modify().expand[0]`
+                // look at the initializer instead
+                if (ExpInitializer ez = v._init.isExpInitializer())
+                {
+                    // Prevent endless loops. Consider:
+                    // `__field0 = (S __tup1 = S(x, y);) , __field0 = __tup1.__fields_field_0`
+                    // escapeExp would recurse on the lhs of the last assignment, which is __field0
+                    // again. In this case, we want the rhs.
+                    // Also consider appending a struct with a `return scope` constructor:
+                    // __appendtmp34 = __appendtmp34.this(null)
+                    // In that case we just break the cycle using `lastTemp`.
+                    auto lc = ez.exp.lastComma();
+                    auto restoreLastTemp = er.lastTemp;
+                    er.lastTemp = v;
+                    // printf("%s %s    TO    %s\n", e.loc.toChars, e.toChars, lc.toChars);
+                    if (lc.isAssignExp || lc.isConstructExp || lc.isBlitExp)
+                        escapeExp(lc.isBinExp().e2, er, deref);
+                    else
+                        escapeExp(ez.exp, er, deref);
+
+                    er.lastTemp = restoreLastTemp;
+                    return;
+                }
+            }
+
+            if (deref < 0 || e.type.hasPointers())
+                er.varDeref(v, deref);
         }
     }
 
     void visitThis(ThisExp e)
     {
+        // Special case because `__this2` isn't `ref` internally
+        if (deref == -1 && e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
+        {
+            escapeByValue(e, er);
+            return;
+        }
+
         if (e.var)
-            er.byValue(e.var);
+            er.varDeref(e.var, deref);
     }
 
     void visitPtr(PtrExp e)
     {
-        if (er.live && e.type.hasPointers())
-            escapeByValue(e.e1, er, retRefTransition);
+        if (deref < 0 || (er.live && e.type.hasPointers()))
+            escapeExp(e.e1, er, deref + 1);
     }
 
     void visitDotVar(DotVarExp e)
     {
-        auto t = e.e1.type.toBasetype();
-        if (e.type.hasPointers() && (er.live || t.ty == Tstruct))
-        {
-            escapeByValue(e.e1, er, retRefTransition);
-        }
+        auto t1b = e.e1.type.toBasetype();
+        // Accessing a class field dereferences the `this` pointer
+        if (t1b.isTypeClass())
+            escapeExp(e.e1, er, deref + 1);
+        else if (deref < 0 || e.type.hasPointers())
+            escapeExp(e.e1, er, deref);
     }
 
     void visitDelegate(DelegateExp e)
     {
         Type t = e.e1.type.toBasetype();
-        if (t.ty == Tclass || t.ty == Tpointer)
-            escapeByValue(e.e1, er, retRefTransition);
+        if (t.isTypeClass() || t.isTypePointer())
+            escapeByValue(e.e1, er);
         else
-            escapeByRef(e.e1, er, retRefTransition);
+            escapeByRef(e.e1, er);
         er.byFunc(e.func, false);
     }
 
@@ -1629,14 +1613,14 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
     void visitArrayLiteral(ArrayLiteralExp e)
     {
         Type tb = e.type.toBasetype();
-        if (tb.ty == Tsarray || tb.ty == Tarray)
+        if (tb.isTypeSArray() || tb.isTypeDArray())
         {
             if (e.basis)
-                escapeByValue(e.basis, er, retRefTransition);
+                escapeExp(e.basis, er, deref);
             foreach (el; *e.elements)
             {
                 if (el)
-                    escapeByValue(el, er, retRefTransition);
+                    escapeExp(el, er, deref);
             }
         }
     }
@@ -1648,120 +1632,127 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
             foreach (ex; *e.elements)
             {
                 if (ex)
-                    escapeByValue(ex, er, retRefTransition);
+                    escapeExp(ex, er, deref);
             }
         }
+        if (deref == -1)
+        {
+            er.byExp(e, er.inRetRefTransition > 0); //
+        }
     }
 
     void visitNew(NewExp e)
     {
         Type tb = e.newtype.toBasetype();
-        if (tb.ty == Tstruct && !e.member && e.arguments)
+        if (tb.isTypeStruct() && !e.member && e.arguments)
         {
             foreach (ex; *e.arguments)
             {
                 if (ex)
-                    escapeByValue(ex, er, retRefTransition);
+                    escapeExp(ex, er, deref);
             }
         }
     }
 
     void visitCast(CastExp e)
     {
-        if (!e.type.hasPointers())
+        if (deref < 0 || !e.type.hasPointers())
             return;
         Type tb = e.type.toBasetype();
-        if (tb.ty == Tarray && e.e1.type.toBasetype().ty == Tsarray)
-        {
-            escapeByRef(e.e1, er, retRefTransition);
-        }
+        if (tb.isTypeDArray() && e.e1.type.toBasetype().isTypeSArray())
+            escapeExp(e.e1, er, deref - 1);
         else
-            escapeByValue(e.e1, er, retRefTransition);
+            escapeExp(e.e1, er, deref);
     }
 
     void visitSlice(SliceExp e)
     {
-        if (auto ve = e.e1.isVarExp())
-        {
-            VarDeclaration v = ve.var.isVarDeclaration();
-            Type tb = e.type.toBasetype();
-            if (v)
-            {
-                if (tb.ty == Tsarray)
-                    return;
-                if (v.isTypesafeVariadicArray)
-                {
-                    er.byValue(v);
-                    return;
-                }
-            }
-        }
-        Type t1b = e.e1.type.toBasetype();
-        if (t1b.ty == Tsarray)
-        {
-            Type tb = e.type.toBasetype();
-            if (tb.ty != Tsarray)
-                escapeByRef(e.e1, er, retRefTransition);
-        }
-        else
-            escapeByValue(e.e1, er, retRefTransition);
+        // Usually: slicing a static array escapes by ref, slicing a dynamic array escapes by value.
+        // However, slices with compile-time known length can implicitly converted to static arrays:
+        // int*[3] b = sa[0 .. 3];
+        // So we need to compare the type before slicing and after slicing
+        const bool staticBefore = e.e1.type.toBasetype().isTypeSArray() !is null;
+        const bool staticAfter = e.type.toBasetype().isTypeSArray() !is null;
+        escapeExp(e.e1, er, deref + staticAfter - staticBefore);
     }
 
     void visitIndex(IndexExp e)
     {
-        if (e.e1.type.toBasetype().ty == Tsarray ||
-            er.live && e.type.hasPointers())
+        Type tb = e.e1.type.toBasetype();
+
+        if (tb.isTypeSArray())
+        {
+            escapeExp(e.e1, er, deref);
+        }
+        else if (tb.isTypeDArray())
         {
-            escapeByValue(e.e1, er, retRefTransition);
+            escapeExp(e.e1, er, deref + 1);
         }
     }
 
     void visitBin(BinExp e)
     {
-        Type tb = e.type.toBasetype();
-        if (tb.ty == Tpointer)
+        if (e.type.toBasetype().isTypePointer())
         {
-            escapeByValue(e.e1, er, retRefTransition);
-            escapeByValue(e.e2, er, retRefTransition);
+            // The expression must be pointer arithmetic, e.g. `p + 1` or `1 + p`
+            escapeExp(e.e1, er, deref);
+            escapeExp(e.e2, er, deref);
         }
     }
 
     void visitBinAssign(BinAssignExp e)
     {
-        escapeByValue(e.e1, er, retRefTransition);
+        escapeExp(e.e1, er, deref);
     }
 
     void visitAssign(AssignExp e)
     {
-        escapeByValue(e.e1, er, retRefTransition);
+        escapeExp(e.e1, er, deref);
     }
 
     void visitComma(CommaExp e)
     {
-        escapeByValue(e.e2, er, retRefTransition);
+        escapeExp(e.e2, er, deref);
     }
 
     void visitCond(CondExp e)
     {
-        escapeByValue(e.e1, er, retRefTransition);
-        escapeByValue(e.e2, er, retRefTransition);
+        escapeExp(e.e1, er, deref);
+        escapeExp(e.e2, er, deref);
     }
 
     void visitCall(CallExp e)
     {
         //printf("CallExp(): %s\n", e.toChars());
-        /* Check each argument that is
-         * passed as 'return scope'.
-         */
+        // Check each argument that is passed as 'return scope'.
         TypeFunction tf = e.calledFunctionType();
-        if (!tf || !e.type.hasPointers())
+        if (!tf)
+            return;
+
+        if (deref < 0 && !tf.isref)
+        {
+            er.byExp(e, er.inRetRefTransition > 0);
+            return;
+        }
+
+        // A function may have a return scope struct parameter, but only return an `int` field of that struct
+        if (deref >= 0 && !e.type.hasPointers())
             return;
 
+        /// Given a `scope` / `return scope` / `return ref` annotation,
+        /// get the corresponding pointer dereference level
+        static int paramDeref(ScopeRef psr)
+        {
+            return
+                (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope) ? -1 :
+                (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope) ? 0 :
+                +1;
+        }
+
         if (e.arguments && e.arguments.length)
         {
-            /* j=1 if _arguments[] is first argument,
-             * skip it because it is not passed by ref
-             */
+            // j=1 if _arguments[] is first argument,
+            // skip it because it is not passed by ref
             int j = tf.isDstyleVariadic();
             for (size_t i = j; i < e.arguments.length; ++i)
             {
@@ -1772,139 +1763,73 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
                     Parameter p = tf.parameterList[i - j];
                     const stc = tf.parameterStorageClass(null, p);
                     ScopeRef psr = buildScopeRef(stc);
-                    if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                    {
-                        if (tf.isref)
-                        {
-                            /* ignore `ref` on struct constructor return because
-                             *   struct S { this(return scope int* q) { this.p = q; } int* p; }
-                             * is different from:
-                             *   ref char* front(return scope char** q) { return *q; }
-                             * https://github.com/dlang/dmd/pull/14869
-                             */
-                            if (auto dve = e.e1.isDotVarExp())
-                                if (auto fd = dve.var.isFuncDeclaration())
-                                    if (fd.isCtorDeclaration() && tf.next.toBasetype().isTypeStruct())
-                                    {
-                                        escapeByValue(arg, er, retRefTransition);
-                                    }
-                        }
-                        else
-                            escapeByValue(arg, er, true);
-                    }
-                    else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                    {
-                        if (tf.isref)
-                        {
-                            /* Treat:
-                             *   ref P foo(return ref P p)
-                             * as:
-                             *   p;
-                             */
-                            escapeByValue(arg, er, retRefTransition);
-                        }
-                        else
-                            escapeByRef(arg, er, retRefTransition);
-                    }
+
+                    // For struct constructors, `tf.isref` is true, but for escape analysis,
+                    // it's as if they return `void` and escape through the first (`this`) parameter:
+                    // void assign(ref S this, return scope constructorArgs...)
+                    // If you then return the constructed result by value, it doesn't count
+                    // as dereferencing the scope arguments, they're still escaped.
+                    const isRef = tf.isref && !(tf.isctor && paramDeref(psr) == 0);
+                    const maybeInaccurate = deref == 0 && paramDeref(psr) == 0;
+                    er.inRetRefTransition += maybeInaccurate;
+                    if (paramDeref(psr) <= 0)
+                        escapeExp(arg, er, deref + paramDeref(psr) + isRef);
+                    er.inRetRefTransition -= maybeInaccurate;
                 }
             }
         }
+
         // If 'this' is returned, check it too
         Type t1 = e.e1.type.toBasetype();
-        if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
+        DotVarExp dve = e.e1.isDotVarExp();
+        if (dve && t1.ty == Tfunction)
         {
-            DotVarExp dve = e.e1.isDotVarExp();
             FuncDeclaration fd = dve.var.isFuncDeclaration();
-            if (fd && fd.isThis())
-            {
-                /* Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
-                 */
-
-                /*****************************
-                 * Concoct storage class for member function's implicit `this` parameter.
-                 * Params:
-                 *      fd = member function
-                 * Returns:
-                 *      storage class for fd's `this`
-                 */
-                StorageClass getThisStorageClass(FuncDeclaration fd)
-                {
-                    StorageClass stc;
-                    auto tf = fd.type.toBasetype().isTypeFunction();
-                    if (tf.isreturn)
-                        stc |= STC.return_;
-                    if (tf.isreturnscope)
-                        stc |= STC.returnScope | STC.scope_;
-                    auto ad = fd.isThis();
-                    if (ad.isClassDeclaration() || tf.isScopeQual)
-                        stc |= STC.scope_;
-                    if (ad.isStructDeclaration())
-                        stc |= STC.ref_;        // `this` for a struct member function is passed by `ref`
-                    return stc;
-                }
-
-                const psr = buildScopeRef(getThisStorageClass(fd));
-                if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                {
-                    if (!tf.isref || tf.isctor)
-                        escapeByValue(dve.e1, er, retRefTransition);
-                }
-                else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                {
-                    if (tf.isref)
-                    {
-                        /* Treat calling:
-                         *   struct S { ref S foo() return; }
-                         * as:
-                         *   this;
-                         */
-                        escapeByValue(dve.e1, er, retRefTransition);
-                    }
-                    else
-                        escapeByRef(dve.e1, er, psr == ScopeRef.ReturnRef_Scope);
-                }
-            }
+            if (!fd)
+                return;
 
-            // If it's also a nested function that is 'return scope'
-            if (fd && fd.isNested())
+            // https://issues.dlang.org/show_bug.cgi?id=20149#c10
+            if (deref < 0 && dve.var.isCtorDeclaration())
             {
-                if (tf.isreturn && tf.isScopeQual)
-                {
-                    if (tf.isreturnscope)
-                        er.byFunc(fd, true);
-                    else
-                        er.byExp(e, false);
-                }
+                er.byExp(e, false);
+                return;
             }
+
+            // Calling a non-static member function dve.var, which is returning `this`, and with dve.e1 representing `this`
+            const psr = buildScopeRef(getThisStorageClass(fd));
+            er.inRetRefTransition += (psr == ScopeRef.ReturnRef_Scope);
+            if (paramDeref(psr) <= 0)
+                escapeExp(dve.e1, er, deref + paramDeref(psr) + (tf.isref && !tf.isctor));
+            er.inRetRefTransition -= (psr == ScopeRef.ReturnRef_Scope);
         }
 
-        /* If returning the result of a delegate call, the .ptr
-         * field of the delegate must be checked.
-         */
-        if (t1.isTypeDelegate())
+        // The return value of a delegate call with return (scope) may point to a closure variable,
+        // so escape the delegate in case it's `scope` / stack allocated.
+        if (t1.isTypeDelegate() && tf.isreturn)
         {
-            if (tf.isreturn)
-                escapeByValue(e.e1, er, retRefTransition);
+            escapeExp(e.e1, er, deref + tf.isref);
         }
 
-        /* If it's a nested function that is 'return scope'
-         */
+        // If `fd` is a nested function that's return ref / return scope, check that
+        // it doesn't escape closure vars
         if (auto ve = e.e1.isVarExp())
         {
-            FuncDeclaration fd = ve.var.isFuncDeclaration();
-            if (fd && fd.isNested())
+            if (FuncDeclaration fd = ve.var.isFuncDeclaration())
             {
-                if (tf.isreturn && tf.isScopeQual)
+                if (fd.isNested() && tf.isreturn)
                 {
-                    if (tf.isreturnscope)
-                        er.byFunc(fd, true);
-                    else
-                        er.byExp(e, false);
+                    er.byFunc(fd, true);
                 }
             }
         }
     }
 
+    if (deref > 0 && !er.live)
+        return; // scope is not transitive currently, so dereferencing expressions don't escape
+
+    if (deref >= 0 && er.live && !e.type.hasPointers())
+        return; // can't escape non-pointer values by value
+
     switch (e.op)
     {
         case EXP.address: return visitAddr(e.isAddrExp());
@@ -1929,14 +1854,36 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
         case EXP.question: return visitCond(e.isCondExp());
         case EXP.call: return visitCall(e.isCallExp());
         default:
-            if (auto b = e.isBinExp())
-                return visitBin(b);
             if (auto ba = e.isBinAssignExp())
                 return visitBinAssign(ba);
+            if (auto b = e.isBinExp())
+                return visitBin(b);
             return visit(e);
     }
 }
 
+/*****************************
+ * Concoct storage class for member function's implicit `this` parameter.
+ * Params:
+ *      fd = member function
+ * Returns:
+ *      storage class for fd's `this`
+ */
+StorageClass getThisStorageClass(FuncDeclaration fd)
+{
+    StorageClass stc;
+    auto tf = fd.type.toBasetype().isTypeFunction();
+    if (tf.isreturn)
+        stc |= STC.return_;
+    if (tf.isreturnscope)
+        stc |= STC.returnScope | STC.scope_;
+    auto ad = fd.isThis();
+    if ((ad && ad.isClassDeclaration()) || tf.isScopeQual)
+        stc |= STC.scope_;
+    if (ad && ad.isStructDeclaration())
+        stc |= STC.ref_;        // `this` for a struct member function is passed by `ref`
+    return stc;
+}
 
 /****************************************
  * e is an expression to be returned by 'ref'.
@@ -1954,238 +1901,10 @@  void escapeByValue(Expression e, ref scope EscapeByResults er, bool retRefTransi
  * Params:
  *      e = expression to be returned by 'ref'
  *      er = where to place collected data
- *      retRefTransition = if `e` is returned through a `return (ref) scope` function call
  */
-private
-void escapeByRef(Expression e, ref scope EscapeByResults er, bool retRefTransition = false)
+void escapeByRef(Expression e, ref scope EscapeByResults er)
 {
-    //printf("[%s] escapeByRef, e: %s, retRefTransition: %d\n", e.loc.toChars(), e.toChars(), retRefTransition);
-    void visit(Expression e)
-    {
-    }
-
-    void visitVar(VarExp e)
-    {
-        auto v = e.var.isVarDeclaration();
-        if (v)
-        {
-            if (v.storage_class & STC.ref_ && v.storage_class & (STC.foreach_ | STC.temp) && v._init)
-            {
-                /* If compiler generated ref temporary
-                    *   (ref v = ex; ex)
-                    * look at the initializer instead
-                    */
-                if (ExpInitializer ez = v._init.isExpInitializer())
-                {
-                    if (auto ce = ez.exp.isConstructExp())
-                        escapeByRef(ce.e2, er, retRefTransition);
-                    else
-                        escapeByRef(ez.exp, er, retRefTransition);
-                }
-            }
-            else
-                er.byRef(v, retRefTransition);
-        }
-    }
-
-    void visitThis(ThisExp e)
-    {
-        if (e.var && e.var.toParent2().isFuncDeclaration().hasDualContext())
-            escapeByValue(e, er, retRefTransition);
-        else if (e.var)
-            er.byRef(e.var, retRefTransition);
-    }
-
-    void visitPtr(PtrExp e)
-    {
-        escapeByValue(e.e1, er, retRefTransition);
-    }
-
-    void visitIndex(IndexExp e)
-    {
-        Type tb = e.e1.type.toBasetype();
-        if (auto ve = e.e1.isVarExp())
-        {
-            VarDeclaration v = ve.var.isVarDeclaration();
-            if (v && v.isTypesafeVariadicArray)
-            {
-                er.byRef(v, retRefTransition);
-                return;
-            }
-        }
-        if (tb.ty == Tsarray)
-        {
-            escapeByRef(e.e1, er, retRefTransition);
-        }
-        else if (tb.ty == Tarray)
-        {
-            escapeByValue(e.e1, er, retRefTransition);
-        }
-    }
-
-    void visitStructLiteral(StructLiteralExp e)
-    {
-        if (e.elements)
-        {
-            foreach (ex; *e.elements)
-            {
-                if (ex)
-                    escapeByRef(ex, er, retRefTransition);
-            }
-        }
-        er.byExp(e, retRefTransition);
-    }
-
-    void visitDotVar(DotVarExp e)
-    {
-        Type t1b = e.e1.type.toBasetype();
-        if (t1b.ty == Tclass)
-            escapeByValue(e.e1, er, retRefTransition);
-        else
-            escapeByRef(e.e1, er, retRefTransition);
-    }
-
-    void visitBinAssign(BinAssignExp e)
-    {
-        escapeByRef(e.e1, er, retRefTransition);
-    }
-
-    void visitAssign(AssignExp e)
-    {
-        escapeByRef(e.e1, er, retRefTransition);
-    }
-
-    void visitComma(CommaExp e)
-    {
-        escapeByRef(e.e2, er, retRefTransition);
-    }
-
-    void visitCond(CondExp e)
-    {
-        escapeByRef(e.e1, er, retRefTransition);
-        escapeByRef(e.e2, er, retRefTransition);
-    }
-
-    void visitCall(CallExp e)
-    {
-        //printf("escapeByRef.CallExp(): %s\n", e.toChars());
-        /* If the function returns by ref, check each argument that is
-         * passed as 'return ref'.
-         */
-        TypeFunction tf = e.calledFunctionType();
-        if (!tf)
-            return;
-        if (tf.isref)
-        {
-            if (e.arguments && e.arguments.length)
-            {
-                /* j=1 if _arguments[] is first argument,
-                 * skip it because it is not passed by ref
-                 */
-                int j = tf.isDstyleVariadic();
-                for (size_t i = j; i < e.arguments.length; ++i)
-                {
-                    Expression arg = (*e.arguments)[i];
-                    size_t nparams = tf.parameterList.length;
-                    if (i - j < nparams && i >= j)
-                    {
-                        Parameter p = tf.parameterList[i - j];
-                        const stc = tf.parameterStorageClass(null, p);
-                        ScopeRef psr = buildScopeRef(stc);
-                        if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                            escapeByRef(arg, er, retRefTransition);
-                        else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                        {
-                            if (auto de = arg.isDelegateExp())
-                            {
-                                if (de.func.isNested())
-                                    er.byExp(de, false);
-                            }
-                            else
-                                escapeByValue(arg, er, retRefTransition);
-                        }
-                    }
-                }
-            }
-            // If 'this' is returned by ref, check it too
-            Type t1 = e.e1.type.toBasetype();
-            if (e.e1.op == EXP.dotVariable && t1.ty == Tfunction)
-            {
-                DotVarExp dve = e.e1.isDotVarExp();
-
-                // https://issues.dlang.org/show_bug.cgi?id=20149#c10
-                if (dve.var.isCtorDeclaration())
-                {
-                    er.byExp(e, false);
-                    return;
-                }
-
-                StorageClass stc = dve.var.storage_class & (STC.return_ | STC.scope_ | STC.ref_);
-                if (tf.isreturn)
-                    stc |= STC.return_;
-                if (tf.isref)
-                    stc |= STC.ref_;
-                if (tf.isScopeQual)
-                    stc |= STC.scope_;
-                if (tf.isreturnscope)
-                    stc |= STC.returnScope;
-
-                const psr = buildScopeRef(stc);
-                if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
-                    escapeByRef(dve.e1, er, psr == ScopeRef.ReturnRef_Scope);
-                else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
-                    escapeByValue(dve.e1, er, retRefTransition);
-
-                // If it's also a nested function that is 'return ref'
-                if (FuncDeclaration fd = dve.var.isFuncDeclaration())
-                {
-                    if (fd.isNested() && tf.isreturn)
-                    {
-                        er.byExp(e, false);
-                    }
-                }
-            }
-            // If it's a delegate, check it too
-            if (e.e1.op == EXP.variable && t1.ty == Tdelegate)
-            {
-                escapeByValue(e.e1, er, retRefTransition);
-            }
-
-            /* If it's a nested function that is 'return ref'
-             */
-            if (auto ve = e.e1.isVarExp())
-            {
-                FuncDeclaration fd = ve.var.isFuncDeclaration();
-                if (fd && fd.isNested())
-                {
-                    if (tf.isreturn)
-                        er.byExp(e, false);
-                }
-            }
-        }
-        else
-            er.byExp(e, retRefTransition);
-    }
-
-    switch (e.op)
-    {
-        case EXP.variable: return visitVar(e.isVarExp());
-        case EXP.this_: return visitThis(e.isThisExp());
-        case EXP.star: return visitPtr(e.isPtrExp());
-        case EXP.structLiteral: return visitStructLiteral(e.isStructLiteralExp());
-        case EXP.dotVariable: return visitDotVar(e.isDotVarExp());
-        case EXP.index: return visitIndex(e.isIndexExp());
-        case EXP.blit: return visitAssign(e.isBlitExp());
-        case EXP.construct: return visitAssign(e.isConstructExp());
-        case EXP.assign: return visitAssign(e.isAssignExp());
-        case EXP.comma: return visitComma(e.isCommaExp());
-        case EXP.question: return visitCond(e.isCondExp());
-        case EXP.call: return visitCall(e.isCallExp());
-        default:
-            if (auto ba = e.isBinAssignExp())
-                return visitBinAssign(ba);
-            return visit(e);
-    }
+    escapeExp(e, er, -1);
 }
 
 /************************************
@@ -2213,6 +1932,20 @@  struct EscapeByResults
     void delegate(VarDeclaration, bool retRefTransition) byRef;
     /// called on variables with values containing pointers
     void delegate(VarDeclaration) byValue;
+
+    /// Switch over `byValue` and `byRef` based on `deref` level (-1 = by ref, 0 = by value, 1 = only for live currently)
+    private void varDeref(VarDeclaration var, int deref)
+    {
+        if (var.isDataseg())
+            return;
+        if (deref == -1)
+            byRef(var, inRetRefTransition > 0);
+        else if (deref == 0)
+            byValue(var);
+        else if (deref > 0 && live)
+            byValue(var);
+    }
+
     /// called on nested functions that are turned into delegates
     /// When `called` is true, it means the delegate escapes variables
     /// from the closure through a call to it, while `false` means the
@@ -2223,6 +1956,14 @@  struct EscapeByResults
 
     /// if @live semantics apply, i.e. expressions `p`, `*p`, `**p`, etc., all return `p`.
     bool live = false;
+
+    /// Incremented / decremented every time an ambiguous return ref/scope parameter is checked.
+    /// See retRefTransition above.
+    private int inRetRefTransition = 0;
+
+    /// When forwarding a temp var to its initializer,
+    /// keep track of the temp var to break endless loops
+    private VarDeclaration lastTemp = null;
 }
 
 /*************************
@@ -2266,7 +2007,7 @@  public void findAllOuterAccessedVariables(FuncDeclaration fd, VarDeclarations* v
  *          - `VarDeclaration` of a non-scope parameter it was assigned to
  *          - `null` for no reason
  */
-private void notMaybeScope(VarDeclaration v, RootObject o)
+private void doNotInferScope(VarDeclaration v, RootObject o)
 {
     if (v.maybeScope)
     {
@@ -2276,23 +2017,6 @@  private void notMaybeScope(VarDeclaration v, RootObject o)
     }
 }
 
-/***********************************
- * Turn off `maybeScope` for variable `v` if it's not a parameter.
- *
- * This is for compatibility with the old system with both `STC.maybescope` and `VarDeclaration.doNotInferScope`,
- * which is now just `VarDeclaration.maybeScope`.
- * This function should probably be removed in future refactors.
- *
- * Params:
- *      v = variable
- *      o = reason for it being turned off
- */
-private void doNotInferScope(VarDeclaration v, RootObject o)
-{
-    if (!v.isParameter)
-        notMaybeScope(v, o);
-}
-
 /***********************************
  * After semantic analysis of the function body,
  * try to infer `scope` / `return` on the parameters
@@ -2305,48 +2029,21 @@  private void doNotInferScope(VarDeclaration v, RootObject o)
 public
 void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
 {
-
-    if (funcdecl.returnInprocess)
-    {
-        funcdecl.returnInprocess = false;
-        if (funcdecl.storage_class & STC.return_)
-        {
-            if (funcdecl.type == f)
-                f = cast(TypeFunction)f.copy();
-            f.isreturn = true;
-            f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope);
-            if (funcdecl.storage_class & STC.returninferred)
-                f.isreturninferred = true;
-        }
-    }
-
-    if (!funcdecl.inferScope)
+    if (!funcdecl.scopeInprocess)
         return;
-    funcdecl.inferScope = false;
+    funcdecl.scopeInprocess = false;
 
-    // Eliminate maybescope's
+    if (funcdecl.storage_class & STC.return_)
     {
-        // Create and fill array[] with maybe candidates from the `this` and the parameters
-        VarDeclaration[10] tmp = void;
-        size_t dim = (funcdecl.vthis !is null) + (funcdecl.parameters ? funcdecl.parameters.length : 0);
-
-        import dmd.common.smallbuffer : SmallBuffer;
-        auto sb = SmallBuffer!VarDeclaration(dim, tmp[]);
-        VarDeclaration[] array = sb[];
-
-        size_t n = 0;
-        if (funcdecl.vthis)
-            array[n++] = funcdecl.vthis;
-        if (funcdecl.parameters)
-        {
-            foreach (v; *funcdecl.parameters)
-            {
-                array[n++] = v;
-            }
-        }
-        eliminateMaybeScopes(array[0 .. n]);
+        if (funcdecl.type == f)
+            f = cast(TypeFunction)f.copy();
+        f.isreturn = true;
+        f.isreturnscope = cast(bool) (funcdecl.storage_class & STC.returnScope);
+        if (funcdecl.storage_class & STC.returninferred)
+            f.isreturninferred = true;
     }
 
+
     // Infer STC.scope_
     if (funcdecl.parameters && !funcdecl.errors)
     {
@@ -2370,61 +2067,6 @@  void finishScopeParamInference(FuncDeclaration funcdecl, ref TypeFunction f)
     }
 }
 
-/**********************************************
- * Have some variables that are maybescopes that were
- * assigned values from other maybescope variables.
- * Now that semantic analysis of the function is
- * complete, we can finalize this by turning off
- * maybescope for array elements that cannot be scope.
- *
- * $(TABLE2 Scope Table,
- * $(THEAD `va`, `v`,    =>,  `va` ,  `v`  )
- * $(TROW maybe, maybe,  =>,  scope,  scope)
- * $(TROW scope, scope,  =>,  scope,  scope)
- * $(TROW scope, maybe,  =>,  scope,  scope)
- * $(TROW maybe, scope,  =>,  scope,  scope)
- * $(TROW -    , -    ,  =>,  -    ,  -    )
- * $(TROW -    , maybe,  =>,  -    ,  -    )
- * $(TROW -    , scope,  =>,  error,  error)
- * $(TROW maybe, -    ,  =>,  scope,  -    )
- * $(TROW scope, -    ,  =>,  scope,  -    )
- * )
- * Params:
- *      array = array of variables that were assigned to from maybescope variables
- */
-private void eliminateMaybeScopes(VarDeclaration[] array)
-{
-    enum log = false;
-    if (log) printf("eliminateMaybeScopes()\n");
-    bool changes;
-    do
-    {
-        changes = false;
-        foreach (va; array)
-        {
-            if (log) printf("  va = %s\n", va.toChars());
-            if (!(va.maybeScope || va.isScope()))
-            {
-                if (va.maybes)
-                {
-                    foreach (v; *va.maybes)
-                    {
-                        if (log) printf("    v = %s\n", v.toChars());
-                        if (v.maybeScope)
-                        {
-                            // v cannot be scope since it is assigned to a non-scope va
-                            notMaybeScope(v, va);
-                            if (!v.isReference())
-                                v.storage_class &= ~(STC.return_ | STC.returninferred);
-                            changes = true;
-                        }
-                    }
-                }
-            }
-        }
-    } while (changes);
-}
-
 /************************************************
  * Is type a reference to a mutable value?
  *
@@ -2552,24 +2194,6 @@  private EnclosedBy enclosesLifetimeOf(VarDeclaration va, VarDeclaration v)
     return EnclosedBy.none;
 }
 
-/***************************************
- * Add variable `v` to maybes[]
- *
- * When a maybescope variable `v` is assigned to a maybescope variable `va`,
- * we cannot determine if `this` is actually scope until the semantic
- * analysis for the function is completed. Thus, we save the data
- * until then.
- * Params:
- *     v = a variable with `maybeScope == true` that was assigned to `this`
- */
-private void addMaybe(VarDeclaration va, VarDeclaration v)
-{
-    //printf("add %s to %s's list of dependencies\n", v.toChars(), toChars());
-    if (!va.maybes)
-        va.maybes = new VarDeclarations();
-    va.maybes.push(v);
-}
-
 // `setUnsafePreview` partially evaluated for dip1000
 public
 bool setUnsafeDIP1000(ref Scope sc, bool gag, Loc loc, const(char)* msg,
@@ -2599,7 +2223,7 @@  private bool checkScopeVarAddr(VarDeclaration v, Expression e, ref Scope sc, boo
 
     if (!v.isScope())
     {
-        notMaybeScope(v, e);
+        doNotInferScope(v, e);
         return false;
     }
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index a69b64d6b78..3d2ad471f21 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -33,6 +33,7 @@  import dmd.dclass;
 import dmd.dcast;
 import dmd.delegatize;
 import dmd.denum;
+import dmd.deps;
 import dmd.dimport;
 import dmd.dinterpret;
 import dmd.dmangle;
@@ -547,7 +548,7 @@  private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
     // https://issues.dlang.org/show_bug.cgi?id=12585
     // Extract the side effect part if ue.e1 is comma.
 
-    if ((sc.flags & SCOPE.ctfe) ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
+    if (sc.ctfe ? hasSideEffect(e1) : !isTrivialExp(e1)) // match logic in extractSideEffect()
     {
         /* Even if opDollar is needed, 'e1' should be evaluate only once. So
          * Rewrite:
@@ -948,7 +949,7 @@  private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
     SearchOptFlags flags = SearchOpt.all;
     Dsymbol s;
 
-    if (sc.flags & SCOPE.ignoresymbolvisibility)
+    if (sc.ignoresymbolvisibility)
         flags |= SearchOpt.ignoreVisibility;
 
     // First look in local scopes
@@ -965,8 +966,7 @@  private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
     FuncDeclaration f = s.isFuncDeclaration();
     if (f)
     {
-        TemplateDeclaration td = getFuncTemplateDecl(f);
-        if (td)
+        if (TemplateDeclaration td = getFuncTemplateDecl(f))
         {
             if (td.overroot)
                 td = td.overroot;
@@ -1351,7 +1351,7 @@  private Expression resolveUFCSProperties(Scope* sc, Expression e1, Expression e2
         e = new CallExp(loc, e, arguments);
 
         // https://issues.dlang.org/show_bug.cgi?id=24017
-        if (sc.flags & SCOPE.debug_)
+        if (sc.debug_)
             e.isCallExp().inDebugStatement = true;
 
         e = e.expressionSemantic(sc);
@@ -1865,7 +1865,7 @@  private bool checkPurity(FuncDeclaration f, const ref Loc loc, Scope* sc)
         return false;
     if (sc.intypeof == 1)
         return false;
-    if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+    if (sc.ctfe || sc.debug_)
         return false;
 
     // If the call has a pure parent, then the called func must be pure.
@@ -1974,7 +1974,7 @@  private bool checkPurity(VarDeclaration v, const ref Loc loc, Scope* sc)
         return false;
     if (sc.intypeof == 1)
         return false; // allow violations inside typeof(expression)
-    if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+    if (sc.ctfe || sc.debug_)
         return false; // allow violations inside compile-time evaluated expressions and debug conditionals
     if (v.ident == Id.ctfe)
         return false; // magic variable never violates pure and safe
@@ -2104,9 +2104,9 @@  private bool checkSafety(FuncDeclaration f, ref Loc loc, Scope* sc)
         return false;
     if (sc.intypeof == 1)
         return false;
-    if (sc.flags & SCOPE.debug_)
+    if (sc.debug_)
         return false;
-    if ((sc.flags & SCOPE.ctfe) && sc.func)
+    if (sc.ctfe && sc.func)
         return false;
 
     if (!sc.func)
@@ -2179,7 +2179,7 @@  private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
         return false;
     if (sc.intypeof == 1)
         return false;
-    if (sc.flags & (SCOPE.ctfe | SCOPE.debug_))
+    if (sc.ctfe || sc.debug_)
         return false;
     /* The original expressions (`new S(...)` or `new S[...]``) will be
      * verified instead. This is to keep errors related to the original code
@@ -2391,7 +2391,7 @@  private Expression resolvePropertiesX(Scope* sc, Expression e1, Expression e2 =
         tthis = dve.e1.type;
         goto Lfd;
     }
-    else if (sc && sc.flags & SCOPE.Cfile && e1.isVarExp() && !e2)
+    else if (sc && sc.inCfile && e1.isVarExp() && !e2)
     {
         // ImportC: do not implicitly call function if no ( ) are present
     }
@@ -3724,7 +3724,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
     {
         if (!e.type)
             e.type = Type.tfloat64;
-        else if (e.type.isimaginary && sc.flags & SCOPE.Cfile)
+        else if (e.type.isimaginary && sc.inCfile)
         {
             /* Convert to core.stdc.config.complex
              */
@@ -3861,8 +3861,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 if (global.params.fixAliasThis)
                 {
-                    ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol();
-                    if (expDsym)
+                    if (ExpressionDsymbol expDsym = scopesym.isExpressionDsymbol())
                     {
                         //printf("expDsym = %s\n", expDsym.exp.toChars());
                         result = expDsym.exp.expressionSemantic(sc);
@@ -3906,7 +3905,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if (exp.ident == Id.ctfe)
         {
-            if (sc.flags & SCOPE.ctfe)
+            if (sc.ctfe)
             {
                 error(exp.loc, "variable `__ctfe` cannot be read at compile time");
                 return setError();
@@ -4290,7 +4289,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             buffer.write4(0);
             e.setData(buffer.extractData(), newlen, 4);
-            if (sc && sc.flags & SCOPE.Cfile)
+            if (sc && sc.inCfile)
                 e.type = Type.tuns32.sarrayOf(e.len + 1);
             else
                 e.type = Type.tdchar.immutableOf().arrayOf();
@@ -4315,7 +4314,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             buffer.writeUTF16(0);
             e.setData(buffer.extractData(), newlen, 2);
-            if (sc && sc.flags & SCOPE.Cfile)
+            if (sc && sc.inCfile)
                 e.type = Type.tuns16.sarrayOf(e.len + 1);
             else
                 e.type = Type.twchar.immutableOf().arrayOf();
@@ -4327,7 +4326,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             goto default;
 
         default:
-            if (sc && sc.flags & SCOPE.Cfile)
+            if (sc && sc.inCfile)
                 e.type = Type.tchar.sarrayOf(e.len + 1);
             else
                 e.type = Type.tchar.immutableOf().arrayOf();
@@ -4526,7 +4525,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         Type t = cle.type.typeSemantic(cle.loc, sc);
         auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
-        auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
+        auto e = initializerToExpression(init, t, sc.inCfile);
         if (!e)
         {
             error(cle.loc, "cannot convert initializer `%s` to expression", toChars(init));
@@ -5099,7 +5098,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return;
             }
             else if (sc.needsCodegen() && // interpreter doesn't need this lowered
-                     !exp.onstack && !exp.type.isscope()) // these won't use the GC
+                     !exp.onstack && !exp.type.isScopeClass()) // these won't use the GC
             {
                 /* replace `new T(arguments)` with `core.lifetime._d_newclassT!T(arguments)`
                  * or `_d_newclassTTrace`
@@ -5427,7 +5426,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         Expression d = new DeclarationExp(e.loc, e.cd);
         sc = sc.push(); // just create new scope
-        sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+        sc.ctfe = false; // temporary stop CTFE
         d = d.expressionSemantic(sc);
         sc = sc.pop();
 
@@ -5595,7 +5594,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         uint olderrors;
 
         sc = sc.push(); // just create new scope
-        sc.flags &= ~SCOPE.ctfe; // temporary stop CTFE
+        sc.ctfe = false; // temporary stop CTFE
         sc.visibility = Visibility(Visibility.Kind.public_); // https://issues.dlang.org/show_bug.cgi?id=12506
 
         /* fd.treq might be incomplete type,
@@ -5822,7 +5821,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return;
             }
         }
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             /* See if need to rewrite the AST because of cast/call ambiguity
              */
@@ -6005,7 +6004,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 // Rewrite (*fp)(arguments) to fp(arguments)
                 exp.e1 = (cast(PtrExp)exp.e1).e1;
             }
-            else if (exp.e1.op == EXP.type && (sc && sc.flags & SCOPE.Cfile))
+            else if (exp.e1.op == EXP.type && (sc && sc.inCfile))
             {
                 const numArgs = exp.arguments ? exp.arguments.length : 0;
 
@@ -6622,7 +6621,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 if (exp.f.checkNestedReference(sc, exp.loc))
                     return setError();
             }
-            else if (sc.func && sc.intypeof != 1 && !(sc.flags & (SCOPE.ctfe | SCOPE.debug_)))
+            else if (sc.func && sc.intypeof != 1 && !(sc.ctfe || sc.debug_))
             {
                 bool err = false;
                 if (!tf.purity && sc.func.setImpure(exp.loc, "`pure` %s `%s` cannot call impure `%s`", exp.e1))
@@ -6886,7 +6885,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             VarDeclaration v = s.isVarDeclaration();
             if (v)
             {
-                if (sc.flags & SCOPE.Cfile)
+                if (sc.inCfile)
                 {
                     /* Do semantic() on the type before inserting v into the symbol table
                      */
@@ -6920,7 +6919,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
 
-            if (v && (sc.flags & SCOPE.Cfile))
+            if (v && sc.inCfile)
             {
                 /* Do semantic() on initializer last so this will be legal:
                  *      int a = a;
@@ -6958,7 +6957,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // The mangling change only works for D mangling
                 }
 
-                if (!(sc.flags & SCOPE.Cfile))
+                if (!sc.inCfile)
                 {
                     /* https://issues.dlang.org/show_bug.cgi?id=21272
                      * If we are in a foreach body we need to extract the
@@ -7096,7 +7095,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             // 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.flags & SCOPE.compile)
+            if (sc.traitsCompiles)
             {
                 genObjCode = false;
             }
@@ -7179,7 +7178,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         {
             printf("IsExp::semantic(%s)\n", e.toChars());
         }
-        if (e.id && !(sc.flags & SCOPE.condition))
+        if (e.id && !sc.condition)
         {
             error(e.loc, "can only declare type aliases within `static if` conditionals or `static assert`s");
             return setError();
@@ -7208,7 +7207,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Scope* sc2 = sc.copy(); // keep sc.flags
             sc2.tinst = null;
             sc2.minst = null;
-            sc2.flags |= SCOPE.fullinst;
+            sc2.fullinst = true;
             Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2);
             sc2.pop();
             if (!t) // errors, so condition is false
@@ -7723,29 +7722,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             const slice = se.peekString();
             message("file      %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
         }
-        if (global.params.moduleDeps.buffer !is null)
-        {
-            OutBuffer* ob = global.params.moduleDeps.buffer;
-            Module imod = sc._module;
 
-            if (!global.params.moduleDeps.name)
-                ob.writestring("depsFile ");
-            ob.writestring(imod.toPrettyChars());
-            ob.writestring(" (");
-            escapePath(ob, imod.srcfile.toChars());
-            ob.writestring(") : ");
-            if (global.params.moduleDeps.name)
-                ob.writestring("string : ");
-            ob.write(se.peekString());
-            ob.writestring(" (");
-            escapePath(ob, resolvedNamez.ptr);
-            ob.writestring(")");
-            ob.writenl();
-        }
-        if (global.params.makeDeps.doOutput)
-        {
-            global.params.makeDeps.files.push(resolvedNamez.ptr);
-        }
+        addImportExpDep(global.params.moduleDeps, global.params.makeDeps, resolvedNamez, se.peekString(), sc._module);
 
         {
             auto fileName = FileName(resolvedNamez);
@@ -8110,7 +8088,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             //printf("e1.op = %d, '%s'\n", e1.op, Token.toChars(e1.op));
         }
 
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             /* See if need to rewrite the AST because of cast/call ambiguity
              */
@@ -8503,7 +8481,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             /* Special handling for &"string"/&(T[]){0, 1}
              * since C regards string/array literals as lvalues
@@ -8743,7 +8721,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         result = e;
                         return;
                     }
-                    if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_))
+                    if (sc.func && !sc.intypeof && !sc.debug_)
                     {
                         sc.setUnsafe(false, exp.loc,
                             "`this` reference necessary to take address of member `%s` in `@safe` function `%s`",
@@ -8834,7 +8812,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             goto case Terror;
         }
 
-        if (sc.flags & SCOPE.Cfile && exp.type && exp.type.toBasetype().ty == Tvoid)
+        if (sc.inCfile && exp.type && exp.type.toBasetype().ty == Tvoid)
         {
             // https://issues.dlang.org/show_bug.cgi?id=23752
             // `&*((void*)(0))` is allowed in C
@@ -9005,7 +8983,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (checkNonAssignmentArrayOp(e.e1))
             return setError();
 
-        e.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+        e.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
         result = e;
     }
 
@@ -9084,7 +9062,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if ((sc && sc.flags & SCOPE.Cfile) &&
+        if ((sc && sc.inCfile) &&
             exp.to && (exp.to.ty == Tident || exp.to.ty == Tsarray) &&
             (exp.e1.op == EXP.address || exp.e1.op == EXP.star ||
              exp.e1.op == EXP.uadd || exp.e1.op == EXP.negate))
@@ -9338,7 +9316,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
 
-        if (sc && sc.flags & SCOPE.Cfile)
+        if (sc && sc.inCfile)
         {
             /* C11 6.5.4-5: A cast does not yield an lvalue.
              * So ensure that castTo does not strip away the cast so that this
@@ -9744,7 +9722,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         assert(!exp.type);
 
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             /* See if need to rewrite the AST because of cast/call ambiguity
              */
@@ -9842,7 +9820,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         e.type = e.e2.type;
         result = e;
 
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
             return;
 
         if (e.type is Type.tvoid)
@@ -10141,7 +10119,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // OR it in, because it might already be set for C array indexing
                     exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
                 }
-                else if (sc.flags & SCOPE.Cfile && t1b.ty == Tsarray)
+                else if (sc.inCfile && t1b.ty == Tsarray)
                 {
                     if (auto ve = exp.e1.isVarExp())
                     {
@@ -10172,7 +10150,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return;
         }
 
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             /* See if need to rewrite the AST because of cast/call ambiguity
              */
@@ -10348,7 +10326,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         if (auto e2comma = exp.e2.isCommaExp())
         {
-            if (!e2comma.isGenerated && !(sc.flags & SCOPE.Cfile))
+            if (!e2comma.isGenerated && !sc.inCfile)
                 error(exp.loc, "using the result of a comma expression is not allowed");
 
             /* Rewrite to get rid of the comma from rvalue
@@ -10493,7 +10471,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
                 e1x = e;
             }
-            else if (sc.flags & SCOPE.Cfile && e1x.isDotIdExp())
+            else if (sc.inCfile && e1x.isDotIdExp())
             {
                 auto die = e1x.isDotIdExp();
                 e1x = fieldLookup(die.e1, sc, die.ident, die.arrow);
@@ -11088,7 +11066,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
              * string to match the size of e1.
              */
             Type t2 = e2x.type.toBasetype();
-            if (sc.flags & SCOPE.Cfile && e2x.isStringExp() && t2.isTypeSArray())
+            if (sc.inCfile && e2x.isStringExp() && t2.isTypeSArray())
             {
                 uinteger_t dim1 = t1.isTypeSArray().dim.toInteger();
                 uinteger_t dim2 = t2.isTypeSArray().dim.toInteger();
@@ -13294,14 +13272,14 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         e1x = resolveProperties(sc, e1x);
         e1x = e1x.toBoolean(sc);
 
-        if (sc.flags & SCOPE.condition)
+        if (sc.condition)
         {
             /* If in static if, don't evaluate e2 if we don't have to.
              */
             e1x = e1x.optimize(WANTvalue);
             if (e1x.toBool().hasValue(exp.op == EXP.orOr))
             {
-                if (sc.flags & SCOPE.Cfile)
+                if (sc.inCfile)
                     result = new IntegerExp(exp.op == EXP.orOr);
                 else
                     result = IntegerExp.createBool(exp.op == EXP.orOr);
@@ -13349,7 +13327,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (e2x.type.ty == Tvoid)
             exp.type = Type.tvoid;
         else
-            exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+            exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
 
         exp.e1 = e1x;
         exp.e2 = e2x;
@@ -13446,7 +13424,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+        exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
 
         // Special handling for array comparisons
         Expression arrayLowering = null;
@@ -13741,7 +13719,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         if (f1 || f2)
             return setError();
 
-        exp.type = (sc && sc.flags & SCOPE.Cfile) ? Type.tint32 : Type.tbool;
+        exp.type = (sc && sc.inCfile) ? Type.tint32 : Type.tbool;
 
         if (!isArrayComparison)
         {
@@ -13957,7 +13935,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         // https://issues.dlang.org/show_bug.cgi?id=23767
         // `cast(void*) 0` should be treated as `null` so the ternary expression
         // gets the pointer type of the other branch
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
         {
             static void rewriteCNull(ref Expression e, ref Type t)
             {
@@ -14273,7 +14251,7 @@  private Expression dotIdSemanticPropX(DotIdExp exp, Scope* sc)
     if (Expression ex = unaSemantic(exp, sc))
         return ex;
 
-    if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
+    if (!sc.inCfile && exp.ident == Id._mangleof)
     {
         // symbol.mangleof
 
@@ -14409,7 +14387,7 @@  Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
 
     //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
 
-    const cfile = (sc.flags & SCOPE.Cfile) != 0;
+    const cfile = sc.inCfile;
 
     /* Special case: rewrite this.id and super.id
      * to be classtype.id and baseclasstype.id
@@ -14464,13 +14442,13 @@  Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
          */
         if (ie.sds.isModule() && ie.sds != sc._module)
             flags |= SearchOpt.ignorePrivateImports;
-        if (sc.flags & SCOPE.ignoresymbolvisibility)
+        if (sc.ignoresymbolvisibility)
             flags |= SearchOpt.ignoreVisibility;
         Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
         /* Check for visibility before resolving aliases because public
          * aliases to private symbols are public.
          */
-        if (s && !(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc._module, s))
+        if (s && !sc.ignoresymbolvisibility && !symbolIsVisible(sc._module, s))
         {
             s = null;
         }
@@ -15128,7 +15106,7 @@  bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
     if (global.params.noSharedAccess != FeatureState.enabled ||
         !sc ||
         sc.intypeof ||
-        sc.flags & SCOPE.ctfe)
+        sc.ctfe)
     {
         return false;
     }
@@ -15699,7 +15677,7 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
 
     Expression visitStructLiteral(StructLiteralExp _this)
     {
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
             return _this;  // C struct literals are lvalues
         else
             return visit(_this);
@@ -15746,7 +15724,7 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
         auto e1 = _this.e1;
         auto var = _this.var;
         //printf("DotVarExp::toLvalue(%s)\n", toChars());
-        if (sc && sc.flags & SCOPE.Cfile)
+        if (sc && sc.inCfile)
         {
             /* C11 6.5.2.3-3: A postfix expression followed by the '.' or '->' operator
              * is an lvalue if the first expression is an lvalue.
@@ -15792,7 +15770,7 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action
 
     Expression visitCast(CastExp _this)
     {
-        if (sc && sc.flags & SCOPE.Cfile)
+        if (sc && sc.inCfile)
         {
             /* C11 6.5.4-5: A cast does not yield an lvalue.
              */
@@ -16295,7 +16273,7 @@  bool checkAddressable(Expression e, Scope* sc)
                 continue;
 
             case EXP.variable:
-                if (sc.flags & SCOPE.Cfile)
+                if (sc.inCfile)
                 {
                     // C11 6.5.3.2: A variable that has its address taken cannot be
                     // stored in a register.
@@ -16597,7 +16575,7 @@  Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
         return ErrorExp.get();
     Expression e = new VarExp(loc, em);
     e = e.expressionSemantic(sc);
-    if (!(sc.flags & SCOPE.Cfile) && em.isCsymbol())
+    if (!sc.inCfile && em.isCsymbol())
     {
         /* C11 types them as int. But if in D file,
          * type qualified names as the enum
@@ -16638,7 +16616,7 @@  Expression toBoolean(Expression exp, Scope* sc)
         case EXP.construct:
         case EXP.blit:
         case EXP.loweredAssignExp:
-            if (sc.flags & SCOPE.Cfile)
+            if (sc.inCfile)
                 return exp;
             // Things like:
             //  if (a = b) ...
@@ -16777,7 +16755,7 @@  bool evalStaticCondition(Scope* sc, Expression original, Expression e, out bool
         const uint nerrors = global.errors;
 
         sc = sc.startCTFE();
-        sc.flags |= SCOPE.condition;
+        sc.condition = true;
 
         e = e.expressionSemantic(sc);
         e = resolveProperties(sc, e);
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 54ff82670ae..c815c589235 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -119,9 +119,8 @@  private struct FUNCFLAG
     bool safetyInprocess;    /// working on determining safety
     bool nothrowInprocess;   /// working on determining nothrow
     bool nogcInprocess;      /// working on determining @nogc
-    bool returnInprocess;    /// working on inferring 'return' for parameters
+    bool scopeInprocess;     /// infer `return` and `scope` for parameters
     bool inlineScanned;      /// function has been scanned for inline possibilities
-    bool inferScope;         /// infer 'scope' for parameters
     bool hasCatches;         /// function has try-catch statements
     bool skipCodegen;        /// do not generate code for this function.
     bool printf;             /// is a printf-like function
@@ -431,8 +430,7 @@  extern (C++) class FuncDeclaration : Declaration
     {
         //printf("FuncDeclaration::overloadInsert(s = %s) this = %s\n", s.toChars(), toChars());
         assert(s != this);
-        AliasDeclaration ad = s.isAliasDeclaration();
-        if (ad)
+        if (AliasDeclaration ad = s.isAliasDeclaration())
         {
             if (overnext)
                 return overnext.overloadInsert(ad);
@@ -501,8 +499,7 @@  extern (C++) class FuncDeclaration : Declaration
         while (f && f.overnext)
         {
             //printf("f.overnext = %p %s\n", f.overnext, f.overnext.toChars());
-            TemplateDeclaration td = f.overnext.isTemplateDeclaration();
-            if (td)
+            if (TemplateDeclaration td = f.overnext.isTemplateDeclaration())
                 return td;
             f = f.overnext.isFuncDeclaration();
         }
@@ -724,19 +721,16 @@  extern (C++) class FuncDeclaration : Declaration
         if (!tf.isnogc)
             nogcInprocess = true;
 
-        if (!isVirtual() || this.isIntroducing())
-            returnInprocess = true;
-
         // Initialize for inferring STC.scope_
-        inferScope = true;
+        scopeInprocess = true;
     }
 
-    extern (D) final uint flags()
+    extern (D) final uint saveFlags()
     {
         return bitFields;
     }
 
-    extern (D) final uint flags(uint f)
+    extern (D) final uint restoreFlags(uint f)
     {
         bitFields = f;
         return bitFields;
@@ -1262,8 +1256,7 @@  extern (C++) class FuncDeclaration : Declaration
     {
         if (type)
         {
-            TypeFunction fdtype = type.isTypeFunction();
-            if (fdtype) // Could also be TypeError
+            if (TypeFunction fdtype = type.isTypeFunction()) // Could also be TypeError
                 return fdtype.parameterList;
         }
 
@@ -1677,7 +1670,7 @@  extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
         this.fes = fes;
         // Always infer scope for function literals
         // See https://issues.dlang.org/show_bug.cgi?id=20362
-        this.inferScope = true;
+        this.scopeInprocess = true;
         //printf("FuncLiteralDeclaration() id = '%s', type = '%s'\n", this.ident.toChars(), type.toChars());
     }
 
@@ -1732,8 +1725,7 @@  extern (C++) final class FuncLiteralDeclaration : FuncDeclaration
     {
         if (parent)
         {
-            TemplateInstance ti = parent.isTemplateInstance();
-            if (ti)
+            if (TemplateInstance ti = parent.isTemplateInstance())
                 return ti.tempdecl.toPrettyChars(QualifyTypes);
         }
         return Dsymbol.toPrettyChars(QualifyTypes);
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index 594e481e469..5d76cea9374 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -214,11 +214,11 @@  void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
 
     //printf("function storage_class = x%llx, sc.stc = x%llx, %x\n", storage_class, sc.stc, Declaration.isFinal());
 
-    if (sc.flags & SCOPE.compile)
+    if (sc.traitsCompiles)
         funcdecl.skipCodegen = true;
 
     funcdecl._linkage = sc.linkage;
-    if (sc.flags & SCOPE.Cfile && funcdecl.isFuncLiteralDeclaration())
+    if (sc.inCfile && funcdecl.isFuncLiteralDeclaration())
         funcdecl._linkage = LINK.d; // so they are uniquely mangled
 
     if (auto fld = funcdecl.isFuncLiteralDeclaration())
@@ -263,7 +263,7 @@  void funcDeclarationSemantic(Scope* sc, FuncDeclaration funcdecl)
         return null;
     }
 
-    if (sc.flags & SCOPE.Cfile)
+    if (sc.inCfile)
     {
         /* C11 allows a function to be declared with a typedef, D does not.
          */
@@ -1047,8 +1047,7 @@  Ldone:
             }
 
             // If it's a member template
-            ClassDeclaration cd = ti.tempdecl.isClassMember();
-            if (cd)
+            if (ClassDeclaration cd = ti.tempdecl.isClassMember())
             {
                 .error(funcdecl.loc, "%s `%s` cannot use template to add virtual function to class `%s`", funcdecl.kind, funcdecl.toPrettyChars, cd.toChars());
             }
@@ -2182,7 +2181,7 @@  int getLevelAndCheck(FuncDeclaration fd, const ref Loc loc, Scope* sc, FuncDecla
     if (level != fd.LevelError)
         return level;
     // Don't give error if in template constraint
-    if (!(sc.flags & SCOPE.constraint))
+    if (!sc.inTemplateConstraint)
     {
         const(char)* xstatic = fd.isStatic() ? "`static` " : "";
         // better diagnostics for static functions
@@ -2291,7 +2290,7 @@  bool checkNestedReference(FuncDeclaration fd, Scope* sc, const ref Loc loc)
                 if (!found)
                 {
                     //printf("\tadding sibling %s to %s\n", fdthis.toPrettyChars(), toPrettyChars());
-                    if (!sc.intypeof && !(sc.flags & SCOPE.compile))
+                    if (!sc.intypeof && !sc.traitsCompiles)
                     {
                         fd.siblingCallers.push(fdthis);
                         fd.computedEscapingSiblings = false;
@@ -2777,7 +2776,7 @@  void modifyReturns(FuncLiteralDeclaration fld, Scope* sc, Type tret)
  */
 bool isRootTraitsCompilesScope(Scope* sc)
 {
-    return (sc.flags & SCOPE.compile) && !(sc.func.flags & SCOPE.compile);
+    return (sc.traitsCompiles) && !sc.func.skipCodegen;
 }
 
 /**************************************
@@ -2801,7 +2800,7 @@  bool setUnsafe(Scope* sc,
     if (sc.intypeof)
         return false; // typeof(cast(int*)0) is safe
 
-    if (sc.flags & SCOPE.debug_) // debug {} scopes are permissive
+    if (sc.debug_) // debug {} scopes are permissive
         return false;
 
     if (!sc.func)
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index c97aeb6d4d0..2bdc1856e18 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -248,6 +248,11 @@  extern (C++) struct Param
     const(char)[] exefile;
     const(char)[] mapfile;
 
+    // Time tracing
+    bool timeTrace = false; /// Whether profiling of compile time is enabled
+    uint timeTraceGranularityUs = 500; /// In microseconds, minimum event size to report
+    const(char)* timeTraceFile; /// File path of output file
+
     ///
     bool parsingUnittestsRequired()
     {
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index bd28d7be7b8..e2aa82a15ae 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -250,6 +250,9 @@  struct Param
     DString resfile;
     DString exefile;
     DString mapfile;
+    bool timeTrace;
+    uint32_t timeTraceGranularityUs;
+    const char* timeTraceFile;
 };
 
 struct structalign_t
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index a44fb2877a9..7f2b225931b 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -2682,10 +2682,7 @@  private void expressionPrettyPrint(Expression e, ref OutBuffer buf, ref HdrGenSt
     void visitDotId(DotIdExp e)
     {
         expToBuffer(e.e1, PREC.primary, buf, hgs);
-        if (e.arrow)
-            buf.writestring("->");
-        else
-            buf.writeByte('.');
+        buf.writeByte('.');
         buf.writestring(e.ident.toString());
     }
 
@@ -3927,7 +3924,7 @@  private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
 
     /* Use 'storage class' (prefix) style for attributes
      */
-    if (t.mod)
+    if (t.mod && !(hgs.ddoc || hgs.hdrgen))
     {
         MODtoBuffer(buf, t.mod);
         buf.writeByte(' ');
@@ -3977,6 +3974,12 @@  private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
         buf.writeByte(')');
     }
     parametersToBuffer(t.parameterList, buf, hgs);
+    // postfix this attributes are more readable
+    if (t.mod && (hgs.ddoc || hgs.hdrgen))
+    {
+        buf.writeByte(' ');
+        MODtoBuffer(buf, t.mod);
+    }
     if (t.isreturnscope && !t.isreturninferred)
     {
         buf.writestring(" return scope");
@@ -4273,13 +4276,23 @@  private void typeToBufferx(Type t, ref OutBuffer buf, ref HdrGenState hgs)
 
     void visitTag(TypeTag t)
     {
-        if (t.mod & MODFlags.const_)
-            buf.writestring("const ");
         if (hgs.importcHdr && t.id)
         {
+            // https://issues.dlang.org/show_bug.cgi?id=24670
+            // `const` must be parenthesized because it can be a return type
+            if (t.mod & MODFlags.const_)
+                buf.writestring("const(");
+
+            // For C to D translation, `struct S` or `enum S` simply becomes `S`
             buf.writestring(t.id.toString());
+
+            if (t.mod & MODFlags.const_)
+                buf.writestring(")");
             return;
         }
+        // The following produces something like "const enum E : short"
+        if (t.mod & MODFlags.const_)
+            buf.writestring("const ");
         buf.writestring(Token.toString(t.tok));
         buf.writeByte(' ');
         if (t.id)
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index ece56c8d1bc..0413df03b5a 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -41,7 +41,7 @@  import dmd.typesem;
  */
 Type cAdjustParamType(Type t, Scope* sc)
 {
-    if (!(sc.flags & SCOPE.Cfile))
+    if (!sc.inCfile)
         return t;
 
     Type tb = t.toBasetype();
@@ -77,7 +77,7 @@  Type cAdjustParamType(Type t, Scope* sc)
 Expression arrayFuncConv(Expression e, Scope* sc)
 {
     //printf("arrayFuncConv() %s\n", e.toChars());
-    if (!(sc.flags & SCOPE.Cfile))
+    if (!sc.inCfile)
         return e;
 
     auto t = e.type.toBasetype();
@@ -121,7 +121,6 @@  Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
     if (e.isErrorExp())
         return e;
 
-    Dsymbol s;
     auto t = e.type;
     if (t.isTypePointer())
     {
@@ -131,6 +130,7 @@  Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
             error(e.loc, "since `%s` is a pointer, use `%s->%s` instead of `%s.%s`", pe, pe, id.toChars(), pe, id.toChars());
         e = new PtrExp(e.loc, e);
     }
+    Dsymbol s;
     if (auto ts = t.isTypeStruct())
         s = ts.sym.search(e.loc, id, 0);
     if (!s)
@@ -154,7 +154,7 @@  Expression fieldLookup(Expression e, Scope* sc, Identifier id, bool arrow)
  */
 Expression carraySemantic(ArrayExp ae, Scope* sc)
 {
-    if (!(sc.flags & SCOPE.Cfile))
+    if (!sc.inCfile)
         return null;
 
     auto e1 = ae.e1.expressionSemantic(sc);
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 8faad30f539..f48b3c69c67 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -161,7 +161,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
                 // Convert initializer to Expression `ex`
                 auto tm = fieldType.addMod(t.mod);
                 auto iz = i.value[j].initializerSemantic(sc, tm, needInterpret);
-                auto ex = iz.initializerToExpression(null, (sc.flags & SCOPE.Cfile) != 0);
+                auto ex = iz.initializerToExpression(null, sc.inCfile);
                 if (ex.op != EXP.error)
                     i.value[j] = iz;
                 return ex;
@@ -305,7 +305,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
         }
         if (auto tsa = t.isTypeSArray())
         {
-            if (sc.flags & SCOPE.Cfile && tsa.isIncomplete())
+            if (sc.inCfile && tsa.isIncomplete())
             {
                 // Change to array of known length
                 auto tn = tsa.next.toBasetype();
@@ -369,7 +369,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
             // If the result will be implicitly cast, move the cast into CTFE
             // to avoid premature truncation of polysemous types.
             // eg real [] x = [1.1, 2.2]; should use real precision.
-            if (i.exp.implicitConvTo(t) && !(sc.flags & SCOPE.Cfile))
+            if (i.exp.implicitConvTo(t) && !sc.inCfile)
             {
                 i.exp = i.exp.implicitCastTo(sc, t);
             }
@@ -377,7 +377,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
             {
                 return i;
             }
-            if (sc.flags & SCOPE.Cfile)
+            if (sc.inCfile)
             {
                 /* the interpreter turns (char*)"string" into &"string"[0] which then
                  * it cannot interpret. Resolve that case by doing optimize() first
@@ -450,7 +450,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
             /* Lop off terminating 0 of initializer for:
              *  static char s[5] = "hello";
              */
-            if (sc.flags & SCOPE.Cfile &&
+            if (sc.inCfile &&
                 typeb.ty == Tsarray &&
                 tynto.isSomeChar &&
                 tb.isTypeSArray().dim.toInteger() + 1 == typeb.isTypeSArray().dim.toInteger())
@@ -463,7 +463,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
          * Initialize an array of unknown size with a string.
          * Change to static array of known size
          */
-        if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+        if (sc.inCfile && i.exp.isStringExp() &&
             tb.isTypeSArray() && tb.isTypeSArray().isIncomplete())
         {
             StringExp se = i.exp.isStringExp();
@@ -549,7 +549,7 @@  Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedIn
         {
             i.exp = i.exp.implicitCastTo(sc, t);
         }
-        else if (sc.flags & SCOPE.Cfile && i.exp.isStringExp() &&
+        else if (sc.inCfile && i.exp.isStringExp() &&
             tta && (tta.next.ty == Tint8 || tta.next.ty == Tuns8) &&
             ti.ty == Tsarray && ti.nextOf().ty == Tchar)
         {
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 26a56c2b1fd..2a11f308017 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -499,7 +499,7 @@  class Lexer
                     clexerCharConstant(*t, c);
                     return;
                 }
-                else if (p[1] == '\"')  // C wide string literal
+                if (p[1] == '\"')  // C wide string literal
                 {
                     const c = *p;
                     ++p;
@@ -509,7 +509,7 @@  class Lexer
                                 'd';
                     return;
                 }
-                else if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal
+                if (p[1] == '8' && p[2] == '\"') // C UTF-8 string literal
                 {
                     p += 2;
                     escapeStringConstant(t);
@@ -542,14 +542,13 @@  class Lexer
                     delimitedStringConstant(t);
                     return;
                 }
-                else if (p[1] == '{')
+                if (p[1] == '{')
                 {
                     p++;
                     tokenStringConstant(t);
                     return;
                 }
-                else
-                    goto case_ident;
+                goto case_ident;
             case 'i':
                 if (Ccompile)
                     goto case_ident;
@@ -559,20 +558,19 @@  class Lexer
                     escapeStringConstant(t, true);
                     return;
                 }
-                else if (p[1] == '`')
+                if (p[1] == '`')
                 {
                     p++; // skip the i
                     wysiwygStringConstant(t, true);
                     return;
                 }
-                else if (p[1] == 'q' && p[2] == '{')
+                if (p[1] == 'q' && p[2] == '{')
                 {
                     p += 2; // skip the i and q
                     tokenStringConstant(t, true);
                     return;
                 }
-                else
-                    goto case_ident;
+                goto case_ident;
             case '"':
                 escapeStringConstant(t);
                 return;
@@ -894,7 +892,7 @@  class Lexer
                         t.value = TOK.comment;
                         return;
                     }
-                    else if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr)
+                    if (doDocComment && t.ptr[2] == '*' && p - 4 != t.ptr)
                     {
                         // if /** but not /**/
                         getDocComment(t, lastLine == startLoc.linnum, startLoc.linnum - lastDocLine > 1);
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 6a2d349f15b..41a645e8b9f 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -21,7 +21,6 @@  import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
-import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.denum;
@@ -58,6 +57,11 @@  static if (__VERSION__ < 2095)
     private alias StringValueType = StringValue!Type;
 }
 
+private auto X(T, U)(T m, U n)
+{
+    return (m << 4) | n;
+}
+
 /***************************
  * Return !=0 if modfrom can be implicitly converted to modto
  */
@@ -67,10 +71,6 @@  bool MODimplicitConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
         return true;
 
     //printf("MODimplicitConv(from = %x, to = %x)\n", modfrom, modto);
-    auto X(T, U)(T m, U n)
-    {
-        return ((m << 4) | n);
-    }
 
     switch (X(modfrom & ~MODFlags.shared_, modto & ~MODFlags.shared_))
     {
@@ -98,11 +98,6 @@  MATCH MODmethodConv(MOD modfrom, MOD modto) pure nothrow @nogc @safe
     if (MODimplicitConv(modfrom, modto))
         return MATCH.constant;
 
-    auto X(T, U)(T m, U n)
-    {
-        return ((m << 4) | n);
-    }
-
     switch (X(modfrom, modto))
     {
     case X(0, MODFlags.wild):
@@ -682,7 +677,7 @@  extern (C++) abstract class Type : ASTNode
         return false;
     }
 
-    bool isscope()
+    bool isScopeClass()
     {
         return false;
     }
@@ -1282,24 +1277,6 @@  extern (C++) abstract class Type : ASTNode
         return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
     }
 
-    /*******************************
-     * Determine if converting 'this' to 'to' is an identity operation,
-     * a conversion to const operation, or the types aren't the same.
-     * Returns:
-     *      MATCH.exact      'this' == 'to'
-     *      MATCH.constant      'to' is const
-     *      MATCH.nomatch    conversion to mutable or invariant
-     */
-    MATCH constConv(Type to)
-    {
-        //printf("Type::constConv(this = %s, to = %s)\n", toChars(), to.toChars());
-        if (equals(to))
-            return MATCH.exact;
-        if (ty == to.ty && MODimplicitConv(mod, to.mod))
-            return MATCH.constant;
-        return MATCH.nomatch;
-    }
-
     /***************************************
      * Compute MOD bits matching `this` argument type to wild parameter type.
      * Params:
@@ -1362,12 +1339,6 @@  extern (C++) abstract class Type : ASTNode
         return defaultInit(this, loc);
     }
 
-    // if initializer is 0
-    bool isZeroInit(const ref Loc loc)
-    {
-        return false; // assume not
-    }
-
     /***************************************
      * Return !=0 if the type or any of its subtypes is wild.
      */
@@ -1866,35 +1837,6 @@  extern (C++) abstract class TypeNext : Type
         return t;
     }
 
-    override MATCH constConv(Type to)
-    {
-        //printf("TypeNext::constConv from = %s, to = %s\n", toChars(), to.toChars());
-        if (equals(to))
-            return MATCH.exact;
-
-        if (!(ty == to.ty && MODimplicitConv(mod, to.mod)))
-            return MATCH.nomatch;
-
-        Type tn = to.nextOf();
-        if (!(tn && next.ty == tn.ty))
-            return MATCH.nomatch;
-
-        MATCH m;
-        if (to.isConst()) // whole tail const conversion
-        {
-            // Recursive shared level check
-            m = next.constConv(tn);
-            if (m == MATCH.exact)
-                m = MATCH.constant;
-        }
-        else
-        {
-            //printf("\tnext => %s, to.next => %s\n", next.toChars(), tn.toChars());
-            m = next.equals(tn) ? MATCH.constant : MATCH.nomatch;
-        }
-        return m;
-    }
-
     override final MOD deduceWild(Type t, bool isRef)
     {
         if (ty == Tfunction)
@@ -2125,28 +2067,6 @@  extern (C++) final class TypeBasic : Type
         return (flags & TFlags.unsigned) != 0;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        switch (ty)
-        {
-        case Tchar:
-        case Twchar:
-        case Tdchar:
-        case Timaginary32:
-        case Timaginary64:
-        case Timaginary80:
-        case Tfloat32:
-        case Tfloat64:
-        case Tfloat80:
-        case Tcomplex32:
-        case Tcomplex64:
-        case Tcomplex80:
-            return false; // no
-        default:
-            return true; // yes
-        }
-    }
-
     override bool hasUnsafeBitpatterns()
     {
         return ty == Tbool;
@@ -2246,11 +2166,6 @@  extern (C++) final class TypeVector : Type
         return tb;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return basetype.isZeroInit(loc);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2327,26 +2242,11 @@  extern (C++) final class TypeSArray : TypeArray
         return nty.isSomeChar;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return next.isZeroInit(loc);
-    }
-
     override structalign_t alignment()
     {
         return next.alignment();
     }
 
-    override MATCH constConv(Type to)
-    {
-        if (auto tsa = to.isTypeSArray())
-        {
-            if (!dim.equals(tsa.dim))
-                return MATCH.nomatch;
-        }
-        return TypeNext.constConv(to);
-    }
-
     override Expression defaultInitLiteral(const ref Loc loc)
     {
         static if (LOGDEFAULTINIT)
@@ -2445,11 +2345,6 @@  extern (C++) final class TypeDArray : TypeArray
         return nty.isSomeChar;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
     override bool isBoolean()
     {
         return true;
@@ -2496,28 +2391,11 @@  extern (C++) final class TypeAArray : TypeArray
         return result;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
     override bool isBoolean()
     {
         return true;
     }
 
-    override MATCH constConv(Type to)
-    {
-        if (auto taa = to.isTypeAArray())
-        {
-            MATCH mindex = index.constConv(taa.index);
-            MATCH mkey = next.constConv(taa.next);
-            // Pick the worst match
-            return mkey < mindex ? mkey : mindex;
-        }
-        return Type.constConv(to);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2554,28 +2432,11 @@  extern (C++) final class TypePointer : TypeNext
         return result;
     }
 
-    override MATCH constConv(Type to)
-    {
-        if (next.ty == Tfunction)
-        {
-            if (to.nextOf() && next.equals((cast(TypeNext)to).next))
-                return Type.constConv(to);
-            else
-                return MATCH.nomatch;
-        }
-        return TypeNext.constConv(to);
-    }
-
     override bool isscalar()
     {
         return true;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2608,11 +2469,6 @@  extern (C++) final class TypeReference : TypeNext
         return result;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2868,16 +2724,6 @@  extern (C++) final class TypeFunction : TypeNext
         return newArgs;
     }
 
-    /** Extends TypeNext.constConv by also checking for matching attributes **/
-    override MATCH constConv(Type to)
-    {
-        // Attributes need to match exactly, otherwise it's an implicit conversion
-        if (this.ty != to.ty || !this.attributesEqual(cast(TypeFunction) to))
-            return MATCH.nomatch;
-
-        return super.constConv(to);
-    }
-
     extern (D) bool checkRetType(const ref Loc loc)
     {
         Type tb = next.toBasetype();
@@ -2994,11 +2840,6 @@  extern (C++) final class TypeDelegate : TypeNext
         return target.ptrsize;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
     override bool isBoolean()
     {
         return true;
@@ -3392,13 +3233,6 @@  extern (C++) final class TypeStruct : Type
         return structinit;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        // Determine zeroInit here, as this can be called before semantic2
-        sym.determineSize(sym.loc);
-        return sym.zeroInit;
-    }
-
     override bool isAssignable()
     {
         bool assignable = true;
@@ -3493,77 +3327,6 @@  extern (C++) final class TypeStruct : Type
         return sym.hasInvariant() || sym.hasFieldWithInvariant;
     }
 
-    extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
-    {
-        //printf("TypeStruct::implicitConvToWithoutAliasThis(%s => %s)\n", toChars(), to.toChars());
-
-        auto tos = to.isTypeStruct();
-        if (!(tos && sym == tos.sym))
-            return MATCH.nomatch;
-
-        if (mod == to.mod)
-            return MATCH.exact;
-
-        if (MODimplicitConv(mod, to.mod))
-            return MATCH.constant;
-
-        /* Check all the fields. If they can all be converted,
-         * allow the conversion.
-         */
-        MATCH m = MATCH.constant;
-        uint offset = ~0; // must never match a field offset
-        foreach (v; sym.fields[])
-        {
-            /* Why are we only looking at the first member of a union?
-             * The check should check for overlap of v with the previous field,
-             * not just starting at the same point
-             */
-            if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field
-                continue;       // ignore
-
-            Type tvf = v.type.addMod(mod);    // from type
-            Type tvt  = v.type.addMod(to.mod); // to type
-
-            // field match
-            MATCH mf = tvf.implicitConvTo(tvt);
-            //printf("\t%s => %s, match = %d\n", v.type.toChars(), tvt.toChars(), mf);
-
-            if (mf == MATCH.nomatch)
-                return MATCH.nomatch;
-            if (mf < m) // if field match is worse
-                m = mf;
-            offset = v.offset;
-        }
-        return m;
-    }
-
-    extern (D) MATCH implicitConvToThroughAliasThis(Type to)
-    {
-        auto tos = to.isTypeStruct();
-        if (!(tos && sym == tos.sym) &&
-            sym.aliasthis &&
-            !(att & AliasThisRec.tracing))
-        {
-            if (auto ato = aliasthisOf(this))
-            {
-                att = cast(AliasThisRec)(att | AliasThisRec.tracing);
-                MATCH m = ato.implicitConvTo(to);
-                att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
-                return m;
-            }
-        }
-        return MATCH.nomatch;
-    }
-
-    override MATCH constConv(Type to)
-    {
-        if (equals(to))
-            return MATCH.exact;
-        if (ty == to.ty && sym == (cast(TypeStruct)to).sym && MODimplicitConv(mod, to.mod))
-            return MATCH.constant;
-        return MATCH.nomatch;
-    }
-
     override MOD deduceWild(Type t, bool isRef)
     {
         if (ty == t.ty && sym == (cast(TypeStruct)t).sym)
@@ -3690,15 +3453,6 @@  extern (C++) final class TypeEnum : Type
         return memType().needsNested();
     }
 
-    override MATCH constConv(Type to)
-    {
-        if (equals(to))
-            return MATCH.exact;
-        if (ty == to.ty && sym == (cast(TypeEnum)to).sym && MODimplicitConv(mod, to.mod))
-            return MATCH.constant;
-        return MATCH.nomatch;
-    }
-
     extern (D) Type toBasetype2()
     {
         if (!sym.members && !sym.memtype)
@@ -3707,11 +3461,6 @@  extern (C++) final class TypeEnum : Type
         return tb.castMod(mod);         // retain modifier bits from 'this'
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return sym.getDefaultValue(loc).toBool().hasValue(false);
-    }
-
     override bool hasVoidInitPointers()
     {
         return memType().hasVoidInitPointers();
@@ -3767,58 +3516,6 @@  extern (C++) final class TypeClass : Type
         return sym;
     }
 
-    extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
-    {
-        ClassDeclaration cdto = to.isClassHandle();
-        MATCH m = constConv(to);
-        if (m > MATCH.nomatch)
-            return m;
-
-        if (cdto && cdto.isBaseOf(sym, null) && MODimplicitConv(mod, to.mod))
-        {
-            //printf("'to' is base\n");
-            return MATCH.convert;
-        }
-        return MATCH.nomatch;
-    }
-
-    extern (D) MATCH implicitConvToThroughAliasThis(Type to)
-    {
-        MATCH m;
-        if (sym.aliasthis && !(att & AliasThisRec.tracing))
-        {
-            if (auto ato = aliasthisOf(this))
-            {
-                att = cast(AliasThisRec)(att | AliasThisRec.tracing);
-                m = ato.implicitConvTo(to);
-                att = cast(AliasThisRec)(att & ~AliasThisRec.tracing);
-            }
-        }
-        return m;
-    }
-
-    override MATCH constConv(Type to)
-    {
-        if (equals(to))
-            return MATCH.exact;
-        if (ty == to.ty && sym == (cast(TypeClass)to).sym && MODimplicitConv(mod, to.mod))
-            return MATCH.constant;
-
-        /* Conversion derived to const(base)
-         */
-        int offset = 0;
-        if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
-        {
-            // Disallow:
-            //  derived to base
-            //  inout(derived) to inout(base)
-            if (!to.isMutable() && !to.isWild())
-                return MATCH.convert;
-        }
-
-        return MATCH.nomatch;
-    }
-
     override MOD deduceWild(Type t, bool isRef)
     {
         ClassDeclaration cd = t.isClassHandle();
@@ -3840,12 +3537,7 @@  extern (C++) final class TypeClass : Type
         return wm;
     }
 
-    override bool isZeroInit(const ref Loc loc)
-    {
-        return true;
-    }
-
-    override bool isscope()
+    override bool isScopeClass()
     {
         return sym.stack;
     }
@@ -4088,12 +3780,6 @@  extern (C++) final class TypeNoreturn : Type
         return this;
     }
 
-    override MATCH constConv(Type to)
-    {
-        // Either another noreturn or conversion to any type
-        return this.implicitConvTo(to);
-    }
-
     override bool isBoolean()
     {
         return true;  // bottom type can be implicitly converted to any other type
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 11c27c67aba..2ec4beeb6eb 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -239,7 +239,7 @@  public:
     virtual bool iscomplex();
     virtual bool isscalar();
     virtual bool isunsigned();
-    virtual bool isscope();
+    virtual bool isScopeClass();
     virtual bool isString();
     virtual bool isAssignable();
     virtual bool isBoolean();
@@ -264,13 +264,11 @@  public:
     virtual Type *makeSharedWildConst();
     virtual Type *makeMutable();
     Type *toBasetype();
-    virtual MATCH constConv(Type *to);
     virtual unsigned char deduceWild(Type *t, bool isRef);
 
     virtual ClassDeclaration *isClassHandle();
     virtual structalign_t alignment();
     virtual Expression *defaultInitLiteral(const Loc &loc);
-    virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
     virtual int hasWild() const;
     virtual bool hasVoidInitPointers();
     virtual bool hasUnsafeBitpatterns();
@@ -340,7 +338,6 @@  public:
     Type *makeSharedWild() override final;
     Type *makeSharedWildConst() override final;
     Type *makeMutable() override final;
-    MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override final;
     void transitive();
     void accept(Visitor *v) override { v->visit(this); }
@@ -362,7 +359,6 @@  public:
     bool iscomplex() override;
     bool isscalar() override;
     bool isunsigned() override;
-    bool isZeroInit(const Loc &loc) override;
 
     // For eliminating dynamic_cast
     TypeBasic *isTypeBasic() override;
@@ -385,7 +381,6 @@  public:
     bool isBoolean() override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     TypeBasic *elementType();
-    bool isZeroInit(const Loc &loc) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -407,9 +402,7 @@  public:
     bool isIncomplete();
     unsigned alignsize() override;
     bool isString() override;
-    bool isZeroInit(const Loc &loc) override;
     structalign_t alignment() override;
-    MATCH constConv(Type *to) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     bool hasUnsafeBitpatterns() override;
     bool hasVoidInitPointers() override;
@@ -429,7 +422,6 @@  public:
     TypeDArray *syntaxCopy() override;
     unsigned alignsize() override;
     bool isString() override;
-    bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -444,9 +436,7 @@  public:
     static TypeAArray *create(Type *t, Type *index);
     const char *kind() override;
     TypeAArray *syntaxCopy() override;
-    bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
-    MATCH constConv(Type *to) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -457,9 +447,7 @@  public:
     static TypePointer *create(Type *t);
     const char *kind() override;
     TypePointer *syntaxCopy() override;
-    MATCH constConv(Type *to) override;
     bool isscalar() override;
-    bool isZeroInit(const Loc &loc) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -469,7 +457,6 @@  class TypeReference final : public TypeNext
 public:
     const char *kind() override;
     TypeReference *syntaxCopy() override;
-    bool isZeroInit(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -557,7 +544,6 @@  public:
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
 
-    MATCH constConv(Type *to) override;
 
     bool isnothrow() const;
     void isnothrow(bool v);
@@ -599,7 +585,6 @@  public:
     const char *kind() override;
     TypeDelegate *syntaxCopy() override;
     unsigned alignsize() override;
-    bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -709,7 +694,6 @@  public:
     TypeStruct *syntaxCopy() override;
     structalign_t alignment() override;
     Expression *defaultInitLiteral(const Loc &loc) override;
-    bool isZeroInit(const Loc &loc) override;
     bool isAssignable() override;
     bool isBoolean() override;
     bool needsDestruction() override;
@@ -718,7 +702,6 @@  public:
     bool hasVoidInitPointers() override;
     bool hasUnsafeBitpatterns() override;
     bool hasInvariant() override;
-    MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -746,8 +729,6 @@  public:
     bool needsDestruction() override;
     bool needsCopyOrPostblit() override;
     bool needsNested() override;
-    MATCH constConv(Type *to) override;
-    bool isZeroInit(const Loc &loc) override;
     bool hasVoidInitPointers() override;
     bool hasUnsafeBitpatterns() override;
     bool hasInvariant() override;
@@ -766,10 +747,8 @@  public:
     const char *kind() override;
     TypeClass *syntaxCopy() override;
     ClassDeclaration *isClassHandle() override;
-    MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override;
-    bool isZeroInit(const Loc &loc) override;
-    bool isscope() override;
+    bool isScopeClass() override;
     bool isBoolean() override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -820,7 +799,6 @@  class TypeNoreturn final : public Type
 public:
     const char *kind() override;
     TypeNoreturn *syntaxCopy() override;
-    MATCH constConv(Type* to) override;
     bool isBoolean() override;
     unsigned alignsize() override;
 
@@ -847,6 +825,7 @@  namespace dmd
     bool equivalent(Type *src, Type *t);
     Covariant covariant(Type *, Type *, StorageClass * = nullptr, bool = false);
     bool isBaseOf(Type *tthis, Type *t, int *poffset);
+    bool isZeroInit(Type *t, const Loc &loc = Loc());
     Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
     Type *pointerTo(Type *type);
     Type *referenceTo(Type *type);
@@ -873,4 +852,5 @@  namespace dmd
     uinteger_t size(Type *type);
     uinteger_t size(Type *type, const Loc &loc);
     MATCH implicitConvTo(Type* from, Type* to);
+    MATCH constConv(Type* from, Type* to);
 }
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index 9e45e4549ff..02f47f8ac4b 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -201,7 +201,7 @@  public:
 
 Expression checkGC(Scope* sc, Expression e)
 {
-    if (sc.flags & SCOPE.ctfeBlock)     // ignore GC in ctfe blocks
+    if (sc.ctfeBlock)     // ignore GC in ctfe blocks
         return e;
 
     /* If betterC, allow GC to happen in non-CTFE code.
@@ -211,10 +211,10 @@  Expression checkGC(Scope* sc, Expression e)
     const betterC = !global.params.useGC;
     FuncDeclaration f = sc.func;
     if (e && e.op != EXP.error && f && sc.intypeof != 1 &&
-           (!(sc.flags & SCOPE.ctfe) || betterC) &&
+           (!sc.ctfe || betterC) &&
            (f.type.ty == Tfunction &&
             (cast(TypeFunction)f.type).isnogc || f.nogcInprocess || global.params.v.gc) &&
-           !(sc.flags & SCOPE.debug_))
+           !sc.debug_)
     {
         scope NOGCVisitor gcv = new NOGCVisitor(f);
         gcv.checkOnly = betterC;
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 756caf870bc..ed732332380 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -2001,7 +2001,7 @@  void escapeLive(Expression e, scope void delegate(VarDeclaration) onVar)
         true,
     );
 
-    escapeByValue(e, er, true);
+    escapeByValue(e, er);
 }
 
 /***************************************
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 0d32d7d9713..22fbbc4fb83 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -564,8 +564,7 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
         {
             //printf("CastExp::op_overload() (%s)\n", e.toChars());
             Expression result;
-            AggregateDeclaration ad = isAggregate(e.e1.type);
-            if (ad)
+            if (AggregateDeclaration ad = isAggregate(e.e1.type))
             {
                 Dsymbol fd = null;
                 /* Rewrite as:
@@ -1034,7 +1033,7 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 e.e2 = new DotIdExp(e.loc, e.e2, Id._tupleof);
 
                 auto sc2 = sc.push();
-                sc2.flags |= SCOPE.noaccesscheck;
+                sc2.noAccessCheck = true;
                 Expression r = e.expressionSemantic(sc2);
                 sc2.pop();
                 return r;
@@ -1412,8 +1411,7 @@  Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expres
 {
     assert(d);
     Expression e;
-    Declaration decl = d.isDeclaration();
-    if (decl)
+    if (Declaration decl = d.isDeclaration())
         e = new DotVarExp(loc, ethis, decl, false);
     else
         e = new DotIdExp(loc, ethis, d.ident);
@@ -1427,8 +1425,7 @@  Expression build_overload(const ref Loc loc, Scope* sc, Expression ethis, Expres
  */
 Dsymbol search_function(ScopeDsymbol ad, Identifier funcid)
 {
-    Dsymbol s = ad.search(Loc.initial, funcid);
-    if (s)
+    if (Dsymbol s = ad.search(Loc.initial, funcid))
     {
         //printf("search_function: s = '%s'\n", s.kind());
         Dsymbol s2 = s.toAlias();
@@ -1436,8 +1433,7 @@  Dsymbol search_function(ScopeDsymbol ad, Identifier funcid)
         FuncDeclaration fd = s2.isFuncDeclaration();
         if (fd && fd.type.ty == Tfunction)
             return fd;
-        TemplateDeclaration td = s2.isTemplateDeclaration();
-        if (td)
+        if (TemplateDeclaration td = s2.isTemplateDeclaration())
             return td;
     }
     return null;
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index 1fbe0ae3609..fb9a18b2892 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -591,13 +591,13 @@  nothrow:
     /***************************
      * Free returned value with FileName::free()
      */
-    extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext)
+    extern (C++) static const(char)* defaultExt(const(char)* name, const(char)* ext) pure
     {
         return defaultExt(name.toDString, ext.toDString).ptr;
     }
 
     /// Ditto
-    extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext)
+    extern (D) static const(char)[] defaultExt(const char[] name, const char[] ext) pure
     {
         auto e = FileName.ext(name);
         if (e.length) // it already has an extension
@@ -615,13 +615,13 @@  nothrow:
     /***************************
      * Free returned value with FileName::free()
      */
-    extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext)
+    extern (C++) static const(char)* forceExt(const(char)* name, const(char)* ext) pure
     {
         return forceExt(name.toDString, ext.toDString).ptr;
     }
 
     /// Ditto
-    extern (D) static const(char)[] forceExt(const char[] name, const char[] ext)
+    extern (D) static const(char)[] forceExt(const char[] name, const char[] ext) pure
     {
         if (auto e = FileName.ext(name))
             return addExt(name[0 .. $ - e.length - 1], ext);
diff --git a/gcc/d/dmd/root/rmem.d b/gcc/d/dmd/root/rmem.d
index c6986c0b56f..8eaf6094f52 100644
--- a/gcc/d/dmd/root/rmem.d
+++ b/gcc/d/dmd/root/rmem.d
@@ -149,6 +149,7 @@  enum CHUNK_SIZE = (256 * 4096 - 64);
 
 __gshared size_t heapleft = 0;
 __gshared void* heapp;
+__gshared size_t heapTotal = 0; // Total amount of memory allocated using malloc
 
 extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc
 {
@@ -167,11 +168,13 @@  extern (D) void* allocmemoryNoFree(size_t m_size) nothrow @nogc
 
     if (m_size > CHUNK_SIZE)
     {
+        heapTotal += m_size;
         return Mem.check(malloc(m_size));
     }
 
     heapleft = CHUNK_SIZE;
     heapp = Mem.check(malloc(CHUNK_SIZE));
+    heapTotal += CHUNK_SIZE;
     goto L1;
 }
 
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index f1bd6c98c80..b0eb3d1abfa 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -128,8 +128,8 @@  bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
 
         if (hasPointers && v.type.toBasetype().ty != Tstruct)
         {
-            if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize ||
-                 (v.offset & (target.ptrsize - 1))))
+            if ((!ad.type.alignment.isDefault() && ad.type.alignment.get() < target.ptrsize) ||
+                 (v.offset & (target.ptrsize - 1)))
             {
                 if (sc.setUnsafe(!printmsg, e.loc,
                     "field `%s.%s` cannot modify misaligned pointers in `@safe` code", ad, v))
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index f36a14ba051..7983a7ac93f 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -40,33 +40,15 @@  enum class CSX : uint16_t
     halt       = 0x20,   // assert(0)
 };
 
-enum class SCOPE
+enum class Contract : uint8_t
 {
-    // Flags that would not be inherited beyond scope nesting
-    ctor          = 0x0001,  // constructor type
-    noaccesscheck = 0x0002,  // don't do access checks
-    condition     = 0x0004,  // inside static if/assert condition
-    debug_        = 0x0008,  // inside debug conditional
-
-    // Flags that would be inherited beyond scope nesting
-    constraint    = 0x0010,  // inside template constraint
-    invariant_    = 0x0020,  // inside invariant code
-    require       = 0x0040,  // inside in contract code
-    ensure        = 0x0060,  // inside out contract code
-    contract      = 0x0060,  // [mask] we're inside contract code
-    ctfe          = 0x0080,  // inside a ctfe-only expression
-    compile       = 0x0100,  // inside __traits(compile)
-    ignoresymbolvisibility = 0x0200,  // ignore symbol visibility (Bugzilla 15907)
-
-    Cfile         = 0x0800,  // C semantics apply
-    free          = 0x8000,  // is on free list
-    fullinst      = 0x10000, // fully instantiate templates
-    ctfeBlock     = 0x20000, // inside a `if (__ctfe)` block
-    dip1000       = 0x40000, // dip1000 errors enabled for this scope
-    dip25         = 0x80000, // dip25 errors enabled for this scope
+    none = 0u,
+    invariant_ = 1u,
+    require = 2u,
+    ensure = 3u,
 };
 
-struct Scope
+struct Scope final
 {
     Scope *enclosing;           // enclosing Scope
 
@@ -122,6 +104,37 @@  struct Scope
 
     unsigned flags;
 
+    bool ctor() const;
+    bool ctor(bool v);
+    bool noAccessCheck() const;
+    bool noAccessCheck(bool v);
+    bool condition() const;
+    bool condition(bool v);
+    bool debug_() const;
+    bool debug_(bool v);
+    bool inTemplateConstraint() const;
+    bool inTemplateConstraint(bool v);
+    Contract contract() const;
+    Contract contract(Contract v);
+    bool ctfe() const;
+    bool ctfe(bool v);
+    bool traitsCompiles() const;
+    bool traitsCompiles(bool v);
+    bool ignoresymbolvisibility() const;
+    bool ignoresymbolvisibility(bool v);
+    bool inCfile() const;
+    bool inCfile(bool v);
+    bool canFree() const;
+    bool canFree(bool v);
+    bool fullinst() const;
+    bool fullinst(bool v);
+    bool ctfeBlock() const;
+    bool ctfeBlock(bool v);
+    bool dip1000() const;
+    bool dip1000(bool v);
+    bool dip25() const;
+    bool dip25(bool v);
+
     UserAttributeDeclaration *userAttribDecl;   // user defined attributes
 
     DocComment *lastdc;         // documentation comment for last symbol at this scope
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 06a5eef47bf..fb7373c73f7 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -21,6 +21,7 @@  import dmd.astcodegen;
 import dmd.astenums;
 import dmd.attrib;
 import dmd.blockexit;
+import dmd.timetrace;
 import dmd.clone;
 import dmd.dcast;
 import dmd.dclass;
@@ -56,6 +57,7 @@  import dmd.parse;
 import dmd.root.filename;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
+import dmd.root.string : toDString;
 import dmd.rootobject;
 import dmd.root.utf;
 import dmd.sideeffect;
@@ -118,43 +120,7 @@  private extern(C++) final class Semantic2Visitor : Visitor
         else if (result)
             return;
 
-        if (sa.msgs)
-        {
-            OutBuffer msgbuf;
-            for (size_t i = 0; i < sa.msgs.length; i++)
-            {
-                Expression e = (*sa.msgs)[i];
-                sc = sc.startCTFE();
-                e = e.expressionSemantic(sc);
-                e = resolveProperties(sc, e);
-                sc = sc.endCTFE();
-                e = ctfeInterpretForPragmaMsg(e);
-                if (e.op == EXP.error)
-                {
-                    errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars());
-                    return;
-                }
-                StringExp se = e.toStringExp();
-                if (se)
-                {
-                    const slice = se.toUTF8(sc).peekString();
-                    // Hack to keep old formatting to avoid changing error messages everywhere
-                    if (sa.msgs.length == 1)
-                        msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr);
-                    else
-                        msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr);
-                }
-                else
-                    msgbuf.printf("%s", e.toChars());
-            }
-            error(sa.loc, "static assert:  %s", msgbuf.extractChars());
-        }
-        else
-            error(sa.loc, "static assert:  `%s` is false", sa.exp.toChars());
-        if (sc.tinst)
-            sc.tinst.printInstantiationTrace();
-        if (!global.gag)
-            fatal();
+        staticAssertFail(sa, sc);
     }
 
     override void visit(TemplateInstance tempinst)
@@ -282,7 +248,7 @@  private extern(C++) final class Semantic2Visitor : Visitor
             // https://issues.dlang.org/show_bug.cgi?id=14166
             // https://issues.dlang.org/show_bug.cgi?id=20417
             // Don't run CTFE for the temporary variables inside typeof or __traits(compiles)
-            vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.flags & SCOPE.compile ? INITnointerpret : INITinterpret);
+            vd._init = vd._init.initializerSemantic(sc, vd.type, sc.intypeof == 1 || sc.traitsCompiles ? INITnointerpret : INITinterpret);
             lowerStaticAAs(vd, sc);
             vd.inuse--;
         }
@@ -330,7 +296,7 @@  private extern(C++) final class Semantic2Visitor : Visitor
         {
             // Cannot initialize a thread-local class or pointer to struct variable with a literal
             // that itself is a thread-local reference and would need dynamic initialization also.
-            if ((vd.type.ty == Tclass) && vd.type.isMutable() && !vd.type.isShared())
+            if (vd.type.ty == Tclass && vd.type.isMutable() && !vd.type.isShared())
             {
                 ExpInitializer ei = vd._init.isExpInitializer();
                 if (ei && ei.exp.op == EXP.classReference)
@@ -393,6 +359,9 @@  private extern(C++) final class Semantic2Visitor : Visitor
         assert(fd.semanticRun <= PASS.semantic2);
         fd.semanticRun = PASS.semantic2;
 
+        timeTraceBeginEvent(TimeTraceEventType.sema2);
+        scope(exit) timeTraceEndEvent(TimeTraceEventType.sema2, fd);
+
         //printf("FuncDeclaration::semantic2 [%s] fd: %s type: %s\n", fd.loc.toChars(), fd.toChars(), fd.type ? fd.type.toChars() : "".ptr);
 
         // Only check valid functions which have a body to avoid errors
@@ -896,3 +865,51 @@  private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor
         this.visit(crExp.value);
     }
 }
+
+/**
+ * Given a static assert with a failing condition, print an error
+ * Params:
+ *   sa = Static assert with failing condition
+ *   sc = scope for evaluating assert message and printing context
+ */
+void staticAssertFail(StaticAssert sa, Scope* sc)
+{
+    if (sa.msgs)
+    {
+        OutBuffer msgbuf;
+        for (size_t i = 0; i < sa.msgs.length; i++)
+        {
+            Expression e = (*sa.msgs)[i];
+            sc = sc.startCTFE();
+            e = e.expressionSemantic(sc);
+            e = resolveProperties(sc, e);
+            sc = sc.endCTFE();
+            e = ctfeInterpretForPragmaMsg(e);
+            if (e.op == EXP.error)
+            {
+                errorSupplemental(sa.loc, "while evaluating `static assert` argument `%s`", (*sa.msgs)[i].toChars());
+                if (!global.gag)
+                    fatal();
+                return;
+            }
+            if (StringExp se = e.toStringExp())
+            {
+                const slice = se.toUTF8(sc).peekString();
+                // Hack to keep old formatting to avoid changing error messages everywhere
+                if (sa.msgs.length == 1)
+                    msgbuf.printf("\"%.*s\"", cast(int)slice.length, slice.ptr);
+                else
+                    msgbuf.printf("%.*s", cast(int)slice.length, slice.ptr);
+            }
+            else
+                msgbuf.printf("%s", e.toChars());
+        }
+        error(sa.loc, "static assert:  %s", msgbuf.extractChars());
+    }
+    else
+        error(sa.loc, "static assert:  `%s` is false", sa.exp.toChars());
+    if (sc.tinst)
+        sc.tinst.printInstantiationTrace();
+    if (!global.gag)
+        fatal();
+}
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 963fa9238a0..89c97cf6be4 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -119,7 +119,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
         sc.tinst = tempinst;
         sc.minst = tempinst.minst;
 
-        int needGagging = (tempinst.gagged && !global.gag);
+        bool needGagging = tempinst.gagged && !global.gag;
         uint olderrors = global.errors;
         int oldGaggedErrors = -1; // dead-store to prevent spurious warning
         /* If this is a gagged instantiation, gag errors.
@@ -221,6 +221,11 @@  private extern(C++) final class Semantic3Visitor : Visitor
     override void visit(FuncDeclaration funcdecl)
     {
         //printf("FuncDeclaration::semantic3(%s '%s', sc = %p)\n", funcdecl.kind(), funcdecl.toChars(), sc);
+        import dmd.timetrace;
+        import dmd.root.string : toDString;
+        timeTraceBeginEvent(TimeTraceEventType.sema3);
+        scope (exit) timeTraceEndEvent(TimeTraceEventType.sema3, funcdecl);
+
         /* Determine if function should add `return 0;`
          */
         bool addReturn0()
@@ -229,7 +234,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
             auto f = funcdecl.type.isTypeFunction();
 
             // C11 5.1.2.2.3
-            if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32)
+            if (sc.inCfile && funcdecl.isCMain() && f.next.ty == Tint32)
                 return true;
 
             return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain());
@@ -290,7 +295,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
             }
         }
 
-        //printf(" sc.incontract = %d\n", (sc.flags & SCOPE.contract));
+        //printf(" sc.incontract = %d\n", sc.contract);
         if (funcdecl.semanticRun >= PASS.semantic3)
             return;
         funcdecl.semanticRun = PASS.semantic3;
@@ -342,7 +347,10 @@  private extern(C++) final class Semantic3Visitor : Visitor
             sc2.explicitVisibility = 0;
             sc2.aligndecl = null;
             if (funcdecl.ident != Id.require && funcdecl.ident != Id.ensure)
-                sc2.flags = sc.flags & ~SCOPE.contract;
+            {
+                sc2.copyFlagsFrom(sc);
+                sc2.contract = Contract.none;
+            }
             sc2.tf = null;
             sc2.os = null;
             sc2.inLoop = false;
@@ -543,8 +551,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
             Statement fpreinv = null;
             if (funcdecl.addPreInvariant())
             {
-                Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
-                if (e)
+                if (Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis))
                     fpreinv = new ExpStatement(Loc.initial, e);
             }
 
@@ -552,8 +559,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
             Statement fpostinv = null;
             if (funcdecl.addPostInvariant())
             {
-                Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis);
-                if (e)
+                if (Expression e = addInvariant(funcdecl.isThis(), funcdecl.vthis))
                     fpostinv = new ExpStatement(Loc.initial, e);
             }
 
@@ -820,7 +826,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.flags & SCOPE.Cfile))
+                    if ((blockexit & BE.fallthru) && f.next.ty != Tvoid && !inlineAsm && !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());
@@ -996,7 +1002,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
                 sym.parent = sc2.scopesym;
                 sym.endlinnum = funcdecl.endloc.linnum;
                 sc2 = sc2.push(sym);
-                sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.require;
+                sc2.contract = Contract.require;
 
                 // BUG: need to error if accessing out parameters
                 // BUG: need to disallow returns
@@ -1041,7 +1047,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
                 }
 
                 sc2 = scout; //push
-                sc2.flags = (sc2.flags & ~SCOPE.contract) | SCOPE.ensure;
+                sc2.contract = Contract.ensure;
 
                 // BUG: need to disallow returns and throws
 
@@ -1212,8 +1218,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
                 {
                     /* Wrap the entire function body in a synchronized statement
                      */
-                    ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration();
-                    if (cd)
+                    if (ClassDeclaration cd = funcdecl.toParentDecl().isClassDeclaration())
                     {
                         if (target.libraryObjectMonitors(funcdecl, sbody))
                         {
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 57a6639575c..4bcfb18881f 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -408,7 +408,7 @@  Expression extractSideEffect(Scope* sc, const char[] name,
      * https://issues.dlang.org/show_bug.cgi?id=17145
      */
     if (!alwaysCopy &&
-        ((sc.flags & SCOPE.ctfe) ? !hasSideEffect(e) : isTrivialExp(e)))
+        (sc.ctfe ? !hasSideEffect(e) : isTrivialExp(e)))
         return e;
 
     auto vd = copyToTemp(0, name, e);
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index c5c8a125936..3b96ecf7c0c 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -82,13 +82,13 @@  version (DMDLIB)
  */
 private Identifier fixupLabelName(Scope* sc, Identifier ident)
 {
-    uint flags = (sc.flags & SCOPE.contract);
+    Contract c = sc.contract;
     const id = ident.toString();
-    if (flags && flags != SCOPE.invariant_ &&
+    if (c != Contract.none && c != Contract.invariant_ &&
         !(id.length >= 2 && id[0] == '_' && id[1] == '_'))  // does not start with "__"
     {
         OutBuffer buf;
-        buf.writestring(flags == SCOPE.require ? "__in_" : "__out_");
+        buf.writestring(c == Contract.require ? "__in_" : "__out_");
         buf.writestring(ident.toString());
 
         ident = Identifier.idPool(buf[]);
@@ -123,7 +123,7 @@  private LabelStatement checkLabeledLoop(Scope* sc, Statement statement) @safe
  */
 private Expression checkAssignmentAsCondition(Expression e, Scope* sc)
 {
-    if (sc.flags & SCOPE.Cfile)
+    if (sc.inCfile)
         return e;
     auto ec = lastComma(e);
     if (ec.op == EXP.assign)
@@ -205,7 +205,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         }
         if (checkMustUse(s.exp, sc))
             s.exp = ErrorExp.get();
-        if (!(sc.flags & SCOPE.Cfile) && discardValue(s.exp))
+        if (!sc.inCfile && discardValue(s.exp))
             s.exp = ErrorExp.get();
 
         s.exp = s.exp.optimize(WANTvalue);
@@ -1697,7 +1697,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         if (ifs.isIfCtfeBlock())
         {
             Scope* scd2 = scd.push();
-            scd2.flags |= SCOPE.ctfeBlock;
+            scd2.ctfeBlock = true;
             ifs.ifbody = ifs.ifbody.semanticNoScope(scd2);
             scd2.pop();
         }
@@ -1733,11 +1733,10 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         // This feature allows a limited form of conditional compilation.
         if (cs.condition.include(sc))
         {
-            DebugCondition dc = cs.condition.isDebugCondition();
-            if (dc)
+            if (DebugCondition dc = cs.condition.isDebugCondition())
             {
                 sc = sc.push();
-                sc.flags |= SCOPE.debug_;
+                sc.debug_ = true;
                 cs.ifbody = cs.ifbody.statementSemantic(sc);
                 sc.pop();
             }
@@ -1964,7 +1963,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             !(!ss.isFinal || needswitcherror || global.params.useAssert == CHECKENABLE.on || sc.func.isSafe);
         if (!ss.hasDefault)
         {
-            if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !(sc.flags & SCOPE.Cfile))
+            if (!ss.isFinal && (!ss._body || !ss._body.isErrorStatement()) && !sc.inCfile)
                 error(ss.loc, "`switch` statement without a `default`; use `final switch` or add `default: assert(0);` or add `default: break;`");
 
             // Generate runtime error if the default is hit
@@ -1972,7 +1971,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             CompoundStatement cs;
             Statement s;
 
-            if (sc.flags & SCOPE.Cfile)
+            if (sc.inCfile)
             {
                 s = new BreakStatement(ss.loc, null);   // default for C is `default: break;`
             }
@@ -2023,7 +2022,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             ss._body = cs;
         }
 
-        if (!(sc.flags & SCOPE.Cfile) && ss.checkLabel())
+        if (!sc.inCfile && ss.checkLabel())
         {
             sc.pop();
             return setError();
@@ -2474,7 +2473,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         Expression e0 = null;
 
         bool errors = false;
-        if (sc.flags & SCOPE.contract)
+        if (sc.contract)
         {
             error(rs.loc, "`return` statements cannot be in contracts");
             errors = true;
@@ -3331,7 +3330,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
                 /* If catch exception type is derived from Exception
                  */
                 if (c.type.toBasetype().implicitConvTo(ClassDeclaration.exception.type) &&
-                    (!c.handler || !c.handler.comeFrom()) && !(sc.flags & SCOPE.debug_))
+                    (!c.handler || !c.handler.comeFrom()) && !sc.debug_)
                 {
                     // Remove c from the array of catches
                     tcs.catches.remove(i);
@@ -3459,7 +3458,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         if (ds.statement)
         {
             sc = sc.push();
-            sc.flags |= SCOPE.debug_;
+            sc.debug_ = true;
             ds.statement = ds.statement.statementSemantic(sc);
             sc.pop();
         }
@@ -3480,7 +3479,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         gs.tf = sc.tf;
         gs.os = sc.os;
         gs.lastVar = sc.lastVar;
-        gs.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
+        gs.inCtfeBlock = sc.ctfeBlock;
 
         if (!gs.label.statement && sc.fes)
         {
@@ -3504,7 +3503,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
                 fd.gotos = new GotoStatements();
             fd.gotos.push(gs);
         }
-        else if (!(sc.flags & SCOPE.Cfile) && gs.checkLabel())
+        else if (!sc.inCfile && gs.checkLabel())
             return setError();
 
         result = gs;
@@ -3520,7 +3519,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         ls.tf = sc.tf;
         ls.os = sc.os;
         ls.lastVar = sc.lastVar;
-        ls.inCtfeBlock = (sc.flags & SCOPE.ctfeBlock) != 0;
+        ls.inCtfeBlock = sc.ctfeBlock;
 
         LabelDsymbol ls2 = fd.searchLabel(ls.ident, ls.loc);
         if (ls2.statement && !ls2.duplicated)
diff --git a/gcc/d/dmd/templatesem.d b/gcc/d/dmd/templatesem.d
index d26e35d814a..afd0add4488 100644
--- a/gcc/d/dmd/templatesem.d
+++ b/gcc/d/dmd/templatesem.d
@@ -154,7 +154,7 @@  void templateDeclarationSemantic(Scope* sc, TemplateDeclaration tempdecl)
 
     /* Calculate TemplateParameter.dependent
      */
-    TemplateParameters tparams = TemplateParameters(1);
+    auto tparams = TemplateParameters(1);
     for (size_t i = 0; i < tempdecl.parameters.length; i++)
     {
         TemplateParameter tp = (*tempdecl.parameters)[i];
@@ -457,7 +457,7 @@  bool evaluateConstraint(TemplateDeclaration td, TemplateInstance ti, Scope* sc,
     // (previously, this was immediately before calling evalStaticCondition), so the
     // semantic pass knows not to issue deprecation warnings for these throw-away decls.
     // https://issues.dlang.org/show_bug.cgi?id=21831
-    scx.flags |= SCOPE.constraint;
+    scx.inTemplateConstraint = true;
 
     assert(!ti.symtab);
     if (fd)
@@ -1337,10 +1337,10 @@  extern (D) MATCHpair deduceFunctionTemplateMatch(TemplateDeclaration td, Templat
                          * We also save/restore sc.func.flags to avoid messing up
                          * attribute inference in the evaluation.
                         */
-                        const oldflags = sc.func ? sc.func.flags : 0;
+                        const oldflags = sc.func ? sc.func.saveFlags : 0;
                         auto e = resolveAliasThis(sc, farg, true);
                         if (sc.func)
-                            sc.func.flags = oldflags;
+                            sc.func.restoreFlags(oldflags);
                         if (e)
                         {
                             farg = e;
diff --git a/gcc/d/dmd/timetrace.d b/gcc/d/dmd/timetrace.d
new file mode 100644
index 00000000000..7d1fd7342c2
--- /dev/null
+++ b/gcc/d/dmd/timetrace.d
@@ -0,0 +1,82 @@ 
+/**
+Compilation time tracing, -ftime-trace.
+
+The time trace profile is output in the Chrome Trace Event Format, described
+here: https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
+
+This file is originally from LDC (the LLVM D compiler).
+
+Copyright: Copyright (C) 1999-2022 by The D Language Foundation, All Rights Reserved
+Authors:   Johan Engelen, Max Haughton, Dennis Korpel
+License:   $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+Source:    $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/common/timetrace.d, common/_timetrace.d)
+Documentation: https://dlang.org/phobos/dmd_common_timetrace.html
+Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/common/timetrace.d
+*/
+module dmd.timetrace;
+
+import dmd.dsymbol;
+import dmd.expression;
+
+/**
+ * Start a new time trace event
+ *
+ * Details of the event will be passed as delegates to `timeTraceEndEvent` so
+ * they're only generated when the event is actually written.
+ *
+ * Params:
+ *   eventType = what compilation stage the event belongs to
+ *      (redundant with the eventType of `timeTraceEndEvent` but used by GDC)
+ */
+extern (C++)
+void timeTraceBeginEvent(TimeTraceEventType eventType)
+{
+}
+
+/**
+ * End a time tracing event, optionally updating the event name and details
+ * with a delegate. Delegates are used to prevent spending time on string
+ * generation when an event is too small to be generated anyway.
+ *
+ * Params:
+ *   eventType = what compilation stage the event belongs to
+ *   sym = Dsymbol which was analyzed, used to generate 'name' and 'detail'
+ *   e = Expression which was analyzed, used to generate 'name' and 'detail'
+ *   detail = custom lazy string for 'detail' of event
+ */
+extern (C++)
+void timeTraceEndEvent(TimeTraceEventType eventType)
+{
+}
+
+/// ditto
+void timeTraceEndEvent(TimeTraceEventType eventType, Dsymbol sym, scope const(char)[] delegate() detail = null)
+{
+    return timeTraceEndEvent(eventType);
+}
+
+/// ditto
+extern (C++)
+void timeTraceEndEvent(TimeTraceEventType eventType, Expression e)
+{
+    return timeTraceEndEvent(eventType);
+}
+
+/// Identifies which compilation stage the event is associated to
+enum TimeTraceEventType
+{
+    generic,
+    parseGeneral,
+    parse,
+    semaGeneral,
+    sema1Import,
+    sema1Module,
+    sema2,
+    sema3,
+    ctfe,
+    ctfeCall,
+    codegenGlobal,
+    codegenModule,
+    codegenFunction,
+    link,
+}
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 5ec38449123..c8608fafc79 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -736,7 +736,9 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
             return dimError(1);
 
         Scope* sc2 = sc.push();
-        sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+        sc2.copyFlagsFrom(sc);
+        sc2.noAccessCheck = true;
+        sc2.ignoresymbolvisibility = true;
         bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
         sc2.pop();
         if (!ok)
@@ -772,7 +774,9 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
             return dimError(1);
 
         Scope* sc2 = sc.push();
-        sc2.flags = sc.flags | SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility;
+        sc2.copyFlagsFrom(sc);
+        sc2.noAccessCheck = true;
+        sc2.ignoresymbolvisibility = true;
         bool ok = TemplateInstance.semanticTiargs(e.loc, sc2, e.args, 1);
         sc2.pop();
         if (!ok)
@@ -1003,7 +1007,8 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
     doSemantic:
         // ignore symbol visibility and disable access checks for these traits
         Scope* scx = sc.push();
-        scx.flags |= SCOPE.ignoresymbolvisibility | SCOPE.noaccesscheck;
+        scx.ignoresymbolvisibility = true;
+        scx.noAccessCheck = true;
         scope (exit) scx.pop();
 
         if (e.ident == Id.hasMember)
@@ -1737,7 +1742,11 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
             Scope* sc2 = sc.push();
             sc2.tinst = null;
             sc2.minst = null;   // this is why code for these are not emitted to object file
-            sc2.flags = (sc.flags & ~(SCOPE.ctfe | SCOPE.condition)) | SCOPE.compile | SCOPE.fullinst;
+            sc2.copyFlagsFrom(sc);
+            sc2.ctfe = false;
+            sc2.condition = false;
+            sc2.traitsCompiles = true;
+            sc2.fullinst = true;
 
             bool err = false;
 
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 33d825a2b84..e4d7a95f888 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -235,7 +235,7 @@  private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
         Dsymbol sm = s.searchX(loc, sc, id, flags);
         if (sm)
         {
-            if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, sm))
+            if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, sm))
             {
                 .error(loc, "`%s` is not visible from module `%s`", sm.toPrettyChars(), sc._module.toChars());
                 sm = null;
@@ -620,7 +620,7 @@  extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
         return false;
     // Don't complain if we're inside a template constraint
     // https://issues.dlang.org/show_bug.cgi?id=21831
-    if (sc.flags & SCOPE.constraint)
+    if (sc.inTemplateConstraint)
         return false;
 
     Type t = type.baseElemOf();
@@ -633,7 +633,7 @@  extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
 
     if (t.isimaginary() || t.iscomplex())
     {
-        if (sc.flags & SCOPE.Cfile)
+        if (sc.inCfile)
             return true;            // complex/imaginary not deprecated in C code
         Type rt;
         switch (t.ty)
@@ -1012,7 +1012,7 @@  private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
         else
         {
             import dmd.dcast : cimplicitConvTo;
-            m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+            m = (sc && sc.inCfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
         }
     }
 
@@ -1445,6 +1445,163 @@  uinteger_t size(Type t, const ref Loc loc)
     }
 }
 
+/*******************************
+ * Determine if converting 'this' to 'to' is an identity operation,
+ * a conversion to const operation, or the types aren't the same.
+ * Returns:
+ *      MATCH.exact      'this' == 'to'
+ *      MATCH.constant      'to' is const
+ *      MATCH.nomatch    conversion to mutable or invariant
+ */
+MATCH constConv(Type from, Type to)
+{
+    MATCH visitType(Type from)
+    {
+        //printf("Type::constConv(this = %s, to = %s)\n", from.toChars(), to.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+        if (from.ty == to.ty && MODimplicitConv(from.mod, to.mod))
+            return MATCH.constant;
+        return MATCH.nomatch;
+    }
+
+    MATCH visitNext(TypeNext from)
+    {
+        //printf("TypeNext::constConv from = %s, to = %s\n", from.toChars(), to.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        if (!(from.ty == to.ty && MODimplicitConv(from.mod, to.mod)))
+            return MATCH.nomatch;
+
+        Type tn = to.nextOf();
+        if (!(tn && from.next.ty == tn.ty))
+            return MATCH.nomatch;
+
+        MATCH m;
+        if (to.isConst()) // whole tail const conversion
+        {
+            // Recursive shared level check
+            m = from.next.constConv(tn);
+            if (m == MATCH.exact)
+                m = MATCH.constant;
+        }
+        else
+        {
+            //printf("\tnext => %s, to.next => %s\n", from.next.toChars(), tn.toChars());
+            m = from.next.equals(tn) ? MATCH.constant : MATCH.nomatch;
+        }
+        return m;
+    }
+
+    MATCH visitSArray(TypeSArray from)
+    {
+        if (auto tsa = to.isTypeSArray())
+        {
+            if (!from.dim.equals(tsa.dim))
+                return MATCH.nomatch;
+        }
+        return visitNext(from);
+    }
+
+    MATCH visitAArray(TypeAArray from)
+    {
+        if (auto taa = to.isTypeAArray())
+        {
+            MATCH mindex = from.index.constConv(taa.index);
+            MATCH mkey = from.next.constConv(taa.next);
+            // Pick the worst match
+            return mkey < mindex ? mkey : mindex;
+        }
+        return visitType(from);
+    }
+
+    MATCH visitPointer(TypePointer from)
+    {
+        if (from.next.ty == Tfunction)
+        {
+            if (to.nextOf() && from.next.equals((cast(TypeNext)to).next))
+                return visitType(from);
+            else
+                return MATCH.nomatch;
+        }
+        return visitNext(from);
+    }
+
+    MATCH visitFunction(TypeFunction from)
+    {
+        // Attributes need to match exactly, otherwise it's an implicit conversion
+        if (from.ty != to.ty || !from.attributesEqual(cast(TypeFunction) to))
+            return MATCH.nomatch;
+
+        return visitNext(from);
+    }
+
+    MATCH visitStruct(TypeStruct from)
+    {
+        if (from.equals(to))
+            return MATCH.exact;
+        if (from.ty == to.ty && from.sym == (cast(TypeStruct)to).sym && MODimplicitConv(from.mod, to.mod))
+            return MATCH.constant;
+        return MATCH.nomatch;
+    }
+
+    MATCH visitEnum(TypeEnum from)
+    {
+        if (from.equals(to))
+            return MATCH.exact;
+        if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym && MODimplicitConv(from.mod, to.mod))
+            return MATCH.constant;
+        return MATCH.nomatch;
+    }
+
+    MATCH visitClass(TypeClass from)
+    {
+        if (from.equals(to))
+            return MATCH.exact;
+        if (from.ty == to.ty && from.sym == (cast(TypeClass)to).sym && MODimplicitConv(from.mod, to.mod))
+            return MATCH.constant;
+
+        /* Conversion derived to const(base)
+         */
+        int offset = 0;
+        if (to.isBaseOf(from, &offset) && offset == 0 && MODimplicitConv(from.mod, to.mod))
+        {
+            // Disallow:
+            //  derived to base
+            //  inout(derived) to inout(base)
+            if (!to.isMutable() && !to.isWild())
+                return MATCH.convert;
+        }
+
+        return MATCH.nomatch;
+    }
+
+    MATCH visitNoreturn(TypeNoreturn from)
+    {
+        // Either another noreturn or conversion to any type
+        return from.implicitConvTo(to);
+    }
+
+    switch(from.ty)
+    {
+        default:            return visitType(from);
+        case Tsarray:       return visitSArray(from.isTypeSArray());
+        case Taarray:       return visitAArray(from.isTypeAArray());
+        case Treference:
+        case Tdelegate:
+        case Tslice:
+        case Tarray:        return visitNext(cast(TypeNext)from);
+        case Tpointer:      return visitPointer(from.isTypePointer());
+        case Tfunction:     return visitFunction(from.isTypeFunction());
+        case Tstruct:       return visitStruct(from.isTypeStruct());
+        case Tenum:         return visitEnum(from.isTypeEnum());
+        case Tclass:        return visitClass(from.isTypeClass());
+        case Tnoreturn:     return visitNoreturn(from.isTypeNoreturn());
+    }
+}
+
+
 /******************************************
  * Perform semantic analysis on a type.
  * Params:
@@ -1479,7 +1636,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 
     Type visitComplex(TypeBasic t)
     {
-        if (!(sc.flags & SCOPE.Cfile))
+        if (!sc.inCfile)
             return visitType(t);
 
         auto tc = getComplexLibraryType(loc, sc, t.ty);
@@ -1653,7 +1810,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         default:
             break;
         }
-        if (tbn.isscope())
+        if (tbn.isScopeClass())
         {
             .error(loc, "cannot have array of scope `%s`", tbn.toChars());
             return error();
@@ -1687,7 +1844,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         default:
             break;
         }
-        if (tn.isscope())
+        if (tn.isScopeClass())
         {
             .error(loc, "cannot have array of scope `%s`", tn.toChars());
             return error();
@@ -1893,7 +2050,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         default:
             break;
         }
-        if (mtype.next.isscope())
+        if (mtype.next.isScopeClass())
         {
             .error(loc, "cannot have array of scope `%s`", mtype.next.toChars());
             return error();
@@ -2059,7 +2216,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             tf.next = tf.next.typeSemantic(loc, sc);
             sc = sc.pop();
             errors |= tf.checkRetType(loc);
-            if (tf.next.isscope() && !tf.isctor)
+            if (tf.next.isScopeClass() && !tf.isctor)
             {
                 .error(loc, "functions cannot return `scope %s`", tf.next.toChars());
                 errors = true;
@@ -2457,7 +2614,7 @@  Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         }
 
         if (tf.parameterList.varargs == VarArg.variadic && tf.linkage != LINK.d && tf.parameterList.length == 0 &&
-            !(sc.flags & SCOPE.Cfile))
+            !sc.inCfile)
         {
             .error(loc, "variadic functions with non-D linkage must have at least one parameter");
             errors = true;
@@ -3209,7 +3366,28 @@  Expression getProperty(Type t, Scope* scope_, const ref Loc loc, Identifier iden
                 else
                 {
                     if (src)
-                        error(loc, "no property `%s` for `%s` of type `%s`", ident.toChars(), src.toChars(), mt.toPrettyChars(true));
+                    {
+                        error(loc, "no property `%s` for `%s` of type `%s`",
+                            ident.toChars(), src.toChars(), mt.toPrettyChars(true));
+                        auto s2 = scope_.search_correct(ident);
+                        // UFCS
+                        if (s2 && s2.isFuncDeclaration)
+                            errorSupplemental(loc, "did you mean %s `%s`?",
+                                s2.kind(), s2.toChars());
+                        else if (src.type.ty == Tpointer)
+                        {
+                            // structPtr.field
+                            auto tn = (cast(TypeNext) src.type).nextOf();
+                            if (auto as = tn.isAggregate())
+                            {
+                                if (auto s3 = as.search_correct(ident))
+                                {
+                                    errorSupplemental(loc, "did you mean %s `%s`?",
+                                        s3.kind(), s3.toChars());
+                                }
+                            }
+                        }
+                    }
                     else
                         error(loc, "no property `%s` for type `%s`", ident.toChars(), mt.toPrettyChars(true));
 
@@ -3897,7 +4075,7 @@  void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
             // compile time sequences are valid types
             !mt.exp.type.isTypeTuple())
         {
-            if (!(sc.flags & SCOPE.Cfile) && // in (extended) C typeof may be used on types as with sizeof
+            if (!sc.inCfile && // in (extended) C typeof may be used on types as with sizeof
                 mt.exp.checkType())
                 goto Lerr;
 
@@ -4786,7 +4964,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
         assert(e.op != EXP.dot);
 
         // https://issues.dlang.org/show_bug.cgi?id=14010
-        if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
+        if (!sc.inCfile && ident == Id._mangleof)
         {
             return mt.getProperty(sc, e.loc, ident, flag & 1);
         }
@@ -4798,7 +4976,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
             /* Create a TupleExp out of the fields of the struct e:
              * (e.field0, e.field1, e.field2, ...)
              */
-            e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+            e = e.expressionSemantic(sc); // do this before turning on noAccessCheck
 
             if (!mt.sym.determineFields())
             {
@@ -4828,20 +5006,20 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
 
             e = new TupleExp(e.loc, e0, exps);
             Scope* sc2 = sc.push();
-            sc2.flags |= SCOPE.noaccesscheck;
+            sc2.noAccessCheck = true;
             e = e.expressionSemantic(sc2);
             sc2.pop();
             return e;
         }
 
-        immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
+        immutable flags = sc.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
         s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
     L1:
         if (!s)
         {
             return noMember(mt, sc, e, ident, flag);
         }
-        if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+        if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, s))
         {
             return noMember(mt, sc, e, ident, flag);
         }
@@ -5078,7 +5256,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
 
             /* Create a TupleExp
              */
-            e = e.expressionSemantic(sc); // do this before turning on noaccesscheck
+            e = e.expressionSemantic(sc); // do this before turning on noAccessCheck
 
             mt.sym.size(e.loc); // do semantic of type
 
@@ -5108,13 +5286,13 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
 
             e = new TupleExp(e.loc, e0, exps);
             Scope* sc2 = sc.push();
-            sc2.flags |= SCOPE.noaccesscheck;
+            sc2.noAccessCheck = true;
             e = e.expressionSemantic(sc2);
             sc2.pop();
             return e;
         }
 
-        SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
+        SearchOptFlags flags = sc.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
         s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
 
     L1:
@@ -5267,7 +5445,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
 
             return noMember(mt, sc, e, ident, flag & 1);
         }
-        if (!(sc.flags & SCOPE.ignoresymbolvisibility) && !symbolIsVisible(sc, s))
+        if (!sc.ignoresymbolvisibility && !symbolIsVisible(sc, s))
         {
             return noMember(mt, sc, e, ident, flag);
         }
@@ -5542,6 +5720,74 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
     }
 }
 
+// if initializer is 0
+bool isZeroInit(Type t, const ref Loc loc)
+{
+    bool visitType(Type _)
+    {
+        return false;       // assume not
+    }
+
+    bool visitBasic(TypeBasic t)
+    {
+        switch (t.ty)
+        {
+            case Tchar:
+            case Twchar:
+            case Tdchar:
+            case Timaginary32:
+            case Timaginary64:
+            case Timaginary80:
+            case Tfloat32:
+            case Tfloat64:
+            case Tfloat80:
+            case Tcomplex32:
+            case Tcomplex64:
+            case Tcomplex80:
+                return false; // no
+            default:
+                return true; // yes
+        }
+    }
+
+    bool visitVector(TypeVector t)
+    {
+        return t.basetype.isZeroInit(loc);
+    }
+
+    bool visitSArray(TypeSArray t)
+    {
+        return t.next.isZeroInit(loc);
+    }
+
+    bool visitStruct(TypeStruct t)
+    {
+        // Determine zeroInit here, as this can be called before semantic2
+        t.sym.determineSize(t.sym.loc);
+        return t.sym.zeroInit;
+    }
+
+    bool visitEnum(TypeEnum t)
+    {
+        return t.sym.getDefaultValue(loc).toBool().hasValue(false);
+    }
+
+    switch(t.ty)
+    {
+        default:               return t.isTypeBasic() ? visitBasic(cast(TypeBasic)t) : visitType(t);
+        case Tvector:          return visitVector(t.isTypeVector());
+        case Tsarray:          return visitSArray(t.isTypeSArray());
+        case Taarray:
+        case Tarray:
+        case Treference:
+        case Tdelegate:
+        case Tclass:
+        case Tpointer:         return true;
+        case Tstruct:          return visitStruct(t.isTypeStruct());
+        case Tenum:            return visitEnum(t.isTypeEnum());
+    }
+}
+
 
 /************************
  * Get the default initialization expression for a type.
@@ -7136,6 +7382,100 @@  bool isRecursiveAliasThis(ref Type att, Type t)
     return false;
 }
 
+MATCH implicitConvToWithoutAliasThis(TypeStruct from, Type to)
+{
+    //printf("TypeStruct::implicitConvToWithoutAliasThis(%s => %s)\n", toChars(), to.toChars());
+
+    auto tos = to.isTypeStruct();
+    if (!(tos && from.sym == tos.sym))
+        return MATCH.nomatch;
+
+    if (from.mod == to.mod)
+        return MATCH.exact;
+
+    if (MODimplicitConv(from.mod, to.mod))
+        return MATCH.constant;
+
+    /* Check all the fields. If they can all be converted,
+     * allow the conversion.
+     */
+    MATCH m = MATCH.constant;
+    uint offset = ~0; // must never match a field offset
+    foreach (v; from.sym.fields[])
+    {
+        /* Why are we only looking at the first member of a union?
+         * The check should check for overlap of v with the previous field,
+         * not just starting at the same point
+         */
+        if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field
+            continue;       // ignore
+
+        Type tvf = v.type.addMod(from.mod);    // from type
+        Type tvt  = v.type.addMod(to.mod);     // to type
+
+        // field match
+        MATCH mf = tvf.implicitConvTo(tvt);
+        //printf("\t%s => %s, match = %d\n", v.type.toChars(), tvt.toChars(), mf);
+
+        if (mf == MATCH.nomatch)
+            return MATCH.nomatch;
+        if (mf < m) // if field match is worse
+            m = mf;
+        offset = v.offset;
+    }
+    return m;
+}
+
+MATCH implicitConvToWithoutAliasThis(TypeClass from, Type to)
+{
+    ClassDeclaration cdto = to.isClassHandle();
+    MATCH m = constConv(from, to);
+    if (m > MATCH.nomatch)
+        return m;
+
+    if (cdto && cdto.isBaseOf(from.sym, null) && MODimplicitConv(from.mod, to.mod))
+    {
+        //printf("'to' is base\n");
+        return MATCH.convert;
+    }
+    return MATCH.nomatch;
+}
+
+MATCH implicitConvToThroughAliasThis(TypeClass from, Type to)
+{
+    MATCH m;
+    if (from.sym.aliasthis && !(from.att & AliasThisRec.tracing))
+    {
+        if (auto ato = aliasthisOf(from))
+        {
+            from.att = cast(AliasThisRec)(from.att | AliasThisRec.tracing);
+            m = ato.implicitConvTo(to);
+            from.att = cast(AliasThisRec)(from.att & ~AliasThisRec.tracing);
+        }
+    }
+    return m;
+}
+
+MATCH implicitConvToThroughAliasThis(TypeStruct from, Type to)
+{
+    auto tos = to.isTypeStruct();
+    if (!(tos && from.sym == tos.sym) &&
+        from.sym.aliasthis &&
+        !(from.att & AliasThisRec.tracing))
+    {
+        if (auto ato = aliasthisOf(from))
+        {
+            from.att = cast(AliasThisRec)(from.att | AliasThisRec.tracing);
+            MATCH m = ato.implicitConvTo(to);
+            from.att = cast(AliasThisRec)(from.att & ~AliasThisRec.tracing);
+            return m;
+        }
+    }
+    return MATCH.nomatch;
+}
+
+
+
 /******************************* Private *****************************************/
 
 private:
@@ -7257,8 +7597,7 @@  Type stripDefaultArgs(Type t)
         {
             foreach (i, p; *parameters)
             {
-                Parameter ps = stripParameter(p);
-                if (ps)
+                if (Parameter ps = stripParameter(p))
                 {
                     // Replace params with a copy we can modify
                     Parameters* nparams = new Parameters(parameters.length);
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index a3198327fb2..5d7154a39d9 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -42,7 +42,7 @@  bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
     // Even when compiling without `useTypeInfo` (e.g. -betterC) we should
     // still be able to evaluate `TypeInfo` at compile-time, just not at runtime.
     // https://issues.dlang.org/show_bug.cgi?id=18472
-    if (!sc || !(sc.flags & SCOPE.ctfe))
+    if (!sc || !sc.ctfe)
     {
         if (!global.params.useTypeInfo)
         {
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index 9228ba69b1c..cde029d5867 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -124,7 +124,7 @@  bool ensurePathToNameExists(Loc loc, const(char)[] name)
  *   buf = Buffer to write the escaped path to
  *   fname = Path to escape
  */
-void escapePath(OutBuffer* buf, const(char)* fname)
+void escapePath(OutBuffer* buf, const(char)* fname) pure
 {
     while (1)
     {
@@ -145,78 +145,6 @@  void escapePath(OutBuffer* buf, const(char)* fname)
     }
 }
 
-/**
- * Takes a path, and make it compatible with GNU Makefile format.
- *
- * GNU make uses a weird quoting scheme for white space.
- * A space or tab preceded by 2N+1 backslashes represents N backslashes followed by space;
- * a space or tab preceded by 2N backslashes represents N backslashes at the end of a file name;
- * and backslashes in other contexts should not be doubled.
- *
- * Params:
- *   buf = Buffer to write the escaped path to
- *   fname = Path to escape
- */
-void writeEscapedMakePath(ref OutBuffer buf, const(char)* fname)
-{
-    uint slashes;
-
-    while (*fname)
-    {
-        switch (*fname)
-        {
-        case '\\':
-            slashes++;
-            break;
-        case '$':
-            buf.writeByte('$');
-            goto default;
-        case ' ':
-        case '\t':
-            while (slashes--)
-                buf.writeByte('\\');
-            goto case;
-        case '#':
-            buf.writeByte('\\');
-            goto default;
-        case ':':
-            // ':' not escaped on Windows because it can
-            // create problems with absolute paths (e.g. C:\Project)
-            version (Windows) {}
-            else
-            {
-                buf.writeByte('\\');
-            }
-            goto default;
-        default:
-            slashes = 0;
-            break;
-        }
-
-        buf.writeByte(*fname);
-        fname++;
-    }
-}
-
-///
-unittest
-{
-    version (Windows)
-    {
-        enum input = `C:\My Project\file#4$.ext`;
-        enum expected = `C:\My\ Project\file\#4$$.ext`;
-    }
-    else
-    {
-        enum input = `/foo\bar/weird$.:name#\ with spaces.ext`;
-        enum expected = `/foo\bar/weird$$.\:name\#\\\ with\ spaces.ext`;
-    }
-
-    OutBuffer buf;
-    buf.writeEscapedMakePath(input);
-    assert(buf[] == expected);
-}
-
 /**
  * Convert string to integer.
  *
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 46d30514287..8a242b88780 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -2180,7 +2180,7 @@  public:
 		tree type = build_ctype (e->type);
 		tree length = size_int (sd->dsym->structsize);
 		tree ptr = (sd->dsym->isStructDeclaration ()
-			    && sd->dsym->type->isZeroInit (e->loc))
+			    && dmd::isZeroInit (sd->dsym->type, e->loc))
 		  ? null_pointer_node : build_address (result);
 
 		this->result_ = d_array_value (type, length, ptr);
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index 982d7cc95dd..c0a496af2fe 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -662,7 +662,7 @@  public:
     this->layout_string (ed->toPrettyChars ());
 
     /* Default initializer for enum.  */
-    if (ed->members && !d->tinfo->isZeroInit ())
+    if (ed->members && !dmd::isZeroInit (d->tinfo))
       {
 	tree length = size_int (dmd::size (ed->type));
 	tree ptr = build_address (enum_initializer_decl (ed));
@@ -1415,7 +1415,7 @@  check_typeinfo_type (const Loc &loc, Scope *sc, Expression *expr)
     {
       /* Even when compiling without RTTI we should still be able to evaluate
 	 TypeInfo at compile-time, just not at run-time.  */
-      if (!sc || !(sc->flags & unsigned(SCOPE::ctfe)))
+      if (!sc || !sc->ctfe ())
 	{
 	  static int warned = 0;
 
diff --git a/gcc/testsuite/gdc.test/compilable/header18365.d b/gcc/testsuite/gdc.test/compilable/header18365.d
index 7e51fb26cc7..8846c86c445 100644
--- a/gcc/testsuite/gdc.test/compilable/header18365.d
+++ b/gcc/testsuite/gdc.test/compilable/header18365.d
@@ -13,7 +13,7 @@  struct FullCaseEntry
 	ubyte n;
 	ubyte size;
 	ubyte entry_len;
-	auto const pure nothrow @nogc @property @trusted value() return
+	auto pure nothrow @nogc @property @trusted value() const return
 	{
 		return seq[0..entry_len];
 	}
diff --git a/gcc/testsuite/gdc.test/compilable/scope.d b/gcc/testsuite/gdc.test/compilable/scope.d
index 44f54f7468a..06549941d25 100644
--- a/gcc/testsuite/gdc.test/compilable/scope.d
+++ b/gcc/testsuite/gdc.test/compilable/scope.d
@@ -262,3 +262,116 @@  struct S23669
         a.length += 1;
     }
 }
+
+/************************************/
+
+// Calling `hasPointers` in escape.d at some point caused
+// a "circular `typeof` definition" error in std.typecons
+// https://github.com/dlang/dmd/pull/16719
+struct Unique
+{
+    int* p;
+    alias ValueType = typeof({ return p; } ());
+    static if (is(ValueType == int*)) {}
+}
+
+// Without handling tuple expansion in escape.d, this error occurs:
+// Error: returning `(ref Tuple!(int, int) __tup2 = this.tuple.get();) , &__tup2.__expand_field_0` escapes a reference to local variable `__tup2`
+struct Tuple(Types...)
+{
+    Types expand;
+    ref Tuple!Types get() { return this; }
+}
+
+struct S2
+{
+    Tuple!(int, int) tuple;
+    int* f() return { return &tuple.get().expand[0]; }
+}
+
+/************************************/
+
+// https://issues.dlang.org/show_bug.cgi?id=23300
+
+auto array(Range)(Range r)
+{
+    int[] result;
+    foreach (e; r)
+        result ~= e;
+    return result;
+}
+
+struct Range
+{
+    int* ptr;
+    int front = 3;
+    enum empty = true;
+    void popFront() @safe scope {}
+}
+
+auto f() @safe
+{
+    scope Range r;
+    return r.array;
+}
+
+/************************************/
+
+// Test that there's no endless loop forwarding `__appendtmp1 => __appendtmp1.this(null)`
+struct SD
+{
+    int* p;
+    this(int*) return scope {}
+}
+
+auto fsd() @safe
+{
+    SD[] a;
+    a ~= SD(null);
+}
+
+/************************************/
+
+// Test that `return scope` inference from assignment doesn't force the function to be `scope`
+struct Scape
+{
+    int* p;
+
+    this()(int* input)
+    {
+        p = input; // return scope inferred here
+        notScope(); // not-scope inferred here
+    }
+
+    void notScope() @safe
+    {
+        static int* g;
+        g = p;
+    }
+}
+
+@safe testScape()
+{
+    Scape(null);
+}
+
+/************************************/
+
+// Test `scope` inference in presence of nested function returning `this`:
+// `save()` can still be called on a `scope Result`
+struct Result
+{
+    int* source;
+    auto save()
+    {
+        int* saveI() { return this.source; }
+        auto saveResult = Result(saveI());
+    }
+}
+
+@safe escapeNested()
+{
+    int s;
+    auto r = Result(&s);
+    r.save();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
index 13974aa0e9a..02fc7db0618 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/bug9631.d
@@ -4,7 +4,7 @@  TEST_OUTPUT:
 fail_compilation/bug9631.d(20): Error: cannot implicitly convert expression `F()` of type `bug9631.T1!().F` to `bug9631.T2!().F`
 ---
 */
-// DISABLED: win32
+
 template T1()
 {
     struct F { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
index 85923b7189e..066e2166d31 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag9679.d
@@ -1,13 +1,73 @@ 
-/*
+/* REQUIRED_ARGS: -verrors=0
 TEST_OUTPUT:
 ---
-fail_compilation/diag9679.d(11): Error: variable `diag9679.main.n` - only parameters, functions and `foreach` declarations can be `ref`
-fail_compilation/diag9679.d(12): Error: variable `diag9679.main.n` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?
+fail_compilation/diag9679.d(15): Error: rvalue `1` cannot be assigned to `ref n`
+fail_compilation/diag9679.d(16): Error: variable `diag9679.main.n` - storage class `auto` has no effect if type is not inferred, did you mean `scope`?
+fail_compilation/diag9679.d(17): Error: variable `diag9679.main.S.a` - field declarations cannot be `ref`
+fail_compilation/diag9679.d(24): Error: returning `r` escapes a reference to local variable `i`
 ---
 */
 
+
+
 void main()
 {
     if (ref n = 1) {}
     if (auto int n = 1) {}
+    struct S { ref int a; }
+}
+
+ref int test2()
+{
+    int i;
+    ref r = i;
+    return r;
+}
+
+ref int test3()
+{
+    extern int i;
+    ref r = i;
+    return r;
+}
+
+struct S { int a; }
+
+void test4()
+{
+    S s;
+    ref int r1 = s.a;
+    r1 = 3;
+    __gshared S t2;
+    ref int r2 = t2.a;
+    static S t3;
+    ref int r3 = t3.a;
+    extern S t4;
+    ref int r4 = t4.a;
+}
+
+/* TEST_OUTPUT:
+---
+fail_compilation/diag9679.d(60): Error: variable `diag9679.test5.r5` - initializer is required for `ref` variable
+fail_compilation/diag9679.d(60): Error: rvalue `0` cannot be assigned to `ref r5`
+fail_compilation/diag9679.d(65): Error: rvalue `4` cannot be assigned to `ref x`
+fail_compilation/diag9679.d(66): Error: returning `x` escapes a reference to local variable `x`
+fail_compilation/diag9679.d(71): Error: type `immutable(int)` cannot be assigned to `ref int x`
+---
+*/
+void test5()
+{
+    ref int r5;
+}
+
+ref int test6()
+{
+    ref int x = 4;
+    return x;
+}
+
+void test7(immutable int y)
+{
+    ref int x = y;
+    x = 5;
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
index 47cb65cde24..9c82b2c2815 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13902.d
@@ -323,9 +323,9 @@  int[] testSlice2() { int[3] sa; int n; return sa[n..2][1..2]; }
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to parameter `vda`
+fail_compilation/fail13902.d(324): Error: returning `vda[0]` escapes a reference to variadic parameter `vda`
+fail_compilation/fail13902.d(325): Error: returning `vda[]` escapes a reference to variadic parameter `vda`
 ---
-
 */
 ref int testDynamicArrayVariadic1(int[] vda...) { return vda[0]; }
 @safe int[]   testDynamicArrayVariadic2(int[] vda...) { return vda[]; }
@@ -335,9 +335,28 @@  int[3]  testDynamicArrayVariadic3(int[] vda...) { return vda[0..3]; }   // no er
 TEST_OUTPUT:
 ---
 fail_compilation/fail13902.d(335): Error: returning `vsa[0]` escapes a reference to parameter `vsa`
-fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to variadic parameter `vsa`
+fail_compilation/fail13902.d(336): Error: returning `vsa[]` escapes a reference to parameter `vsa`
 ---
 */
 ref int testStaticArrayVariadic1(int[3] vsa...) { return vsa[0]; }
 int[]   testStaticArrayVariadic2(int[3] vsa...) { return vsa[]; }
 int[3]  testStaticArrayVariadic3(int[3] vsa...) { return vsa[0..3]; }   // no error
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail13902.d(355): Error: returning `match(st)` escapes a reference to local variable `st`
+---
+*/
+
+// This was reduced from a `static assert(!__traits(compiles, {...}))` test in `std.sumtype`
+// which was asserting that matchers couldn't escape sumtype members.
+// This should give an error even without `@safe` or `-preview=dip1000`
+
+int* match(return ref int i) { return &i; }
+
+int* escape()
+{
+    int st;
+    return match(st);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
index 9c23b78df92..09737e5b25f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19948.d
@@ -1,5 +1,5 @@ 
 // https://issues.dlang.org/show_bug.cgi?id=19948
-// DISABLED: win32
+
 /*
 TEST_OUTPUT:
 ---
@@ -8,7 +8,7 @@  fail_compilation/fail19948.d(16):        cannot pass argument `X()` of type `fai
 fail_compilation/fail19948.d(19):        `fail19948.func(const(X))` declared here
 ---
 */
-// DISABLED: win32
+
 struct X {}
 void main()
 {
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d
index f04db024932..9d99212adac 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20183.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20183.d
@@ -3,15 +3,15 @@  TEST_OUTPUT:
 ---
 fail_compilation/fail20183.d(1016): Error: function `addr` is not callable using argument types `(int)`
 fail_compilation/fail20183.d(1016):        cannot pass rvalue argument `S(0).i` of type `int` to parameter `return ref int b`
-fail_compilation/fail20183.d(1005):        `fail20183.addr(return ref int b)` declared here
-fail_compilation/fail20183.d(1017): Error: address of struct temporary returned by `s()` assigned to longer lived variable `q`
+fail_compilation/fail20183.d(1004):        `fail20183.addr(return ref int b)` declared here
+fail_compilation/fail20183.d(1017): Error: address of expression temporary returned by `s()` assigned to `q` with longer lifetime
+fail_compilation/fail20183.d(1018): Error: address of struct literal `S(0)` assigned to `r` with longer lifetime
 ---
  */
 
 #line 1000
 
 // https://issues.dlang.org/show_bug.cgi?id=20183
-
 @safe:
 
 int* addr(return ref int b) { return &b; }
@@ -19,20 +19,22 @@  int* addr(return ref int b) { return &b; }
 struct S
 {
     int i;
+    S* addrOf() return => &this;
 }
 
 S s() { return S(); }
 
 void test()
 {
-    int* p = addr(S().i);  // struct literal
-    int* q = addr(s().i);  // struct temporary
+    scope int* p = addr(S().i);  // struct literal
+    scope int* q = addr(s().i);  // struct temporary
+    scope S* r = S().addrOf();   // struct literal
 }
 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail20183.d(1107): Error: address of struct temporary returned by `s()` assigned to longer lived variable `this.ptr`
+fail_compilation/fail20183.d(1107): Error: address of expression temporary returned by `s()` assigned to `this.ptr` with longer lifetime
 ---
  */
 #line 1100
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail347.d b/gcc/testsuite/gdc.test/fail_compilation/fail347.d
index 8d061f96fdb..e495ba257e3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail347.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail347.d
@@ -2,9 +2,13 @@ 
 EXTRA_FILES: imports/fail347a.d
 TEST_OUTPUT:
 ---
-fail_compilation/fail347.d(22): Error: undefined identifier `bbr`, did you mean variable `bar`?
-fail_compilation/fail347.d(23): Error: no property `ofo` for type `S`, did you mean `fail347.S.foo`?
-fail_compilation/fail347.d(24): Error: undefined identifier `strlenx`, did you mean function `strlen`?
+fail_compilation/fail347.d(26): Error: undefined identifier `bbr`, did you mean variable `bar`?
+fail_compilation/fail347.d(27): Error: no property `ofo` for type `S`, did you mean `fail347.S.foo`?
+fail_compilation/fail347.d(29): Error: no property `fool` for `sp` of type `fail347.S*`
+fail_compilation/fail347.d(29):        did you mean variable `foo`?
+fail_compilation/fail347.d(30): Error: undefined identifier `strlenx`, did you mean function `strlen`?
+fail_compilation/fail347.d(31): Error: no property `strlenx` for `"hello"` of type `string`
+fail_compilation/fail347.d(31):        did you mean function `strlen`?
 ---
 */
 
@@ -21,5 +25,8 @@  void main()
     S bar;
     bbr.foo = 3;
     bar.ofo = 4;
+    auto sp = &bar;
+    sp.fool = 5;
     auto s = strlenx("hello");
+    auto q = "hello".strlenx();
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope.d b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
index ce983c01fc6..919d9401cd5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope.d
@@ -7,7 +7,7 @@  fail_compilation/retscope.d(32): Error: returning `b ? nested1(& i) : nested2(&
 fail_compilation/retscope.d(45): Error: scope variable `p` assigned to global variable `q`
 fail_compilation/retscope.d(47): Error: address of variable `i` assigned to `q` with longer lifetime
 fail_compilation/retscope.d(48): Error: scope variable `a` assigned to global variable `b`
-fail_compilation/retscope.d(49): Error: address of struct temporary returned by `(*fp2)()` assigned to longer lived variable `q`
+fail_compilation/retscope.d(49): Error: address of expression temporary returned by `(*fp2)()` assigned to `q` with longer lifetime
 ---
 */
 
@@ -299,15 +299,31 @@  struct S7
 
 /***************************************************/
 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/retscope.d(315): Error: scope parameter `p` may not be returned
+fail_compilation/retscope.d(316): Error: returning `p[]` escapes a reference to parameter `p`
+fail_compilation/retscope.d(319): Error: scope parameter `p` may not be returned
+---
+*/
+
 int[3] escape8(scope int[] p) @safe { return p[0 .. 3]; } // should not error
 char*[3] escape9(scope char*[] p) @safe { return p[0 .. 3]; }
 
+// https://issues.dlang.org/show_bug.cgi?id=24663
+    int*[3] escape8b(scope int*[3] p) @safe { return p[]; }
+ref int*[3] escape9b(      int*[3] p) @safe { return p[]; }
+
+ref int[3] asStatic(return scope int[] p) @safe { return p[0 .. 3]; }
+ref int[3] asStatic2(      scope int[] p) @safe { return p[0 .. 3]; }
+
 /***************************************************/
 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/retscope.d(319): Error: reference to local variable `i` assigned to non-scope `f`
+fail_compilation/retscope.d(335): Error: reference to local variable `i` assigned to non-scope `f`
 ---
 */
 
@@ -331,7 +347,7 @@  int* bar10( scope int** ptr ) @safe
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/retscope.d(342): Error: cannot take address of `scope` variable `aa` since `scope` applies to first indirection only
+fail_compilation/retscope.d(358): Error: cannot take address of `scope` variable `aa` since `scope` applies to first indirection only
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope3.d b/gcc/testsuite/gdc.test/fail_compilation/retscope3.d
index 951ad599d55..0774d0d469a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope3.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope3.d
@@ -53,7 +53,7 @@  void bar4()
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to variadic parameter `u`
+fail_compilation/retscope3.d(4003): Error: copying `u[]` into allocated memory escapes a reference to parameter `u`
 fail_compilation/retscope3.d(4016): Error: storing reference to outer local variable `i` into allocated memory causes it to escape
 fail_compilation/retscope3.d(4025): Error: storing reference to stack allocated value returned by `makeSA()` into allocated memory causes it to escape
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
index ddeae81bc23..32710983673 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
@@ -78,8 +78,11 @@  void foo() @safe
 fail_compilation/retscope6.d(8016): Error: address of variable `i` assigned to `p` with longer lifetime
 fail_compilation/retscope6.d(8031): Error: reference to local variable `i` assigned to non-scope parameter `p` calling `betty`
 fail_compilation/retscope6.d(8031): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `betty`
-fail_compilation/retscope6.d(8021):        which is assigned to non-scope parameter `p`
+fail_compilation/retscope6.d(8023):        which is not `scope` because of `p = q`
+fail_compilation/retscope6.d(8048): Error: reference to local variable `i` assigned to non-scope parameter `p` calling `archie`
+fail_compilation/retscope6.d(8039):        which is not `scope` because of `r = p`
 fail_compilation/retscope6.d(8048): Error: reference to local variable `j` assigned to non-scope parameter `q` calling `archie`
+fail_compilation/retscope6.d(8038):        which is not `scope` because of `p = q`
 ---
 */
 
@@ -109,8 +112,8 @@  void testfrankly()
 
 void betty()(int* p, int* q)
 {
-     p = q;
-     escape(p);
+    p = q;
+    escape(p);
 }
 
 void testbetty()
@@ -124,9 +127,9 @@  void testbetty()
 
 void archie()(int* p, int* q, int* r)
 {
-     p = q;
-     r = p;
-     escape(q);
+    p = q;
+    r = p;
+    escape(q);
 }
 
 void testarchie()
@@ -293,3 +296,26 @@  ref int escape23021() @safe
 }
 
 /******************************/
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(14050): Error: scope variable `z` assigned to non-scope parameter `y` calling `f23294`
+fail_compilation/retscope6.d(14044):        which is not `scope` because of `x = y`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=23294
+
+@safe:
+int g23294;
+
+auto f23294(int* x, int* y)
+{
+    x = y;
+    g23294++; // make sure it's not inferring scope from pure
+}
+
+void escape23294(scope int* z)
+{
+    f23294(z, z); // passes
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/staticassert_sema1.d b/gcc/testsuite/gdc.test/fail_compilation/staticassert_sema1.d
new file mode 100644
index 00000000000..e64c437de32
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/staticassert_sema1.d
@@ -0,0 +1,39 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/staticassert_sema1.d(17): Error: static assert:  "unsupported OS"
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24645
+// Test that a static assert(0) is not drowned out by subsequent import errors.
+
+version(_NONEXISTENT_OS)
+{
+
+}
+else
+{
+    static assert(0, msg);
+}
+
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+import object: _NONEXISTENT;
+
+enum msg = "unsupported OS";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test14238.d b/gcc/testsuite/gdc.test/fail_compilation/test14238.d
index a0e4d69b361..e1cd39c595a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test14238.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test14238.d
@@ -1,17 +1,19 @@ 
 /* REQUIRED_ARGS: -preview=dip1000
    TEST_OUTPUT:
 ---
-fail_compilation/test14238.d(20): Error: scope parameter `fn` may not be returned
-fail_compilation/test14238.d(28): Error: escaping reference to stack allocated value returned by `&baz`
+fail_compilation/test14238.d(22): Error: scope parameter `fn` may not be returned
+fail_compilation/test14238.d(25): Error: function `test14238.bar` is `@nogc` yet allocates closure for `bar()` with the GC
+fail_compilation/test14238.d(27):        function `test14238.bar.baz` closes over variable `x`
+fail_compilation/test14238.d(26):        `x` declared here
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=14238
 
 @safe:
 
-alias Fn = ref int delegate() return;
+alias Fn = ref int delegate() return @nogc;
 
-ref int foo(return scope Fn fn)
+ref int call(return scope Fn fn) @nogc
 {
     return fn(); // Ok
 }
@@ -20,10 +22,14 @@  ref int foo2(scope Fn fn) {
     return fn(); // Error
 }
 
-ref int bar() {
+ref int bar() @nogc {
     int x;
     ref int baz() {
             return x;
     }
-    return foo(&baz);
+
+    if (x == 0)
+        return call(&baz);
+    else
+        return (&baz)();
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18644.d b/gcc/testsuite/gdc.test/fail_compilation/test18644.d
index 430967ee4a4..201e44694ed 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test18644.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18644.d
@@ -1,9 +1,9 @@ 
 /* REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
-fail_compilation/test18644.d(15): Error: storing reference to stack allocated value returned by `foo()` into allocated memory causes it to escape
-fail_compilation/test18644.d(16): Error: escaping reference to stack allocated value returned by `foo()`
-fail_compilation/test18644.d(22): Error: escaping reference to stack allocated value returned by `foo()`
+fail_compilation/test18644.d(15): Error: nested function `foo` returns `scope` values and escapes them into allocated memory
+fail_compilation/test18644.d(16): Error: escaping local variable through nested function `foo`
+fail_compilation/test18644.d(22): Error: escaping local variable through nested function `foo`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22977.d b/gcc/testsuite/gdc.test/fail_compilation/test22977.d
index 87bb19cc711..9478ec989d8 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test22977.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22977.d
@@ -3,7 +3,7 @@  REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
 fail_compilation/test22977.d(16): Error: escaping local variable through nested function `scfunc`
-fail_compilation/test22977.d(22): Error: escaping reference to stack allocated value returned by `scfunc2()`
+fail_compilation/test22977.d(22): Error: escaping local variable through nested function `scfunc2`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23022.d b/gcc/testsuite/gdc.test/fail_compilation/test23022.d
index 8c4eca9c563..db1f4a712c1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test23022.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test23022.d
@@ -2,7 +2,7 @@ 
 REQUIRED_ARGS: -preview=dip1000
 TEST_OUTPUT:
 ---
-fail_compilation/test23022.d(14): Error: scope parameter `p` may not be returned
+fail_compilation/test23022.d(14): Error: returning `p` escapes a reference to variadic parameter `p`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24680.d b/gcc/testsuite/gdc.test/fail_compilation/test24680.d
new file mode 100644
index 00000000000..50efba41344
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24680.d
@@ -0,0 +1,20 @@ 
+/**
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/test24680.d(19): Error: returning `c.peek(buf[])` escapes a reference to local variable `buf`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24680
+
+class C
+{
+    final auto peek(ubyte[] buf) { return buf; }
+}
+
+@safe escape(C c)
+{
+    ubyte[5] buf;
+    return c.peek(buf[]);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
index 4c8576c88d9..ea929bcc45c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
@@ -17,14 +17,14 @@  fail_compilation/typeerrors.d(52): Error: cannot have associative array of `void
 fail_compilation/typeerrors.d(54): Error: cannot have parameter of type `void`
 fail_compilation/typeerrors.d(56): Error: slice `[1..5]` is out of range of [0..4]
 fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0..4]
+fail_compilation/typeerrors.d(59): Error: variable `typeerrors.foo.globalC` globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`
+fail_compilation/typeerrors.d(59): Error: variable `typeerrors.foo.globalC` reference to `scope class` must be `scope`
+fail_compilation/typeerrors.d(60): Error: variable `typeerrors.foo.manifestC` globals, statics, fields, manifest constants, ref and out parameters cannot be `scope`
+fail_compilation/typeerrors.d(60): Error: variable `typeerrors.foo.manifestC` reference to `scope class` must be `scope`
 ---
 */
 
 
-
-
-
-
 template tuple(T...) { alias T tuple; }
 
 void bar();
@@ -55,4 +55,7 @@  void foo()
 
     alias T2 = T[1 .. 5];
     alias T3 = T[2 .. 1];
+
+    static C globalC;
+    enum C manifestC = new C();
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/verrors5.d b/gcc/testsuite/gdc.test/fail_compilation/verrors5.d
index 424d4f7622d..74068610add 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/verrors5.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/verrors5.d
@@ -36,5 +36,6 @@  fail_compilation/verrors5.d(6): Error: undefined identifier `T`
 fail_compilation/verrors5.d(7): Error: undefined identifier `T`
 fail_compilation/verrors5.d(8): Error: undefined identifier `T`
 fail_compilation/verrors5.d(9): Error: undefined identifier `T`
+error limit (5) reached, use `-verrors=0` to show all
 ---
 */
diff --git a/gcc/testsuite/gdc.test/runnable/declaration.d b/gcc/testsuite/gdc.test/runnable/declaration.d
index 5be76fac6d7..a6642ea6677 100644
--- a/gcc/testsuite/gdc.test/runnable/declaration.d
+++ b/gcc/testsuite/gdc.test/runnable/declaration.d
@@ -406,6 +406,33 @@  void test13950()
 
 /***************************************************/
 
+
+void testlocalref()
+{
+    int x = 4;
+    ref int rx = x;
+    rx = 5;
+    assert(x == 5);
+    ref int r2 = rx;
+    r2 = 6;
+    assert(x == 6);
+}
+
+/***************************************************/
+
+int global;
+
+ref int tgr() { return global; }
+
+void testglobalref()
+{
+    auto i = tgr();
+    i = 1;
+    assert(global == 0);
+}
+
+/***************************************************/
+
 int main()
 {
     test6475();
@@ -419,6 +446,8 @@  int main()
     test10142();
     test11421();
     test13950();
+    testlocalref();
+    testglobalref();
 
     printf("Success\n");
     return 0;
diff --git a/gcc/testsuite/gdc.test/runnable/link11069a.d b/gcc/testsuite/gdc.test/runnable/link11069a.d
index e31cfa0bcf6..429ae8da7ec 100644
--- a/gcc/testsuite/gdc.test/runnable/link11069a.d
+++ b/gcc/testsuite/gdc.test/runnable/link11069a.d
@@ -1,5 +1,5 @@ 
 // EXTRA_FILES: imports/std11069array.d imports/std11069container.d imports/std11069range.d imports/std11069typecons.d
-// REQUIRED_ARGS: -noboundscheck
+// REQUIRED_ARGS: -boundscheck=off
 // <-- To remove necessity of _D7imports13std11069array7__arrayZ
 
 class Bar
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index d458bea5e1a..a6072c4570d 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
+34875cd6e1faa42e84ae953c0485ef524fe67e38
 
 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/cpuid.d b/libphobos/libdruntime/core/cpuid.d
index 62edbac34f3..4c2eb2adc00 100644
--- a/libphobos/libdruntime/core/cpuid.d
+++ b/libphobos/libdruntime/core/cpuid.d
@@ -1038,9 +1038,9 @@  bool hasCPUID()
 
     void cpuidX86()
     {
-            datacache[0].size = 8;
-            datacache[0].associativity = 2;
-            datacache[0].lineSize = 32;
+        datacache[0].size = 8;
+        datacache[0].associativity = 2;
+        datacache[0].lineSize = 32;
     }
 }
 
diff --git a/libphobos/libdruntime/core/demangle.d b/libphobos/libdruntime/core/demangle.d
index 4405dec2639..c197262384f 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -3187,9 +3187,7 @@  private struct BufSlice
     size_t from;
     size_t to;
 
-    @safe:
-    pure:
-    nothrow:
+    @safe pure nothrow:
 
     @disable this();
 
@@ -3209,7 +3207,7 @@  private struct BufSlice
             this.to = to;
     }
 
-    invariant()
+    invariant
     {
         if (buf is null)
         {
diff --git a/libphobos/libdruntime/core/internal/array/concatenation.d b/libphobos/libdruntime/core/internal/array/concatenation.d
index 4a05b50fcff..3063c4c0ea0 100644
--- a/libphobos/libdruntime/core/internal/array/concatenation.d
+++ b/libphobos/libdruntime/core/internal/array/concatenation.d
@@ -62,7 +62,7 @@  Tret _d_arraycatnTX(Tret, Tarr...)(auto ref Tarr froms) @trusted
     {
         size_t i = 0;
         foreach (ref from; froms)
-            static if (is (typeof(from) : T))
+            static if (is(typeof(from) : T))
                 copyEmplace(cast(T) from, res[i++]);
             else
             {
diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d
index 8f0323a054b..8098597a72a 100644
--- a/libphobos/libdruntime/core/internal/array/construction.d
+++ b/libphobos/libdruntime/core/internal/array/construction.d
@@ -530,7 +530,7 @@  Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trust
         if (dims.length == 1)
         {
             auto r = _d_newarrayT!UnqT(dim, isShared);
-            return *cast(void[]*)(&r);
+            return *cast(void[]*)&r;
         }
 
         auto allocSize = (void[]).sizeof * dim;
diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d
index 6242d76ba30..36cf6891feb 100644
--- a/libphobos/libdruntime/core/internal/atomic.d
+++ b/libphobos/libdruntime/core/internal/atomic.d
@@ -983,7 +983,7 @@  else version (GNU)
         // Internal static mutex reference.
         private AtomicMutex* _getAtomicMutex() @trusted @nogc nothrow
         {
-            __gshared static AtomicMutex mutex;
+            __gshared AtomicMutex mutex;
             return &mutex;
         }
 
diff --git a/libphobos/libdruntime/core/internal/convert.d b/libphobos/libdruntime/core/internal/convert.d
index 92eb243ec1a..7bac8359a77 100644
--- a/libphobos/libdruntime/core/internal/convert.d
+++ b/libphobos/libdruntime/core/internal/convert.d
@@ -695,7 +695,7 @@  const(ubyte)[] toUbyte(T)(const ref scope T val) if (__traits(isIntegral, T) &&
         }
         else
         {
-            return (cast(const(ubyte)*)(&val))[0 .. T.sizeof];
+            return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
         }
     }
     else if (__ctfe)
@@ -715,7 +715,7 @@  const(ubyte)[] toUbyte(T)(const ref scope T val) if (__traits(isIntegral, T) &&
     }
     else
     {
-        return (cast(const(ubyte)*)(&val))[0 .. T.sizeof];
+        return (cast(const(ubyte)*)&val)[0 .. T.sizeof];
     }
 }
 
diff --git a/libphobos/libdruntime/core/internal/gc/bits.d b/libphobos/libdruntime/core/internal/gc/bits.d
index aa94e407642..a060e65c8e1 100644
--- a/libphobos/libdruntime/core/internal/gc/bits.d
+++ b/libphobos/libdruntime/core/internal/gc/bits.d
@@ -134,7 +134,7 @@  struct GCBits
         }
         else
         {
-            auto pos = i >> BITS_SHIFT;
+            const pos = i >> BITS_SHIFT;
             auto pdata = cast(shared)(data + pos);
             auto mask = BITS_1 << (i & BITS_MASK);
             auto state = *pdata;
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index b1b270799aa..dd6f92a8a7a 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -404,7 +404,7 @@  class ConservativeGC : GC
                 p = sentinel_sub(p);
                 if (p != pool.findBase(p))
                     return 0;
-                auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy;
+                const biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy;
 
                 oldb = pool.getBits(biti);
                 pool.setBits(biti, mask);
@@ -447,7 +447,7 @@  class ConservativeGC : GC
                 p = sentinel_sub(p);
                 if (p != pool.findBase(p))
                     return 0;
-                auto biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy;
+                const biti = cast(size_t)(p - pool.baseAddr) >> pool.shiftBy;
 
                 oldb = pool.getBits(biti);
                 pool.clrBits(biti, mask);
@@ -784,25 +784,25 @@  class ConservativeGC : GC
                 return 0;
 
             auto lpool = cast(LargeObjectPool*) pool;
-            size_t pagenum = lpool.pagenumOf(p);
+            const pagenum = lpool.pagenumOf(p);
             if (lpool.pagetable[pagenum] != Bins.B_PAGE)
                 return 0;
 
-            size_t psz = lpool.bPageOffsets[pagenum];
+            uint psz = lpool.bPageOffsets[pagenum];
             assert(psz > 0);
 
-            auto minsz = lpool.numPages(minsize);
-            auto maxsz = lpool.numPages(maxsize);
+            const minsz = lpool.numPages(minsize);
+            const maxsz = lpool.numPages(maxsize);
 
             if (pagenum + psz >= lpool.npages)
                 return 0;
             if (lpool.pagetable[pagenum + psz] != Bins.B_FREE)
                 return 0;
 
-            size_t freesz = lpool.bPageOffsets[pagenum + psz];
+            const freesz = lpool.bPageOffsets[pagenum + psz];
             if (freesz < minsz)
                 return 0;
-            size_t sz = freesz > maxsz ? maxsz : freesz;
+            const sz = freesz > maxsz ? maxsz : freesz;
             invalidate((pool.baseAddr + (pagenum + psz) * PAGESIZE)[0 .. sz * PAGESIZE], 0xF0, true);
             memset(lpool.pagetable + pagenum + psz, Bins.B_PAGEPLUS, sz);
             lpool.bPageOffsets[pagenum] = cast(uint) (psz + sz);
@@ -1609,7 +1609,7 @@  struct Gcx
     void Invariant() const { }
 
     debug(INVARIANT)
-    invariant()
+    invariant
     {
         if (initialized)
         {
@@ -3171,8 +3171,7 @@  Lmark:
     {
         // first, we find the Pool this block is in, then check to see if the
         // mark bit is clear.
-        auto pool = findPool(addr);
-        if (pool)
+        if (auto pool = findPool(addr))
         {
             auto offset = cast(size_t)(addr - pool.baseAddr);
             auto pn = offset / PAGESIZE;
@@ -3924,7 +3923,7 @@  struct Pool
     void Invariant() const {}
 
     debug(INVARIANT)
-    invariant()
+    invariant
     {
         if (baseAddr)
         {
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index 6cd75f3a791..b9b10aae3d9 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -959,7 +959,7 @@  version (CRuntime_Microsoft) // supported since MSVCRT 12 (VS 2013) only
             double num;
             double denom;
         }
-        static __gshared immutable(Entry[5]) table =
+        static immutable Entry[5] table =
         [ // Raise exception by evaluating num / denom:
             { FE_INVALID,   0.0,    0.0    },
             { FE_DIVBYZERO, 1.0,    0.0    },
diff --git a/libphobos/libdruntime/core/stdc/stdatomic.d b/libphobos/libdruntime/core/stdc/stdatomic.d
index 72e037f7e92..51968af8c5f 100644
--- a/libphobos/libdruntime/core/stdc/stdatomic.d
+++ b/libphobos/libdruntime/core/stdc/stdatomic.d
@@ -18,6 +18,7 @@  module core.stdc.stdatomic;
 import core.atomic : MemoryOrder;
 import core.internal.atomic;
 import core.stdc.config;
+import core.stdc.stddef;
 import core.stdc.stdint;
 
 @safe nothrow @nogc:
@@ -54,7 +55,7 @@  enum
     ///
     ATOMIC_CHAR32_T_LOCK_FREE = IsAtomicLockFree!dchar ? 2 : 0,
     ///
-    ATOMIC_WCHAR_T_LOCK_FREE = ATOMIC_CHAR16_T_LOCK_FREE,
+    ATOMIC_WCHAR_T_LOCK_FREE = IsAtomicLockFree!wchar_t ? 2 : 0,
     ///
     ATOMIC_SHORT_LOCK_FREE = IsAtomicLockFree!short ? 2 : 0,
     ///
@@ -365,7 +366,7 @@  alias atomic_char16_t = shared(wchar);
 ///
 alias atomic_char32_t = shared(dchar);
 ///
-alias atomic_wchar_t = shared(wchar);
+alias atomic_wchar_t = shared(wchar_t);
 
 ///
 alias atomic_int_least8_t = shared(int_least8_t);
diff --git a/libphobos/libdruntime/core/stdc/stdint.d b/libphobos/libdruntime/core/stdc/stdint.d
index 1776269378f..4f9b98cd8ce 100644
--- a/libphobos/libdruntime/core/stdc/stdint.d
+++ b/libphobos/libdruntime/core/stdc/stdint.d
@@ -480,13 +480,21 @@  enum int_fast64_t  INT_FAST64_MIN  = int_fast64_t.min;
 ///
 enum int_fast64_t  INT_FAST64_MAX  = int_fast64_t.max;
 
+///
+enum uint_fast8_t  UINT_FAST8_MIN  = uint_fast8_t.min;
 ///
 enum uint_fast8_t  UINT_FAST8_MAX  = uint_fast8_t.max;
 ///
+enum uint_fast16_t UINT_FAST16_MIN = uint_fast16_t.min;
+///
 enum uint_fast16_t UINT_FAST16_MAX = uint_fast16_t.max;
 ///
+enum uint_fast32_t UINT_FAST32_MIN = uint_fast32_t.min;
+///
 enum uint_fast32_t UINT_FAST32_MAX = uint_fast32_t.max;
 ///
+enum uint_fast64_t UINT_FAST64_MIN = uint_fast64_t.min;
+///
 enum uint_fast64_t UINT_FAST64_MAX = uint_fast64_t.max;
 
 ///
diff --git a/libphobos/libdruntime/core/stdc/wctype.d b/libphobos/libdruntime/core/stdc/wctype.d
index b37e8322dc3..88b6a01245f 100644
--- a/libphobos/libdruntime/core/stdc/wctype.d
+++ b/libphobos/libdruntime/core/stdc/wctype.d
@@ -14,6 +14,7 @@ 
 
 module core.stdc.wctype;
 
+import core.stdc.config;
 public  import core.stdc.wchar_; // for wint_t, WEOF
 
 extern (C):
@@ -21,10 +22,41 @@  extern (C):
 nothrow:
 @nogc:
 
-///
-alias wchar_t wctrans_t;
-///
-alias wchar_t wctype_t;
+version (CRuntime_Glibc)
+{
+    ///
+    alias wctype_t = c_ulong;
+    ///
+    alias wctrans_t = const(int)*;
+}
+else version (CRuntime_Musl)
+{
+    ///
+    alias wctype_t = c_ulong;
+    ///
+    alias wctrans_t = const(int)*;
+}
+else version (FreeBSD)
+{
+    ///
+    alias wctype_t = c_ulong;
+    ///
+    alias wctrans_t = int;
+}
+else version (CRuntime_Bionic)
+{
+    ///
+    alias wctype_t = c_long;
+    ///
+    alias wctrans_t = const(void)*;
+}
+else
+{
+    ///
+    alias wchar_t wctrans_t;
+    ///
+    alias wchar_t wctype_t;
+}
 
 ///
 pure int iswalnum(wint_t wc);
@@ -63,3 +95,17 @@  pure wint_t    towupper(wint_t wc);
 wint_t    towctrans(wint_t wc, wctrans_t desc);
 ///
 @system wctrans_t wctrans(const scope char* property);
+
+unittest
+{
+    assert(iswalpha('A'));
+    assert(!iswalpha('0'));
+    wctype_t alpha = wctype("alpha");
+    assert(alpha);
+    wctrans_t tolower = wctrans("tolower");
+    assert(tolower);
+    assert(iswctype('A', alpha));
+    assert(!iswctype('0', alpha));
+    assert(towctrans('A', tolower) == 'a');
+    assert(towctrans('0', tolower) == '0');
+}
diff --git a/libphobos/libdruntime/core/stdcpp/string_view.d b/libphobos/libdruntime/core/stdcpp/string_view.d
index fd79a121be5..986fa7ee273 100644
--- a/libphobos/libdruntime/core/stdcpp/string_view.d
+++ b/libphobos/libdruntime/core/stdcpp/string_view.d
@@ -37,7 +37,7 @@  extern(C++, struct) struct char_traits(CharT) {}
 /**
 * D language counterpart to C++ std::basic_string_view.
 *
-* C++ reference: $(LINK2 hhttps://en.cppreference.com/w/cpp/string/basic_string_view)
+* C++ reference: $(LINK2 https://en.cppreference.com/w/cpp/string/basic_string_view, std::basic_string_view)
 */
 extern(C++, class) struct basic_string_view(T, Traits = char_traits!T)
 {
diff --git a/libphobos/libdruntime/core/sys/posix/signal.d b/libphobos/libdruntime/core/sys/posix/signal.d
index a8b7f7511a9..ed4ec1270d9 100644
--- a/libphobos/libdruntime/core/sys/posix/signal.d
+++ b/libphobos/libdruntime/core/sys/posix/signal.d
@@ -136,7 +136,7 @@  version (Solaris)
     import core.sys.posix.unistd;
 
     @property int SIGRTMIN() nothrow @nogc {
-        __gshared static int sig = -1;
+        __gshared int sig = -1;
         if (sig == -1) {
             sig = cast(int)sysconf(_SC_SIGRT_MIN);
         }
@@ -144,7 +144,7 @@  version (Solaris)
     }
 
     @property int SIGRTMAX() nothrow @nogc {
-        __gshared static int sig = -1;
+        __gshared int sig = -1;
         if (sig == -1) {
             sig = cast(int)sysconf(_SC_SIGRT_MAX);
         }
@@ -180,7 +180,7 @@  else version (linux)
     }
 
     @property int SIGRTMIN() nothrow @nogc {
-        __gshared static int sig = -1;
+        __gshared int sig = -1;
         if (sig == -1) {
             sig = __libc_current_sigrtmin();
         }
@@ -188,7 +188,7 @@  else version (linux)
     }
 
     @property int SIGRTMAX() nothrow @nogc {
-        __gshared static int sig = -1;
+        __gshared int sig = -1;
         if (sig == -1) {
             sig = __libc_current_sigrtmax();
         }
diff --git a/libphobos/libdruntime/core/sys/posix/sys/resource.d b/libphobos/libdruntime/core/sys/posix/sys/resource.d
index 3a9a1876393..b75c794e926 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/resource.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/resource.d
@@ -82,14 +82,14 @@  version (linux)
     }
 
     static if (__USE_FILE_OFFSET64)
-         alias ulong rlim_t;
+        alias ulong rlim_t;
     else
-         alias c_ulong rlim_t;
+        alias c_ulong rlim_t;
 
     static if (__USE_FILE_OFFSET64)
         enum RLIM_INFINITY = 0xffffffffffffffffUL;
     else
-        enum RLIM_INFINITY = cast(c_ulong)(~0UL);
+        enum RLIM_INFINITY = cast(c_ulong)~0UL;
 
     enum RLIM_SAVED_MAX = RLIM_INFINITY;
     enum RLIM_SAVED_CUR = RLIM_INFINITY;
@@ -163,7 +163,7 @@  else version (Darwin)
 
     enum
     {
-        RLIM_INFINITY  = ((cast(ulong) 1 << 63) - 1),
+        RLIM_INFINITY  = ((1UL << 63) - 1),
         RLIM_SAVED_MAX = RLIM_INFINITY,
         RLIM_SAVED_CUR = RLIM_INFINITY,
     }
@@ -205,7 +205,7 @@  else version (FreeBSD)
 
     enum
     {
-        RLIM_INFINITY   = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
+        RLIM_INFINITY   = (cast(rlim_t)((1UL << 63) - 1)),
         RLIM_SAVED_MAX  = RLIM_INFINITY,
         RLIM_SAVED_CUR  = RLIM_INFINITY,
     }
@@ -262,7 +262,7 @@  else version (NetBSD)
 
     enum
     {
-        RLIM_INFINITY   = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
+        RLIM_INFINITY   = (cast(rlim_t)((1UL << 63) - 1)),
         RLIM_SAVED_MAX = RLIM_INFINITY,
         RLIM_SAVED_CUR = RLIM_INFINITY,
     }
@@ -319,7 +319,7 @@  else version (OpenBSD)
 
     enum
     {
-        RLIM_INFINITY  = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
+        RLIM_INFINITY  = (cast(rlim_t)((1UL << 63) - 1)),
         RLIM_SAVED_MAX = RLIM_INFINITY,
         RLIM_SAVED_CUR = RLIM_INFINITY,
     }
@@ -378,7 +378,7 @@  else version (DragonFlyBSD)
 
     enum
     {
-        RLIM_INFINITY   = (cast(rlim_t)((cast(ulong) 1 << 63) - 1)),
+        RLIM_INFINITY   = (cast(rlim_t)((1UL << 63) - 1)),
         RLIM_SAVED_MAX  = RLIM_INFINITY,
         RLIM_SAVED_CUR  = RLIM_INFINITY,
     }
diff --git a/libphobos/libdruntime/core/sys/windows/dll.d b/libphobos/libdruntime/core/sys/windows/dll.d
index 6a003b5c633..7c601bb2e3f 100644
--- a/libphobos/libdruntime/core/sys/windows/dll.d
+++ b/libphobos/libdruntime/core/sys/windows/dll.d
@@ -117,19 +117,19 @@  version (Win32)
     //     _NtdllBaseTag           - tag used for RtlAllocateHeap
     //     _LdrpTlsList            - root of the double linked list with TlsList entries
 
-    static __gshared int* pNtdllBaseTag; // remembered for reusage in addTlsData
-
-    static __gshared ubyte[] jmp_LdrpInitialize = [ 0x33, 0xED, 0xE9 ]; // xor ebp,ebp; jmp _LdrpInitialize
-    static __gshared ubyte[] jmp__LdrpInitialize = [ 0x5D, 0xE9 ]; // pop ebp; jmp __LdrpInitialize
-    static __gshared ubyte[] jmp__LdrpInitialize_xp64 = [ 0x5D, 0x90, 0x90, 0x90, 0x90, 0x90 ]; // pop ebp; nop; nop; nop; nop; nop;
-    static __gshared ubyte[] call_LdrpInitializeThread = [ 0xFF, 0x75, 0x08, 0xE8 ]; // push [ebp+8]; call _LdrpInitializeThread
-    static __gshared ubyte[] call_LdrpAllocateTls = [ 0x00, 0x00, 0xE8 ]; // jne 0xc3; call _LdrpAllocateTls
-    static __gshared ubyte[] call_LdrpAllocateTls_svr03 = [ 0x65, 0xfc, 0x00, 0xE8 ]; // and [ebp+fc], 0; call _LdrpAllocateTls
-    static __gshared ubyte[] jne_LdrpAllocateTls = [ 0x0f, 0x85 ]; // jne body_LdrpAllocateTls
-    static __gshared ubyte[] mov_LdrpNumberOfTlsEntries = [ 0x8B, 0x0D ]; // mov ecx, _LdrpNumberOfTlsEntries
-    static __gshared ubyte[] mov_NtdllBaseTag = [ 0x51, 0x8B, 0x0D ]; // push ecx; mov ecx, _NtdllBaseTag
-    static __gshared ubyte[] mov_NtdllBaseTag_srv03 = [ 0x50, 0xA1 ]; // push eax; mov eax, _NtdllBaseTag
-    static __gshared ubyte[] mov_LdrpTlsList = [ 0x8B, 0x3D ]; // mov edi, _LdrpTlsList
+    __gshared int* pNtdllBaseTag; // remembered for reusage in addTlsData
+
+    __gshared ubyte[] jmp_LdrpInitialize = [ 0x33, 0xED, 0xE9 ]; // xor ebp,ebp; jmp _LdrpInitialize
+    __gshared ubyte[] jmp__LdrpInitialize = [ 0x5D, 0xE9 ]; // pop ebp; jmp __LdrpInitialize
+    __gshared ubyte[] jmp__LdrpInitialize_xp64 = [ 0x5D, 0x90, 0x90, 0x90, 0x90, 0x90 ]; // pop ebp; nop; nop; nop; nop; nop;
+    __gshared ubyte[] call_LdrpInitializeThread = [ 0xFF, 0x75, 0x08, 0xE8 ]; // push [ebp+8]; call _LdrpInitializeThread
+    __gshared ubyte[] call_LdrpAllocateTls = [ 0x00, 0x00, 0xE8 ]; // jne 0xc3; call _LdrpAllocateTls
+    __gshared ubyte[] call_LdrpAllocateTls_svr03 = [ 0x65, 0xfc, 0x00, 0xE8 ]; // and [ebp+fc], 0; call _LdrpAllocateTls
+    __gshared ubyte[] jne_LdrpAllocateTls = [ 0x0f, 0x85 ]; // jne body_LdrpAllocateTls
+    __gshared ubyte[] mov_LdrpNumberOfTlsEntries = [ 0x8B, 0x0D ]; // mov ecx, _LdrpNumberOfTlsEntries
+    __gshared ubyte[] mov_NtdllBaseTag = [ 0x51, 0x8B, 0x0D ]; // push ecx; mov ecx, _NtdllBaseTag
+    __gshared ubyte[] mov_NtdllBaseTag_srv03 = [ 0x50, 0xA1 ]; // push eax; mov eax, _NtdllBaseTag
+    __gshared ubyte[] mov_LdrpTlsList = [ 0x8B, 0x3D ]; // mov edi, _LdrpTlsList
 
     static LdrpTlsListEntry* addTlsListEntry( void** peb, void* tlsstart, void* tlsend, void* tls_callbacks_a, int* tlsindex ) nothrow
     {
diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d
index c3192fc39f9..dc79141efa7 100644
--- a/libphobos/libdruntime/core/time.d
+++ b/libphobos/libdruntime/core/time.d
@@ -701,9 +701,10 @@  public:
 
     version (CoreUnittest) unittest
     {
-        foreach (D; AliasSeq!(Duration, const Duration, immutable Duration))
+        alias Types = AliasSeq!(Duration, const Duration, immutable Duration);
+        foreach (D; Types)
         {
-            foreach (E; AliasSeq!(Duration, const Duration, immutable Duration))
+            foreach (E; Types)
             {
                 assert((cast(D)Duration(5)) + (cast(E)Duration(7)) == Duration(12));
                 assert((cast(D)Duration(5)) - (cast(E)Duration(7)) == Duration(-2));
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index 9bc929ce8ef..565f6a1b15c 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -3191,6 +3191,10 @@  auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
         sum += v;
 
     assert(sum == 3);
+
+    foreach (ref v; dict.byValue)
+        v++;
+    assert(dict == ["k1": 2, "k2": 3]);
 }
 
 /***********************************
@@ -3214,7 +3218,7 @@  auto byValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
  *---
  *
  * Note that this is a low-level interface to iterating over the associative
- * array and is not compatible withth the
+ * array and is not compatible with the
  * $(LINK2 $(ROOT_DIR)phobos/std_typecons.html#.Tuple,`Tuple`) type in Phobos.
  * For compatibility with `Tuple`, use
  * $(LINK2 $(ROOT_DIR)phobos/std_array.html#.byPair,std.array.byPair) instead.
@@ -3278,8 +3282,11 @@  auto byKeyValue(T : V[K], K, V)(T* aa) pure nothrow @nogc
         assert(e.key[1] == e.value + '0');
         sum += e.value;
     }
-
     assert(sum == 3);
+
+    foreach (e; dict.byKeyValue)
+        e.value++;
+    assert(dict == ["k1": 2, "k2": 3]);
 }
 
 /***********************************
@@ -3451,8 +3458,8 @@  Value[] values(T : Value[Key], Value, Key)(T *aa) @property
 }
 
 /***********************************
- * Looks up key; if it exists returns corresponding value else evaluates and
- * returns defaultValue.
+ * If `key` is in `aa`, returns corresponding value; otherwise it evaluates and
+ * returns `defaultValue`.
  * Params:
  *      aa =     The associative array.
  *      key =    The key.
@@ -3481,8 +3488,8 @@  inout(V) get(K, V)(inout(V[K])* aa, K key, lazy inout(V) defaultValue)
 }
 
 /***********************************
- * Looks up key; if it exists returns corresponding value else evaluates
- * value, adds it to the associative array and returns it.
+ * If `key` is in `aa`, returns corresponding value; otherwise it evaluates
+ * `value`, adds it to the associative array and returns it.
  * Params:
  *      aa =     The associative array.
  *      key =    The key.
diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d
index 26c16d3af0a..2bddeaf41d7 100644
--- a/libphobos/libdruntime/rt/aaA.d
+++ b/libphobos/libdruntime/rt/aaA.d
@@ -343,11 +343,11 @@  immutable(void)* rtinfoEntry(ref Impl aa, immutable(size_t)* keyinfo,
             pos++;
         }
         if (keybits > 0)
-            rtinfoData[pos] = mixin(src) & ((cast(size_t) 1 << keybits) - 1);
+            rtinfoData[pos] = mixin(src) & ((size_t(1) << keybits) - 1);
     }
 
     if (keyinfo is rtinfoHasPointers)
-        copyKeyInfo!"~cast(size_t) 0"();
+        copyKeyInfo!"~size_t(0)"();
     else if (keyinfo !is rtinfoNoPointers)
         copyKeyInfo!"keyinfo[pos]"();
 
@@ -373,11 +373,11 @@  immutable(void)* rtinfoEntry(ref Impl aa, immutable(size_t)* keyinfo,
             pos++;
         }
         if (endoff > 0)
-            rtinfoData[dstpos] &= ((cast(size_t) 1 << endoff) - 1);
+            rtinfoData[dstpos] &= (size_t(1) << endoff) - 1;
     }
 
     if (valinfo is rtinfoHasPointers)
-        copyValInfo!"~cast(size_t) 0"();
+        copyValInfo!"~size_t(0)"();
     else if (valinfo !is rtinfoNoPointers)
         copyValInfo!"valinfo[pos]"();
 
@@ -977,7 +977,7 @@  unittest
     aa1 = null;
     aa2 = null;
     aa3 = null;
-    GC.runFinalizers((cast(char*)(&entryDtor))[0 .. 1]);
+    GC.runFinalizers((cast(char*)&entryDtor)[0 .. 1]);
     assert(T.dtor == 6 && T.postblit == 2);
 }
 
diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d
index 43ddd5a9316..c7d8bbaab35 100644
--- a/libphobos/libdruntime/rt/cast_.d
+++ b/libphobos/libdruntime/rt/cast_.d
@@ -167,7 +167,7 @@  void* _d_paint_cast(Object o, ClassInfo c)
 {
     /* If o is really an instance of c, just do a paint
      */
-    auto p = (o && cast(void*)(areClassInfosEqual(typeid(o), c)) ? o : null);
+    auto p = o && cast(void*)(areClassInfosEqual(typeid(o), c)) ? o : null;
     debug assert(cast(void*)p is cast(void*)_d_dynamic_cast(o, c));
     return cast(void*)p;
 }
diff --git a/libphobos/libdruntime/rt/config.d b/libphobos/libdruntime/rt/config.d
index a6605f4d603..912b8fe36ad 100644
--- a/libphobos/libdruntime/rt/config.d
+++ b/libphobos/libdruntime/rt/config.d
@@ -129,8 +129,7 @@  string rt_envvarsOption(string opt, scope rt_configCallBack dg) @nogc nothrow
             var[4 + i] = cast(char) toupper(c);
         var[4 + opt.length] = 0;
 
-        auto p = getenv(var.ptr);
-        if (p)
+        if (auto p = getenv(var.ptr))
         {
             string s = dg(cast(string) p[0 .. strlen(p)]);
             if (s != null)
diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d
index 052b859fd49..be416c47906 100644
--- a/libphobos/libdruntime/rt/dmain2.d
+++ b/libphobos/libdruntime/rt/dmain2.d
@@ -607,7 +607,7 @@  extern (C) void _d_print_throwable(Throwable t)
             void sink(in char[] s) scope nothrow
             {
                 if (!s.length) return;
-                int swlen = MultiByteToWideChar(
+                const swlen = MultiByteToWideChar(
                         CP_UTF8, 0, s.ptr, cast(int)s.length, null, 0);
                 if (!swlen) return;
 
@@ -615,7 +615,7 @@  extern (C) void _d_print_throwable(Throwable t)
                         (this.len + swlen + 1) * WCHAR.sizeof);
                 if (!newPtr) return;
                 ptr = newPtr;
-                auto written = MultiByteToWideChar(
+                const written = MultiByteToWideChar(
                         CP_UTF8, 0, s.ptr, cast(int)s.length, ptr+len, swlen);
                 len += written;
             }
@@ -633,10 +633,6 @@  extern (C) void _d_print_throwable(Throwable t)
                 return _fdToHandle(fd);
         }
 
-        auto hStdErr = windowsHandle(fileno(stderr));
-        CONSOLE_SCREEN_BUFFER_INFO sbi;
-        bool isConsole = GetConsoleScreenBufferInfo(hStdErr, &sbi) != 0;
-
         // ensure the exception is shown at the beginning of the line, while also
         // checking whether stderr is a valid file
         int written = fprintf(stderr, "\n");
@@ -653,22 +649,22 @@  extern (C) void _d_print_throwable(Throwable t)
 
                 // Avoid static user32.dll dependency for console applications
                 // by loading it dynamically as needed
-                auto user32 = LoadLibraryW("user32.dll");
-                if (user32)
+                if (auto user32 = LoadLibraryW("user32.dll"))
                 {
                     alias typeof(&MessageBoxW) PMessageBoxW;
-                    auto pMessageBoxW = cast(PMessageBoxW)
-                        GetProcAddress(user32, "MessageBoxW");
-                    if (pMessageBoxW)
+                    if (auto pMessageBoxW = cast(PMessageBoxW) GetProcAddress(user32, "MessageBoxW"))
                         pMessageBoxW(null, buf.get(), caption.get(), MB_ICONERROR);
+                    FreeLibrary(user32);
                 }
-                FreeLibrary(user32);
                 caption.free();
                 buf.free();
             }
             return;
         }
-        else if (isConsole)
+        auto hStdErr = windowsHandle(fileno(stderr));
+        CONSOLE_SCREEN_BUFFER_INFO sbi = void;
+        const isConsole = GetConsoleScreenBufferInfo(hStdErr, &sbi) != 0;
+        if (isConsole)
         {
             WSink buf;
             formatThrowable(t, &buf.sink);
@@ -676,10 +672,9 @@  extern (C) void _d_print_throwable(Throwable t)
             if (buf.ptr)
             {
                 uint codepage = GetConsoleOutputCP();
-                int slen = WideCharToMultiByte(codepage, 0,
+                const slen = WideCharToMultiByte(codepage, 0,
                         buf.ptr, cast(int)buf.len, null, 0, null, null);
-                auto sptr = cast(char*)malloc(slen * char.sizeof);
-                if (sptr)
+                if (auto sptr = cast(char*)malloc(slen * char.sizeof))
                 {
                     WideCharToMultiByte(codepage, 0,
                         buf.ptr, cast(int)buf.len, sptr, slen, null, null);
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 676f88d5ae4..a8d084060cf 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -1941,15 +1941,15 @@  byte[] _d_arrayappendcTX(const TypeInfo ti, return scope ref byte[] px, size_t n
         __setArrayAllocLength(info, newsize, isshared, tinext);
         if (!isshared)
             __insertBlkInfoCache(info, bic);
-        auto newdata = cast(byte *)__arrayStart(info);
+        auto newdata = cast(byte*)__arrayStart(info);
         memcpy(newdata, px.ptr, length * sizeelem);
         // do postblit processing
         __doPostblit(newdata, length * sizeelem, tinext);
-        (cast(void **)(&px))[1] = newdata;
+        (cast(void**)&px)[1] = newdata;
     }
 
   L1:
-    *cast(size_t *)&px = newlength;
+    *cast(size_t*)&px = newlength;
     return px;
 }
 
@@ -2417,14 +2417,14 @@  deprecated unittest
     // associative arrays
     import rt.aaA : entryDtor;
     // throw away all existing AA entries with dtor
-    GC.runFinalizers((cast(char*)(&entryDtor))[0..1]);
+    GC.runFinalizers((cast(char*)&entryDtor)[0..1]);
 
     S1[int] aa1;
     aa1[0] = S1(0);
     aa1[1] = S1(1);
     dtorCount = 0;
     aa1 = null;
-    GC.runFinalizers((cast(char*)(&entryDtor))[0..1]);
+    GC.runFinalizers((cast(char*)&entryDtor)[0..1]);
     assert(dtorCount == 2);
 
     int[S1] aa2;
@@ -2433,7 +2433,7 @@  deprecated unittest
     aa2[S1(2)] = 2;
     dtorCount = 0;
     aa2 = null;
-    GC.runFinalizers((cast(char*)(&entryDtor))[0..1]);
+    GC.runFinalizers((cast(char*)&entryDtor)[0..1]);
     assert(dtorCount == 3);
 
     S1[2][int] aa3;
@@ -2441,7 +2441,7 @@  deprecated unittest
     aa3[1] = [S1(1),S1(3)];
     dtorCount = 0;
     aa3 = null;
-    GC.runFinalizers((cast(char*)(&entryDtor))[0..1]);
+    GC.runFinalizers((cast(char*)&entryDtor)[0..1]);
     assert(dtorCount == 4);
 }
 
diff --git a/libphobos/libdruntime/rt/monitor_.d b/libphobos/libdruntime/rt/monitor_.d
index cbe2a484402..3a9c1f7cc2e 100644
--- a/libphobos/libdruntime/rt/monitor_.d
+++ b/libphobos/libdruntime/rt/monitor_.d
@@ -27,7 +27,7 @@  do
     auto m = ensureMonitor(cast(Object) owner);
     if (m.impl is null)
     {
-        atomicOp!("+=")(m.refs, cast(size_t) 1);
+        atomicOp!"+="(m.refs, size_t(1));
     }
     // Assume the monitor is garbage collected and simply copy the reference.
     ownee.__monitor = owner.__monitor;
@@ -44,7 +44,7 @@  extern (C) void _d_monitordelete(Object h, bool det)
         // let the GC collect the monitor
         setMonitor(h, null);
     }
-    else if (!atomicOp!("-=")(m.refs, cast(size_t) 1))
+    else if (!atomicOp!"-="(m.refs, size_t(1)))
     {
         // refcount == 0 means unshared => no synchronization required
         disposeEvent(cast(Monitor*) m, h);
@@ -65,7 +65,7 @@  extern (C) void _d_monitordelete_nogc(Object h) @nogc nothrow
         // let the GC collect the monitor
         setMonitor(h, null);
     }
-    else if (!atomicOp!("-=")(m.refs, cast(size_t) 1))
+    else if (!atomicOp!"-="(m.refs, size_t(1)))
     {
         // refcount == 0 means unshared => no synchronization required
         deleteMonitor(cast(Monitor*) m);
@@ -231,7 +231,7 @@  private:
     return *cast(shared Monitor**)&h.__monitor;
 }
 
-private shared(Monitor)* getMonitor(Object h) pure @nogc
+shared(Monitor)* getMonitor(Object h) pure @nogc
 {
     return atomicLoad!(MemoryOrder.acq)(h.monitor);
 }
diff --git a/libphobos/libdruntime/rt/util/typeinfo.d b/libphobos/libdruntime/rt/util/typeinfo.d
index 730649ef481..9c5af477cbb 100644
--- a/libphobos/libdruntime/rt/util/typeinfo.d
+++ b/libphobos/libdruntime/rt/util/typeinfo.d
@@ -203,10 +203,10 @@  detect if we need to override. The overriding initializer should be nonzero.
 private class TypeInfoGeneric(T, Base = T) : Select!(is(T == Base), TypeInfo, TypeInfoGeneric!Base)
 if (T.sizeof == Base.sizeof && T.alignof == Base.alignof)
 {
-    const: nothrow: pure: @trusted:
+    const: nothrow pure @trusted:
 
     // Returns the type name.
-    override string toString() const pure nothrow @safe { return T.stringof; }
+    override string toString() const @safe { return T.stringof; }
 
     // `getHash` is the same for `Base` and `T`, introduce it just once.
     static if (is(T == Base))
@@ -390,16 +390,16 @@  unittest
 // void
 class TypeInfo_v : TypeInfoGeneric!ubyte
 {
-    const: nothrow: pure: @trusted:
+    const nothrow pure @trusted:
 
-    override string toString() const pure nothrow @safe { return "void"; }
+    override string toString() const @safe { return "void"; }
 
     override size_t getHash(scope const void* p)
     {
         assert(0);
     }
 
-    override @property uint flags() nothrow pure
+    override @property uint flags()
     {
         return 1;
     }
@@ -640,7 +640,7 @@  class TypeInfo_n : TypeInfo
 
     override @property size_t tsize() { return typeof(null).sizeof; }
 
-    override const(void)[] initializer() @trusted { return (cast(void *)null)[0 .. size_t.sizeof]; }
+    override const(void)[] initializer() @trusted { return (cast(void*)null)[0 .. size_t.sizeof]; }
 
     override void swap(void*, void*) {}
 
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 46e244379e1..76975e01c29 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-0c28620c301c9ae3136b1e1e5af55c290dbc7aae
+ebd24da8add9243c52e5cb346dcdf7acf3e6cbac
 
 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/mutation.d b/libphobos/src/std/algorithm/mutation.d
index fbef28e5d56..e434d248edb 100644
--- a/libphobos/src/std/algorithm/mutation.d
+++ b/libphobos/src/std/algorithm/mutation.d
@@ -1071,10 +1071,20 @@  Params:
         copy is performed.
 */
 void move(T)(ref T source, ref T target)
+if (__traits(compiles, target = T.init))
 {
     moveImpl(target, source);
 }
 
+/// ditto
+template move(T)
+if (!__traits(compiles, imported!"std.traits".lvalueOf!T = T.init))
+{
+    ///
+    deprecated("Can't move into `target` as `" ~ T.stringof ~ "` can't be assigned")
+    void move(ref T source, ref T target) => moveImpl(target, source);
+}
+
 /// For non-struct types, `move` just performs `target = source`:
 @safe unittest
 {
@@ -1184,6 +1194,19 @@  pure nothrow @safe @nogc unittest
     assert(s53 is s51);
 }
 
+@system unittest
+{
+    static struct S
+    {
+        immutable int i;
+        ~this() @safe {}
+    }
+    alias ol = __traits(getOverloads, std.algorithm.mutation, "move", true)[1];
+    static assert(__traits(isDeprecated, ol!S));
+    // uncomment after deprecation
+    //static assert(!__traits(compiles, { S a, b; move(a, b); }));
+}
+
 /// Ditto
 T move(T)(return scope ref T source)
 {
diff --git a/libphobos/src/std/algorithm/sorting.d b/libphobos/src/std/algorithm/sorting.d
index c5b085d1037..2d16c65111f 100644
--- a/libphobos/src/std/algorithm/sorting.d
+++ b/libphobos/src/std/algorithm/sorting.d
@@ -2164,12 +2164,12 @@  private void quickSortImpl(alias less, Range)(Range r, size_t depth)
 {
     import std.algorithm.comparison : min, max;
     import std.algorithm.mutation : swap, swapAt;
-    import std.conv : to;
 
     alias Elem = ElementType!(Range);
-    enum size_t shortSortGetsBetter = max(32, 1024 / Elem.sizeof);
+    enum int size = Elem.sizeof;
+    enum size_t shortSortGetsBetter = max(32, 1024 / size);
     static assert(shortSortGetsBetter >= 1, Elem.stringof ~ " "
-        ~ to!string(Elem.sizeof));
+        ~ size.stringof);
 
     // partition
     while (r.length > shortSortGetsBetter)
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index 494fa297b4b..1ce4a648777 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -295,6 +295,19 @@  if (is(Range == U*, U) && isIterable!U && !isAutodecodableString!Range && !isInf
     R().array;
 }
 
+// Test that `array(scope InputRange r)` returns a non-scope array
+// https://issues.dlang.org/show_bug.cgi?id=23300
+@safe pure nothrow unittest
+{
+    @safe int[] fun()
+    {
+        import std.algorithm.iteration : map;
+        int[3] arr = [1, 2, 3];
+        scope r = arr[].map!(x => x + 3);
+        return r.array;
+    }
+}
+
 /**
 Convert a narrow autodecoding string to an array type that fully supports
 random access.  This is handled as a special case and always returns an array
@@ -650,6 +663,8 @@  if (isInputRange!Values && isInputRange!Keys)
                 alias ValueElement = ElementType!Values;
                 static if (hasElaborateDestructor!ValueElement)
                     ValueElement.init.__xdtor();
+
+                aa[key] = values.front;
             })))
             {
                 () @trusted {
@@ -790,6 +805,20 @@  if (isInputRange!Values && isInputRange!Keys)
     assert(assocArray(1.iota, [UnsafeElement()]) == [0: UnsafeElement()]);
 }
 
+@safe unittest
+{
+    struct ValueRange
+    {
+        string front() const @system;
+        @safe:
+        void popFront() {}
+        bool empty() const { return false; }
+    }
+    int[] keys;
+    ValueRange values;
+    static assert(!__traits(compiles, assocArray(keys, values)));
+}
+
 /**
 Construct a range iterating over an associative array by key/value tuples.
 
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index 639b8214c8c..0993d34843f 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -1306,7 +1306,7 @@  public:
 
     /**
       Sets the bits of a slice of `BitArray` starting
-      at index `start` and ends at index ($D end - 1)
+      at index `start` and ends at index $(D end - 1)
       with the values specified by `val`.
      */
     void opSliceAssign(bool val, size_t start, size_t end) @nogc pure nothrow
diff --git a/libphobos/src/std/datetime/date.d b/libphobos/src/std/datetime/date.d
index ebdaba42a9d..7526f2d7bb4 100644
--- a/libphobos/src/std/datetime/date.d
+++ b/libphobos/src/std/datetime/date.d
@@ -3776,7 +3776,7 @@  public:
         enforceValid!"months"(cast(Month) month);
         enforceValid!"days"(year, cast(Month) month, day);
 
-        _year  = cast(short) year;
+        _year  = year.castToYear;
         _month = cast(Month) month;
         _day   = cast(ubyte) day;
     }
@@ -3814,6 +3814,7 @@  public:
         assertThrown!DateTimeException(Date(1999, 10, 32));
         assertThrown!DateTimeException(Date(1999, 11, 31));
         assertThrown!DateTimeException(Date(1999, 12, 32));
+        assertThrown!DateTimeException(Date(short.max+1, 1, 1));
 
         assertNotThrown!DateTimeException(Date(1999, 1, 31));
         assertNotThrown!DateTimeException(Date(1999, 2, 28));
@@ -3839,6 +3840,7 @@  public:
         assertThrown!DateTimeException(Date(-1, 2, 29));
         assertThrown!DateTimeException(Date(-2, 2, 29));
         assertThrown!DateTimeException(Date(-3, 2, 29));
+        assertThrown!DateTimeException(Date(short.min-1, 1, 1));
     }
 
 
@@ -4128,7 +4130,7 @@  public:
     @property void year(int year) @safe pure
     {
         enforceValid!"days"(year, _month, _day);
-        _year = cast(short) year;
+        _year = year.castToYear;
     }
 
     ///
@@ -4215,7 +4217,7 @@  public:
     {
         if (year <= 0)
             throw new DateTimeException("The given year is not a year B.C.");
-        _year = cast(short)((year - 1) * -1);
+        _year = castToYear((year - 1) * -1);
     }
 
     ///
@@ -9689,6 +9691,16 @@  if (units == "days")
     assert(!valid!"days"(2017, 2, 29));
 }
 
+private short castToYear(int year, string file = __FILE__, size_t line = __LINE__) @safe pure
+{
+    import std.conv : to, ConvOverflowException;
+    import std.format : format;
+
+    try
+        return year.to!short;
+    catch (ConvOverflowException)
+        throw new DateTimeException(format("year %s doesn't fit to Date.", year), file, line);
+}
 
 /++
     Params:
diff --git a/libphobos/src/std/datetime/timezone.d b/libphobos/src/std/datetime/timezone.d
index b23891808f5..4b6f27d066d 100644
--- a/libphobos/src/std/datetime/timezone.d
+++ b/libphobos/src/std/datetime/timezone.d
@@ -3339,7 +3339,7 @@  else version (Posix)
     Windows uses a different set of time zone names than the IANA time zone
     database does, and how they correspond to one another changes over time
     (particularly when Microsoft updates Windows).
-    $(HTTP unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml)
+    $(HTTP github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml, windowsZones.xml)
     provides the current conversions (which may or may not match up with what's
     on a particular Windows box depending on how up-to-date it is), and
     parseTZConversions reads in those conversions from windowsZones.xml so that
@@ -3358,7 +3358,7 @@  else version (Posix)
 
     Params:
         windowsZonesXMLText = The text from
-        $(HTTP unicode.org/cldr/data/common/supplemental/windowsZones.xml, windowsZones.xml)
+        $(HTTP github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml, windowsZones.xml)
 
     Throws:
         Exception if there is an error while parsing the given XML.
@@ -3372,7 +3372,7 @@  else version (Posix)
     // and parse it so that it's guaranteed to be up-to-date, though
     // that has the downside that the code needs to worry about the
     // site being down or unicode.org changing the URL.
-    auto url = "http://unicode.org/cldr/data/common/supplemental/windowsZones.xml";
+    auto url = "https://raw.githubusercontent.com/unicode-org/cldr/main/common/supplemental/windowsZones.xml";
     auto conversions2 = parseTZConversions(std.net.curl.get(url));
 --------------------
   +/
@@ -3458,7 +3458,7 @@  TZConversions parseTZConversions(string windowsZonesXMLText) @safe pure
     import std.algorithm.iteration : uniq;
     import std.algorithm.sorting : isSorted;
 
-    // Reduced text from http://unicode.org/cldr/data/common/supplemental/windowsZones.xml
+    // Reduced text from https://github.com/unicode-org/cldr/blob/main/common/supplemental/windowsZones.xml
     auto sampleFileText =
 `<?xml version="1.0" encoding="UTF-8" ?>
 <!DOCTYPE supplementalData SYSTEM "../../common/dtd/ldmlSupplemental.dtd">
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index 58a667c1d85..c3024d79968 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -1540,9 +1540,9 @@  version (StdUnittest)
 }
 
 /+
-Returns true if the field at index `i` in ($D T) shares its address with another field.
+Returns true if the field at index `i` in $(D T) shares its address with another field.
 
-Note: This does not merelly check if the field is a member of an union, but also that
+Note: This does not merely check if the field is a member of an union, but also that
 it is not a single child.
 +/
 package enum isUnionAliased(T, size_t i) = isUnionAliasedImpl!T(T.tupleof[i].offsetof);
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/package.d b/libphobos/src/std/experimental/allocator/building_blocks/package.d
index 6bc527d2374..521d7ed0a47 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/package.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/package.d
@@ -43,7 +43,7 @@  alignedReallocate) APIs.))
 $(TR $(TDC size_t goodAllocSize(size_t n);, $(POST $(RES) >= n)) $(TD Allocators
 customarily allocate memory in discretely-sized chunks. Therefore, a request for
 `n` bytes may result in a larger allocation. The extra memory allocated goes
-unused and adds to the so-called $(HTTP goo.gl/YoKffF,internal fragmentation).
+unused and adds to the so-called $(HTTPS en.wikipedia.org/wiki/Fragmentation_(computing)#Internal_fragmentation,internal fragmentation).
 The function `goodAllocSize(n)` returns the actual number of bytes that would
 be allocated upon a request for `n` bytes. This module defines a default
 implementation that returns `n` rounded up to a multiple of the allocator's
@@ -137,7 +137,7 @@  thread-safe or not, this instance may be `shared`.))
 
 $(H2 Sample Assembly)
 
-The example below features an _allocator modeled after $(HTTP goo.gl/m7329l,
+The example below features an _allocator modeled after $(HTTP jemalloc.net/,
 jemalloc), which uses a battery of free-list allocators spaced so as to keep
 internal fragmentation to a minimum. The `FList` definitions specify no
 bounds for the freelist because the `Segregator` does all size selection in
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/region.d b/libphobos/src/std/experimental/allocator/building_blocks/region.d
index a23746a236b..736b1858e43 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/region.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/region.d
@@ -904,7 +904,7 @@  version (DragonFlyBSD)
 {
     // sbrk is deprecated in favor of mmap   (we could implement a mmap + MAP_NORESERVE + PROT_NONE version)
     // brk has been removed
-    // https://www.dragonflydigest.com/2019/02/22/22586.html
+    // https://web.archive.org/web/20221006070113/https://www.dragonflydigest.com/2019/02/22/22586.html
     // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/dc676eaefa61b0f47bbea1c53eab86fd5ccd78c6
     // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/4b5665564ef37dc939a3a9ffbafaab9894c18885
     // http://gitweb.dragonflybsd.org/dragonfly.git/commitdiff/8618d94a0e2ff8303ad93c123a3fa598c26a116e
@@ -968,7 +968,7 @@  version (Posix) struct SbrkRegion(uint minAlign = platformAlignment)
         scope(exit) pthread_mutex_unlock(cast(pthread_mutex_t*) &sbrkMutex) == 0
             || assert(0);
         // Assume sbrk returns the old break. Most online documentation confirms
-        // that, except for http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf,
+        // that, except for https://web.archive.org/web/20171014020821/http://www.inf.udec.cl/~leo/Malloc_tutorial.pdf,
         // which claims the returned value is not portable.
         auto p = sbrk(rounded);
         if (p == cast(void*) -1)
diff --git a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d
index 3770af10ceb..1d1e480ec56 100644
--- a/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d
+++ b/libphobos/src/std/experimental/allocator/building_blocks/stats_collector.d
@@ -134,7 +134,7 @@  enum Options : ulong
     bytesNotMoved = 1u << 17,
     /**
     Measures the sum of extra bytes allocated beyond the bytes requested, i.e.
-    the $(HTTP goo.gl/YoKffF, internal fragmentation). This is the current
+    the $(HTTPS en.wikipedia.org/wiki/Fragmentation_(computing)#Internal_fragmentation, internal fragmentation). This is the current
     effective number of slack bytes, and it goes up and down with time.
     */
     bytesSlack = 1u << 18,
diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d
index 3d4dc9a2c52..087dbec449a 100644
--- a/libphobos/src/std/experimental/allocator/mallocator.d
+++ b/libphobos/src/std/experimental/allocator/mallocator.d
@@ -52,7 +52,7 @@  struct Mallocator
         import core.memory : pureRealloc;
         if (!s)
         {
-            // fuzzy area in the C standard, see http://goo.gl/ZpWeSE
+            // fuzzy area in the C standard, see https://stackoverflow.com/questions/6502077/malloc-and-realloc-functions
             // so just deallocate and nullify the pointer
             deallocate(b);
             b = null;
diff --git a/libphobos/src/std/experimental/allocator/mmap_allocator.d b/libphobos/src/std/experimental/allocator/mmap_allocator.d
index 4151d0e0504..494d5a3b40a 100644
--- a/libphobos/src/std/experimental/allocator/mmap_allocator.d
+++ b/libphobos/src/std/experimental/allocator/mmap_allocator.d
@@ -60,7 +60,7 @@  struct MmapAllocator
             // http://man7.org/linux/man-pages/man2/mmap.2.html
             package alias allocateZeroed = allocate;
         else version (NetBSD)
-            // http://netbsd.gw.com/cgi-bin/man-cgi?mmap+2+NetBSD-current
+            // https://man.netbsd.org/mmap.2
             package alias allocateZeroed = allocate;
         else version (Solaris)
             // https://docs.oracle.com/cd/E88353_01/html/E37841/mmap-2.html
diff --git a/libphobos/src/std/format/internal/read.d b/libphobos/src/std/format/internal/read.d
index 9130499081c..597898c9e23 100644
--- a/libphobos/src/std/format/internal/read.d
+++ b/libphobos/src/std/format/internal/read.d
@@ -161,15 +161,16 @@  if (isInputRange!Range && isSomeChar!T && !is(T == enum) && isSomeChar!(ElementT
     enforceFmt(find(acceptedSpecs!T, spec.spec).length,
                text("Wrong unformat specifier '%", spec.spec , "' for ", T.stringof));
 
-    static if (T.sizeof == 1)
+    enum int size = T.sizeof;
+    static if (size == 1)
         return unformatValue!ubyte(input, spec);
-    else static if (T.sizeof == 2)
+    else static if (size == 2)
         return unformatValue!ushort(input, spec);
-    else static if (T.sizeof == 4)
+    else static if (size == 4)
         return unformatValue!uint(input, spec);
     else
         static assert(false, T.stringof ~ ".sizeof must be 1, 2, or 4 not " ~
-                      to!string(T.sizeof));
+                      size.stringof);
 }
 
 T unformatValueImpl(T, Range, Char)(ref Range input, scope const ref FormatSpec!Char fmt)
diff --git a/libphobos/src/std/format/package.d b/libphobos/src/std/format/package.d
index f1d47055836..a78e1b3d0dc 100644
--- a/libphobos/src/std/format/package.d
+++ b/libphobos/src/std/format/package.d
@@ -358,7 +358,7 @@  $(BOOKTABLE ,
                  Default precision is large enough to add all digits
                  of the integral value.
 
-                 In case of ($B 'a') and $(B 'A'), the integral digit can be
+                 In case of $(B 'a') and $(B 'A'), the integral digit can be
                  any hexadecimal digit.
                )
    )
diff --git a/libphobos/src/std/json.d b/libphobos/src/std/json.d
index 6e94a5d71ce..9dcec89b2ce 100644
--- a/libphobos/src/std/json.d
+++ b/libphobos/src/std/json.d
@@ -13,7 +13,7 @@  also $(LINK https://forum.dlang.org/post/dzfyaxypmkdrpakmycjv@forum.dlang.org).)
 Copyright: Copyright Jeremie Pelletier 2008 - 2009.
 License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
 Authors:   Jeremie Pelletier, David Herberth
-References: $(LINK http://json.org/), $(LINK http://seriot.ch/parsing_json.html)
+References: $(LINK http://json.org/), $(LINK https://seriot.ch/projects/parsing_json.html)
 Source:    $(PHOBOSSRC std/json.d)
 */
 /*
@@ -804,7 +804,22 @@  struct JSONValue
         assert(j["author"].str == "Walter");
     }
 
-    ///
+    /**
+     * Compare two JSONValues for equality
+     *
+     * JSON arrays and objects are compared deeply. The order of object keys does not matter.
+     *
+     * Floating point numbers are compared for exact equality, not approximal equality.
+     *
+     * Different number types (unsigned, signed, and floating) will be compared by converting
+     * them to a common type, in the same way that comparison of built-in D `int`, `uint` and
+     * `float` works.
+     *
+     * Other than that, types must match exactly.
+     * Empty arrays are not equal to empty objects, and booleans are never equal to integers.
+     *
+     * Returns: whether this `JSONValue` is equal to `rhs`
+     */
     bool opEquals(const JSONValue rhs) const @nogc nothrow pure @safe
     {
         return opEquals(rhs);
@@ -871,9 +886,13 @@  struct JSONValue
     ///
     @safe unittest
     {
-        assert(JSONValue(0u) == JSONValue(0));
-        assert(JSONValue(0u) == JSONValue(0.0));
-        assert(JSONValue(0) == JSONValue(0.0));
+        assert(JSONValue(10).opEquals(JSONValue(10.0)));
+        assert(JSONValue(10) != (JSONValue(10.5)));
+
+        assert(JSONValue(1) != JSONValue(true));
+        assert(JSONValue.emptyArray != JSONValue.emptyObject);
+
+        assert(parseJSON(`{"a": 1, "b": 2}`).opEquals(parseJSON(`{"b": 2, "a": 1}`)));
     }
 
     /// Implements the foreach `opApply` interface for json arrays.
diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d
index 8fcd88f4c68..7a72f428cd7 100644
--- a/libphobos/src/std/math/exponential.d
+++ b/libphobos/src/std/math/exponential.d
@@ -422,217 +422,7 @@  if (isIntegral!I && isFloatingPoint!F)
 Unqual!(Largest!(F, G)) pow(F, G)(F x, G y) @nogc @trusted pure nothrow
 if (isFloatingPoint!(F) && isFloatingPoint!(G))
 {
-    import core.math : fabs, sqrt;
-    import std.math.traits : isInfinity, isNaN, signbit;
-
-    alias Float = typeof(return);
-
-    static real impl(real x, real y) @nogc pure nothrow
-    {
-        // Special cases.
-        if (isNaN(y))
-            return y;
-        if (isNaN(x) && y != 0.0)
-            return x;
-
-        // Even if x is NaN.
-        if (y == 0.0)
-            return 1.0;
-        if (y == 1.0)
-            return x;
-
-        if (isInfinity(y))
-        {
-            if (isInfinity(x))
-            {
-                if (!signbit(y) && !signbit(x))
-                    return F.infinity;
-                else
-                    return F.nan;
-            }
-            else if (fabs(x) > 1)
-            {
-                if (signbit(y))
-                    return +0.0;
-                else
-                    return F.infinity;
-            }
-            else if (fabs(x) == 1)
-            {
-                return F.nan;
-            }
-            else // < 1
-            {
-                if (signbit(y))
-                    return F.infinity;
-                else
-                    return +0.0;
-            }
-        }
-        if (isInfinity(x))
-        {
-            if (signbit(x))
-            {
-                long i = cast(long) y;
-                if (y > 0.0)
-                {
-                    if (i == y && i & 1)
-                        return -F.infinity;
-                    else if (i == y)
-                        return F.infinity;
-                    else
-                        return -F.nan;
-                }
-                else if (y < 0.0)
-                {
-                    if (i == y && i & 1)
-                        return -0.0;
-                    else if (i == y)
-                        return +0.0;
-                    else
-                        return F.nan;
-                }
-            }
-            else
-            {
-                if (y > 0.0)
-                    return F.infinity;
-                else if (y < 0.0)
-                    return +0.0;
-            }
-        }
-
-        if (x == 0.0)
-        {
-            if (signbit(x))
-            {
-                long i = cast(long) y;
-                if (y > 0.0)
-                {
-                    if (i == y && i & 1)
-                        return -0.0;
-                    else
-                        return +0.0;
-                }
-                else if (y < 0.0)
-                {
-                    if (i == y && i & 1)
-                        return -F.infinity;
-                    else
-                        return F.infinity;
-                }
-            }
-            else
-            {
-                if (y > 0.0)
-                    return +0.0;
-                else if (y < 0.0)
-                    return F.infinity;
-            }
-        }
-        if (x == 1.0)
-            return 1.0;
-
-        if (y >= F.max)
-        {
-            if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
-                return 0.0;
-            if (x > 1.0 || x < -1.0)
-                return F.infinity;
-        }
-        if (y <= -F.max)
-        {
-            if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
-                return F.infinity;
-            if (x > 1.0 || x < -1.0)
-                return 0.0;
-        }
-
-        if (x >= F.max)
-        {
-            if (y > 0.0)
-                return F.infinity;
-            else
-                return 0.0;
-        }
-        if (x <= -F.max)
-        {
-            long i = cast(long) y;
-            if (y > 0.0)
-            {
-                if (i == y && i & 1)
-                    return -F.infinity;
-                else
-                    return F.infinity;
-            }
-            else if (y < 0.0)
-            {
-                if (i == y && i & 1)
-                    return -0.0;
-                else
-                    return +0.0;
-            }
-        }
-
-        // Integer power of x.
-        long iy = cast(long) y;
-        if (iy == y && fabs(y) < 32_768.0)
-            return pow(x, iy);
-
-        real sign = 1.0;
-        if (x < 0)
-        {
-            // Result is real only if y is an integer
-            // Check for a non-zero fractional part
-            enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L;
-            static if (maxOdd > ulong.max)
-            {
-                // Generic method, for any FP type
-                import std.math.rounding : floor;
-                if (floor(y) != y)
-                    return sqrt(x); // Complex result -- create a NaN
-
-                const hy = 0.5 * y;
-                if (floor(hy) != hy)
-                    sign = -1.0;
-            }
-            else
-            {
-                // Much faster, if ulong has enough precision
-                const absY = fabs(y);
-                if (absY <= maxOdd)
-                {
-                    const uy = cast(ulong) absY;
-                    if (uy != absY)
-                        return sqrt(x); // Complex result -- create a NaN
-
-                    if (uy & 1)
-                        sign = -1.0;
-                }
-            }
-            x = -x;
-        }
-        version (INLINE_YL2X)
-        {
-            // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
-            // TODO: This is not accurate in practice. A fast and accurate
-            // (though complicated) method is described in:
-            // "An efficient rounding boundary test for pow(x, y)
-            // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
-            return sign * exp2( core.math.yl2x(x, y) );
-        }
-        else
-        {
-            // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
-            // TODO: This is not accurate in practice. A fast and accurate
-            // (though complicated) method is described in:
-            // "An efficient rounding boundary test for pow(x, y)
-            // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
-            Float w = exp2(y * log2(x));
-            return sign * w;
-        }
-    }
-    return impl(x, y);
+    return _powImpl(x, y);
 }
 
 ///
@@ -802,6 +592,216 @@  if (isFloatingPoint!(F) && isFloatingPoint!(G))
     assert(pow(-real.infinity, 0.0) == 1.0);
 }
 
+private real _powImpl(real x, real y) @safe @nogc pure nothrow
+{
+    alias F = real;
+    import core.math : fabs, sqrt;
+    import std.math.traits : isInfinity, isNaN, signbit;
+
+    // Special cases.
+    if (isNaN(y))
+        return y;
+    if (isNaN(x) && y != 0.0)
+        return x;
+
+    // Even if x is NaN.
+    if (y == 0.0)
+        return 1.0;
+    if (y == 1.0)
+        return x;
+
+    if (isInfinity(y))
+    {
+        if (isInfinity(x))
+        {
+            if (!signbit(y) && !signbit(x))
+                return F.infinity;
+            else
+                return F.nan;
+        }
+        else if (fabs(x) > 1)
+        {
+            if (signbit(y))
+                return +0.0;
+            else
+                return F.infinity;
+        }
+        else if (fabs(x) == 1)
+        {
+            return F.nan;
+        }
+        else // < 1
+        {
+            if (signbit(y))
+                return F.infinity;
+            else
+                return +0.0;
+        }
+    }
+    if (isInfinity(x))
+    {
+        if (signbit(x))
+        {
+            long i = cast(long) y;
+            if (y > 0.0)
+            {
+                if (i == y && i & 1)
+                    return -F.infinity;
+                else if (i == y)
+                    return F.infinity;
+                else
+                    return -F.nan;
+            }
+            else if (y < 0.0)
+            {
+                if (i == y && i & 1)
+                    return -0.0;
+                else if (i == y)
+                    return +0.0;
+                else
+                    return F.nan;
+            }
+        }
+        else
+        {
+            if (y > 0.0)
+                return F.infinity;
+            else if (y < 0.0)
+                return +0.0;
+        }
+    }
+
+    if (x == 0.0)
+    {
+        if (signbit(x))
+        {
+            long i = cast(long) y;
+            if (y > 0.0)
+            {
+                if (i == y && i & 1)
+                    return -0.0;
+                else
+                    return +0.0;
+            }
+            else if (y < 0.0)
+            {
+                if (i == y && i & 1)
+                    return -F.infinity;
+                else
+                    return F.infinity;
+            }
+        }
+        else
+        {
+            if (y > 0.0)
+                return +0.0;
+            else if (y < 0.0)
+                return F.infinity;
+        }
+    }
+    if (x == 1.0)
+        return 1.0;
+
+    if (y >= F.max)
+    {
+        if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
+            return 0.0;
+        if (x > 1.0 || x < -1.0)
+            return F.infinity;
+    }
+    if (y <= -F.max)
+    {
+        if ((x > 0.0 && x < 1.0) || (x > -1.0 && x < 0.0))
+            return F.infinity;
+        if (x > 1.0 || x < -1.0)
+            return 0.0;
+    }
+
+    if (x >= F.max)
+    {
+        if (y > 0.0)
+            return F.infinity;
+        else
+            return 0.0;
+    }
+    if (x <= -F.max)
+    {
+        long i = cast(long) y;
+        if (y > 0.0)
+        {
+            if (i == y && i & 1)
+                return -F.infinity;
+            else
+                return F.infinity;
+        }
+        else if (y < 0.0)
+        {
+            if (i == y && i & 1)
+                return -0.0;
+            else
+                return +0.0;
+        }
+    }
+
+    // Integer power of x.
+    long iy = cast(long) y;
+    if (iy == y && fabs(y) < 32_768.0)
+        return pow(x, iy);
+
+    real sign = 1.0;
+    if (x < 0)
+    {
+        // Result is real only if y is an integer
+        // Check for a non-zero fractional part
+        enum maxOdd = pow(2.0L, real.mant_dig) - 1.0L;
+        static if (maxOdd > ulong.max)
+        {
+            // Generic method, for any FP type
+            import std.math.rounding : floor;
+            if (floor(y) != y)
+                return sqrt(x); // Complex result -- create a NaN
+
+            const hy = 0.5 * y;
+            if (floor(hy) != hy)
+                sign = -1.0;
+        }
+        else
+        {
+            // Much faster, if ulong has enough precision
+            const absY = fabs(y);
+            if (absY <= maxOdd)
+            {
+                const uy = cast(ulong) absY;
+                if (uy != absY)
+                    return sqrt(x); // Complex result -- create a NaN
+
+                if (uy & 1)
+                    sign = -1.0;
+            }
+        }
+        x = -x;
+    }
+    version (INLINE_YL2X)
+    {
+        // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
+        // TODO: This is not accurate in practice. A fast and accurate
+        // (though complicated) method is described in:
+        // "An efficient rounding boundary test for pow(x, y)
+        // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
+        return sign * exp2( core.math.yl2x(x, y) );
+    }
+    else
+    {
+        // If x > 0, x ^^ y == 2 ^^ ( y * log2(x) )
+        // TODO: This is not accurate in practice. A fast and accurate
+        // (though complicated) method is described in:
+        // "An efficient rounding boundary test for pow(x, y)
+        // in double precision", C.Q. Lauter and V. Lefèvre, INRIA (2007).
+        auto w = exp2(y * log2(x));
+        return sign * w;
+    }
+}
+
 /** Computes the value of a positive integer `x`, raised to the power `n`, modulo `m`.
  *
  *  Params:
diff --git a/libphobos/src/std/numeric.d b/libphobos/src/std/numeric.d
index 648b70eeea8..9f0fb564de3 100644
--- a/libphobos/src/std/numeric.d
+++ b/libphobos/src/std/numeric.d
@@ -3405,7 +3405,7 @@  private:
 
     // This algorithm works by performing the even and odd parts of our FFT
     // using the "two for the price of one" method mentioned at
-    // http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521
+    // https://web.archive.org/web/20180312110051/http://www.engineeringproductivitytools.com/stuff/T0001/PT10.HTM#Head521
     // by making the odd terms into the imaginary components of our new FFT,
     // and then using symmetry to recombine them.
     void fftImplPureReal(Ret, R)(R range, Ret buf) const
diff --git a/libphobos/src/std/outbuffer.d b/libphobos/src/std/outbuffer.d
index 92af9a9a16a..f6d4ba850f3 100644
--- a/libphobos/src/std/outbuffer.d
+++ b/libphobos/src/std/outbuffer.d
@@ -22,9 +22,10 @@  import std.traits : isSomeString;
  * OutBuffer's byte order is the format native to the computer.
  * To control the byte order (endianness), use a class derived
  * from OutBuffer.
+ *
  * OutBuffer's internal buffer is allocated with the GC. Pointers
  * stored into the buffer are scanned by the GC, but you have to
- * ensure proper alignment, e.g. by using alignSize((void*).sizeof).
+ * ensure proper alignment, e.g. by using `alignSize((void*).sizeof)`.
  */
 
 class OutBuffer
@@ -297,7 +298,7 @@  class OutBuffer
      * Append output of C's vprintf() to internal buffer.
      */
 
-    void vprintf(scope string format, va_list args) @trusted nothrow
+    void vprintf(scope string format, va_list args) @system nothrow
     {
         import core.stdc.stdio : vsnprintf;
         import core.stdc.stdlib : alloca;
@@ -342,7 +343,7 @@  class OutBuffer
      * Append output of C's printf() to internal buffer.
      */
 
-    void printf(scope string format, ...) @trusted
+    void printf(scope string format, ...) @system
     {
         va_list ap;
         va_start(ap, format);
@@ -475,7 +476,7 @@  class OutBuffer
     buf.write("hello");
     buf.write(cast(byte) 0x20);
     buf.write("world");
-    buf.printf(" %d", 62665);
+    buf.writef(" %d", 62665);
     assert(cmp(buf.toString(), "hello world 62665") == 0);
 
     buf.clear();
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index fadb4c1759d..7525d9b1491 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -884,11 +884,26 @@  identical to the non-@safe case, but safety introduces some restrictions:
 
 */
 @trusted auto task(F, Args...)(F fun, Args args)
-if (is(typeof(fun(args))) && isSafeTask!F)
+if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F)
 {
     return new Task!(run, F, Args)(fun, args);
 }
 
+@safe unittest
+{
+    static struct Oops {
+        int convert() {
+            *cast(int*) 0xcafebabe = 0xdeadbeef;
+            return 0;
+        }
+        alias convert this;
+    }
+    static void foo(int) @safe {}
+
+    static assert(!__traits(compiles, task(&foo, Oops.init)));
+    static assert(!__traits(compiles, scopedTask(&foo, Oops.init)));
+}
+
 /**
 These functions allow the creation of `Task` objects on the stack rather
 than the GC heap.  The lifetime of a `Task` created by `scopedTask`
@@ -928,7 +943,7 @@  if (is(typeof(delegateOrFp(args))) && !isSafeTask!F)
 
 /// Ditto
 @trusted auto scopedTask(F, Args...)(F fun, Args args)
-if (is(typeof(fun(args))) && isSafeTask!F)
+if (__traits(compiles, () @safe => fun(args)) && isSafeTask!F)
 {
     auto ret = Task!(run, F, Args)(fun, args);
     ret.isScoped = true;
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index b6fddf76559..e2a2d7d2564 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -6070,10 +6070,13 @@  nothrow pure @system unittest
     Generate lockstep's opApply function as a mixin string.
     If withIndex is true prepend a size_t index to the delegate.
 */
-private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
+private struct LockstepMixin(Ranges...)
 {
+    import std.conv : text;
     import std.format : format;
 
+    string name;
+    string implName;
     string[] params;
     string[] emptyChecks;
     string[] dgArgs;
@@ -6081,76 +6084,101 @@  private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
     string indexDef;
     string indexInc;
 
-    if (withIndex)
+@safe pure:
+    this(bool withIndex, bool reverse)
     {
-        params ~= "size_t";
-        dgArgs ~= "index";
-        if (reverse)
+        if (withIndex)
         {
-            indexDef = q{
-                size_t index = ranges[0].length-1;
-                enforce(_stoppingPolicy == StoppingPolicy.requireSameLength,
-                        "lockstep can only be used with foreach_reverse when stoppingPolicy == requireSameLength");
+            params ~= "size_t";
+            dgArgs ~= "index";
+            if (reverse)
+            {
+                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");
 
-                foreach (range; ranges[1..$])
-                    enforce(range.length == ranges[0].length);
-                };
-            indexInc = "--index;";
+                    foreach (range; ranges[1 .. $])
+                        enforce(range.length == ranges[0].length);
+                    };
+                indexInc = "--index;";
+            }
+            else
+            {
+                indexDef = "size_t index = 0;";
+                indexInc = "++index;";
+            }
         }
-        else
+
+        foreach (idx, Range; Ranges)
         {
-            indexDef = "size_t index = 0;";
-            indexInc = "++index;";
+            params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
+            emptyChecks ~= format("!ranges[%s].empty", idx);
+            if (reverse)
+            {
+                dgArgs ~= format("ranges[%s].back", idx);
+                popFronts ~= format("ranges[%s].popBack();", idx);
+            }
+            else
+            {
+                dgArgs ~= format("ranges[%s].front", idx);
+                popFronts ~= format("ranges[%s].popFront();", idx);
+            }
         }
-    }
 
-    foreach (idx, Range; Ranges)
-    {
-        params ~= format("%sElementType!(Ranges[%s])", hasLvalueElements!Range ? "ref " : "", idx);
-        emptyChecks ~= format("!ranges[%s].empty", idx);
         if (reverse)
         {
-            dgArgs ~= format("ranges[%s].back", idx);
-            popFronts ~= format("ranges[%s].popBack();", idx);
+            name = "opApplyReverse";
+            if (withIndex) implName = "opApplyReverseIdxImpl";
+            else           implName = "opApplyReverseImpl";
         }
         else
         {
-            dgArgs ~= format("ranges[%s].front", idx);
-            popFronts ~= format("ranges[%s].popFront();", idx);
+            name = "opApply";
+            if (withIndex) implName = "opApplyIdxImpl";
+            else           implName = "opApplyImpl";
         }
     }
 
-    string name = reverse ? "opApplyReverse" : "opApply";
-
-    return format(
-    q{
-        int %s(scope int delegate(%s) dg)
-        {
-            import std.exception : enforce;
-
-            auto ranges = _ranges;
-            int res;
-            %s
+const:
+    string getAlias()
+    {
+        return format(q{
+            alias %s = %s!(int delegate(%-(%s%|, %)));
+        },
+            name, implName, params
+        );
+    }
 
-            while (%s)
+    string getImpl()
+    {
+        return format(q{
+            int %s(DG)(scope DG dg) scope
             {
-                res = dg(%s);
-                if (res) break;
-                %s
+                import std.exception : enforce;
+
+                auto ranges = this.ranges;
                 %s
-            }
 
-            if (_stoppingPolicy == StoppingPolicy.requireSameLength)
-            {
-                foreach (range; ranges)
-                    enforce(range.empty);
+                while (%-(%s%| && %))
+                {
+                    if (int result = dg(%-(%s%|, %))) return result;
+                    %-(%s%|
+                    %)
+                    %s
+                }
+
+                if (this.stoppingPolicy == StoppingPolicy.requireSameLength)
+                {
+                    foreach (range; ranges)
+                        enforce(range.empty);
+                }
+                return 0;
             }
-            return res;
-        }
-    }, name, params.join(", "), indexDef,
-       emptyChecks.join(" && "), dgArgs.join(", "),
-       popFronts.join("\n                "),
-       indexInc);
+        },
+            implName, indexDef, emptyChecks, dgArgs, popFronts, indexInc
+        );
+    }
 }
 
 /**
@@ -6170,10 +6198,6 @@  private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
 
    By default `StoppingPolicy` is set to `StoppingPolicy.shortest`.
 
-   Limitations: The `pure`, `@safe`, `@nogc`, or `nothrow` attributes cannot be
-   inferred for `lockstep` iteration. $(LREF zip) can infer the first two due to
-   a different implementation.
-
    See_Also: $(LREF zip)
 
        `lockstep` is similar to $(LREF zip), but `zip` bundles its
@@ -6184,41 +6208,53 @@  private string lockstepMixin(Ranges...)(bool withIndex, bool reverse)
 struct Lockstep(Ranges...)
 if (Ranges.length > 1 && allSatisfy!(isInputRange, Ranges))
 {
+    private Ranges ranges;
+    private StoppingPolicy stoppingPolicy;
+
     ///
-    this(R ranges, StoppingPolicy sp = StoppingPolicy.shortest)
+    this(Ranges ranges, StoppingPolicy sp = StoppingPolicy.shortest)
     {
         import std.exception : enforce;
 
-        _ranges = ranges;
+        this.ranges = ranges;
         enforce(sp != StoppingPolicy.longest,
-                "Can't use StoppingPolicy.Longest on Lockstep.");
-        _stoppingPolicy = sp;
+            "Can't use StoppingPolicy.Longest on Lockstep.");
+        this.stoppingPolicy = sp;
     }
 
-    mixin(lockstepMixin!Ranges(false, false));
-    mixin(lockstepMixin!Ranges(true, false));
+    private enum lockstepMixinFF = LockstepMixin!Ranges(withIndex: false, reverse: false);
+    mixin(lockstepMixinFF.getImpl);
+
+    private enum lockstepMixinTF = LockstepMixin!Ranges(withIndex: true, reverse: false);
+    mixin(lockstepMixinTF.getImpl);
+
+    mixin(lockstepMixinFF.getAlias);
+    mixin(lockstepMixinTF.getAlias);
+
     static if (allSatisfy!(isBidirectionalRange, Ranges))
     {
-        mixin(lockstepMixin!Ranges(false, true));
+        private enum lockstepMixinFT = LockstepMixin!Ranges(withIndex: false, reverse: true);
+        mixin(lockstepMixinFT.getImpl);
         static if (allSatisfy!(hasLength, Ranges))
         {
-            mixin(lockstepMixin!Ranges(true, true));
+            private enum lockstepMixinTT = LockstepMixin!Ranges(withIndex: true, reverse: true);
+            mixin(lockstepMixinTT.getImpl);
+            mixin(lockstepMixinTT.getAlias);
         }
         else
         {
-            mixin(lockstepReverseFailMixin!Ranges(true));
+            mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
+            alias opApplyReverse = opApplyReverseIdxFail;
         }
+        mixin(lockstepMixinFT.getAlias);
     }
     else
     {
-        mixin(lockstepReverseFailMixin!Ranges(false));
-        mixin(lockstepReverseFailMixin!Ranges(true));
+        mixin(lockstepReverseFailMixin!Ranges(withIndex: false));
+        mixin(lockstepReverseFailMixin!Ranges(withIndex: true));
+        alias opApplyReverse = opApplyReverseFail;
+        alias opApplyReverse = opApplyReverseIdxFail;
     }
-
-private:
-    alias R = Ranges;
-    R _ranges;
-    StoppingPolicy _stoppingPolicy;
 }
 
 /// Ditto
@@ -6238,33 +6274,39 @@  if (allSatisfy!(isInputRange, Ranges))
 }
 
 ///
-@system unittest
+pure @safe unittest
 {
-   auto arr1 = [1,2,3,4,5,100];
-   auto arr2 = [6,7,8,9,10];
+    int[6] arr1 = [1,2,3,4,5,100];
+    int[5] arr2 = [6,7,8,9,10];
 
-   foreach (ref a, b; lockstep(arr1, arr2))
-   {
-       a += b;
-   }
+    foreach (ref a, b; lockstep(arr1[], arr2[]))
+    {
+        a += b;
+    }
 
-   assert(arr1 == [7,9,11,13,15,100]);
+    assert(arr1 == [7,9,11,13,15,100]);
+}
 
-   /// Lockstep also supports iterating with an index variable:
-   foreach (index, a, b; lockstep(arr1, arr2))
-   {
-       assert(arr1[index] == a);
-       assert(arr2[index] == b);
-   }
+/// Lockstep also supports iterating with an index variable:
+pure @safe unittest
+{
+    int[3] arr1 = [1,2,3];
+    int[3] arr2 = [4,5,6];
+
+    foreach (index, a, b; lockstep(arr1[], arr2[]))
+    {
+        assert(arr1[index] == a);
+        assert(arr2[index] == b);
+    }
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=15860: foreach_reverse on lockstep
-@system unittest
+pure @safe unittest
 {
     auto arr1 = [0, 1, 2, 3];
     auto arr2 = [4, 5, 6, 7];
 
-    size_t n = arr1.length -1;
+    size_t n = arr1.length - 1;
     foreach_reverse (index, a, b; lockstep(arr1, arr2, StoppingPolicy.requireSameLength))
     {
         assert(n == index);
@@ -6283,7 +6325,7 @@  if (allSatisfy!(isInputRange, Ranges))
     }
 }
 
-@system unittest
+pure @safe unittest
 {
     import std.algorithm.iteration : filter;
     import std.conv : to;
@@ -6380,7 +6422,7 @@  if (allSatisfy!(isInputRange, Ranges))
     foreach (x, y; lockstep(iota(0, 10), iota(0, 10))) { }
 }
 
-@system unittest
+pure @safe unittest
 {
     struct RvalueRange
     {
@@ -6436,11 +6478,11 @@  private string lockstepReverseFailMixin(Ranges...)(bool withIndex)
 
     return format(
     q{
-        int opApplyReverse()(scope int delegate(%s) dg)
+        int opApplyReverse%sFail()(scope int delegate(%s) dg)
         {
             static assert(false, "%s");
         }
-    }, params.join(", "), message);
+    }, withIndex ? "Idx" : "" , params.join(", "), message);
 }
 
 // For generic programming, make sure Lockstep!(Range) is well defined for a
diff --git a/libphobos/src/std/stdio.d b/libphobos/src/std/stdio.d
index 8caa9b36718..b4744600cd5 100644
--- a/libphobos/src/std/stdio.d
+++ b/libphobos/src/std/stdio.d
@@ -220,31 +220,6 @@  version (CRuntime_Microsoft)
     private alias _FGETWC = _fgetwc_nolock;
     private alias _FLOCK = _lock_file;
     private alias _FUNLOCK = _unlock_file;
-
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTC = _fputc_nolock;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTWC = _fputwc_nolock;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETC = _fgetc_nolock;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETWC = _fgetwc_nolock;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FLOCK was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FLOCK = _lock_file;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FUNLOCK was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FUNLOCK = _unlock_file;
 }
 else version (CRuntime_Glibc)
 {
@@ -254,31 +229,6 @@  else version (CRuntime_Glibc)
     private alias _FGETWC = fgetwc_unlocked;
     private alias _FLOCK = core.sys.posix.stdio.flockfile;
     private alias _FUNLOCK = core.sys.posix.stdio.funlockfile;
-
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTC = fputc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTWC = fputwc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETC = fgetc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETWC = fgetwc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FLOCK was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FLOCK = core.sys.posix.stdio.flockfile;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FUNLOCK was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FUNLOCK = core.sys.posix.stdio.funlockfile;
 }
 else version (GENERIC_IO)
 {
@@ -304,52 +254,6 @@  else version (GENERIC_IO)
     {
         static assert(0, "don't know how to lock files on GENERIC_IO");
     }
-
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal function fputc_unlocked was unintentionally available "
-               ~ "from std.stdio and will be removed afer 2.107")
-    extern (C) pragma(mangle, fputc.mangleof) int fputc_unlocked(int c, _iobuf* fp);
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal function fputwc_unlocked was unintentionally available "
-               ~ "from std.stdio and will be removed afer 2.107")
-    extern (C) pragma(mangle, core.stdc.wchar_.fputwc.mangleof) int fputwc_unlocked(wchar_t c, _iobuf* fp);
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal function fgetc_unlocked was unintentionally available "
-               ~ "from std.stdio and will be removed afer 2.107")
-    extern (C) pragma(mangle, fgetc.mangleof) int fgetc_unlocked(_iobuf* fp);
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal function fgetwc_unlocked was unintentionally available "
-               ~ "from std.stdio and will be removed afer 2.107")
-    extern (C) pragma(mangle, core.stdc.wchar_.fgetwc.mangleof) int fgetwc_unlocked(_iobuf* fp);
-
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTC = fputc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FPUTWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FPUTWC = fputwc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETC = fgetc_unlocked;
-    // @@@DEPRECATED_2.107@@@
-    deprecated("internal alias FGETWC was unintentionally available from "
-               ~ "std.stdio and will be removed afer 2.107")
-    alias FGETWC = fgetwc_unlocked;
-
-    version (Posix)
-    {
-        // @@@DEPRECATED_2.107@@@
-        deprecated("internal alias FLOCK was unintentionally available from "
-                   ~ "std.stdio and will be removed afer 2.107")
-        alias FLOCK = core.sys.posix.stdio.flockfile;
-        // @@@DEPRECATED_2.107@@@
-        deprecated("internal alias FUNLOCK was unintentionally available from "
-                   ~ "std.stdio and will be removed afer 2.107")
-        alias FUNLOCK = core.sys.posix.stdio.funlockfile;
-    }
 }
 else
 {
@@ -795,7 +699,7 @@  Throws: `ErrnoException` in case of error.
 /**
 Detaches from the current file (throwing on failure), and then runs a command
 by calling the C standard library function $(HTTP
-opengroup.org/onlinepubs/007908799/xsh/_popen.html, _popen).
+pubs.opengroup.org/onlinepubs/7908799/xsh/popen.html, popen).
 
 Throws: `ErrnoException` in case of error.
  */
@@ -813,8 +717,9 @@  The mode must be compatible with the mode of the file descriptor.
 Throws: `ErrnoException` in case of error.
 Params:
     fd = File descriptor to associate with this `File`.
-    stdioOpenmode = Mode to associate with this File. The mode has the same semantics
-        semantics as in the C standard library $(CSTDIO fdopen) function,
+    stdioOpenmode = Mode to associate with this File. The mode has the same
+        semantics as in the POSIX library function $(HTTP
+        pubs.opengroup.org/onlinepubs/7908799/xsh/fdopen.html, fdopen)
         and must be compatible with `fd`.
  */
     void fdopen(int fd, scope const(char)[] stdioOpenmode = "rb") @safe
@@ -1135,6 +1040,9 @@  Throws: `ErrnoException` if the file is not opened or the call to `fread` fails.
         assert(buf == "\r\n\n\r\n");
     }
 
+    // https://issues.dlang.org/show_bug.cgi?id=24685
+    static assert(!__traits(compiles, (File f) @safe { int*[1] bar; f.rawRead(bar[]); }));
+
     // https://issues.dlang.org/show_bug.cgi?id=21729
     @system unittest
     {
@@ -4576,11 +4484,11 @@  if ((isSomeFiniteCharInputRange!R1 || isSomeString!R1) &&
         {
             /*
              * The new opengroup large file support API is transparently
-             * included in the normal C bindings. http://opengroup.org/platform/lfs.html#1.0
+             * included in the normal C bindings. https://www.opengroup.org/platform/lfs.html#1.0
              * if _FILE_OFFSET_BITS in druntime is 64, off_t is 64 bit and
              * the normal functions work fine. If not, then large file support
              * probably isn't available. Do not use the old transitional API
-             * (the native extern(C) fopen64, http://www.unix.org/version2/whatsnew/lfs20mar.html#3.0)
+             * (the native extern(C) fopen64, https://unix.org/version2/whatsnew/lfs20mar.html#3.0)
              */
             import core.sys.posix.stdio : fopen;
             return fopen(namez, modez);
@@ -4629,6 +4537,13 @@  private auto trustedFwrite(T)(FILE* f, const T[] obj) @trusted
  * Convenience function that forwards to `core.stdc.stdio.fread`
  */
 private auto trustedFread(T)(FILE* f, T[] obj) @trusted
+if (!imported!"std.traits".hasIndirections!T)
+{
+    return fread(obj.ptr, T.sizeof, obj.length, f);
+}
+
+private auto trustedFread(T)(FILE* f, T[] obj) @system
+if (imported!"std.traits".hasIndirections!T)
 {
     return fread(obj.ptr, T.sizeof, obj.length, f);
 }
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 3c425c7d7de..aceb2878d49 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3543,6 +3543,35 @@  struct Nullable(T)
         format!"%s"(a);
     }
 
+    /**
+     * Returns true if `this` has a value, otherwise false.
+     *
+     * Allows a `Nullable` to be used as the condition in an `if` statement:
+     *
+     * ---
+     * if (auto result = functionReturningNullable())
+     * {
+     *     doSomethingWith(result.get);
+     * }
+     * ---
+     */
+    bool opCast(T : bool)() const
+    {
+        return !isNull;
+    }
+
+    /// Prevents `opCast` from disabling built-in conversions.
+    auto ref T opCast(T, this This)()
+    if (is(This : T) || This.sizeof == T.sizeof)
+    {
+        static if (is(This : T))
+            // Convert implicitly
+            return this;
+        else
+            // Reinterpret
+            return *cast(T*) &this;
+    }
+
     /**
      * Forces `this` to the null state.
      */
@@ -4400,6 +4429,26 @@  auto nullable(T)(T t)
     assert(destroyed);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=22293
+@safe unittest
+{
+    Nullable!int empty;
+    Nullable!int full = 123;
+
+    assert(cast(bool) empty == false);
+    assert(cast(bool) full == true);
+
+    if (empty) assert(0);
+    if (!full) assert(0);
+}
+
+// check that opCast doesn't break unsafe casts
+@system unittest
+{
+    Nullable!(const(int*)) a;
+    auto result = cast(immutable(Nullable!(int*))) a;
+}
+
 /**
 Just like `Nullable!T`, except that the null state is defined as a
 particular value. For example, $(D Nullable!(uint, uint.max)) is an
@@ -10928,19 +10977,22 @@  struct RefCounted(T, RefCountedAutoInitialize autoInit =
         swap(_refCounted._store, rhs._refCounted._store);
     }
 
-    void opAssign(T rhs)
+    static if (__traits(compiles, lvalueOf!T = T.init))
     {
-        import std.algorithm.mutation : move;
-
-        static if (autoInit == RefCountedAutoInitialize.yes)
+        void opAssign(T rhs)
         {
-            _refCounted.ensureInitialized();
-        }
-        else
-        {
-            assert(_refCounted.isInitialized);
+            import std.algorithm.mutation : move;
+
+            static if (autoInit == RefCountedAutoInitialize.yes)
+            {
+                _refCounted.ensureInitialized();
+            }
+            else
+            {
+                assert(_refCounted.isInitialized);
+            }
+            move(rhs, _refCounted._store._payload);
         }
-        move(rhs, _refCounted._store._payload);
     }
 
     static if (autoInit == RefCountedAutoInitialize.yes)
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index f0d5d4d268b..9a326a5ac3a 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -53,7 +53,7 @@  $(TR $(TD Miscellaneous) $(TD
     See_Also:
         $(LINK2 http://en.wikipedia.org/wiki/Unicode, Wikipedia)<br>
         $(LINK http://www.cl.cam.ac.uk/~mgk25/unicode.html#utf-8)<br>
-        $(LINK http://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
+        $(LINK https://web.archive.org/web/20100113043530/https://anubis.dkuug.dk/JTC1/SC2/WG2/docs/n1335)
     Copyright: Copyright The D Language Foundation 2000 - 2012.
     License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
     Authors:   $(HTTP digitalmars.com, Walter Bright) and