diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index 8b66cf264a7..36a139b4ec4 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -327,7 +327,7 @@ build_attributes (Expressions *eattrs)
   for (size_t i = 0; i < eattrs->length; i++)
     {
       Expression *attr = (*eattrs)[i];
-      Dsymbol *sym = attr->type->toDsymbol (0);
+      Dsymbol *sym = toDsymbol (attr->type, NULL);
 
       if (!sym)
 	{
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 71f8473e0ec..aabe1ad43cb 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -1344,7 +1344,10 @@ d_parse_file (void)
     }
 
   if (global.params.v.templates)
-    printTemplateStats ();
+    {
+      printTemplateStats (global.params.v.templatesListInstances,
+			  global.errorSink);
+    }
 
   /* Generate JSON files.  */
   if (global.params.json.doOutput)
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 23749315fff..4ca85bb970d 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -782,7 +782,7 @@ public:
       {
 	/* Do not store variables we cannot take the address of,
 	   but keep the values for purposes of debugging.  */
-	if (d->type->isscalar () && !d->type->hasPointers ())
+	if (d->type->isscalar () && !hasPointers (d->type))
 	  {
 	    tree decl = get_symbol_decl (d);
 	    d_pushdecl (decl);
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 2b4400f398e..138b0b6fa7c 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce
+bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa
 
 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/astenums.d b/gcc/d/dmd/astenums.d
index f19edb9e4b4..77940b80248 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -459,3 +459,9 @@ extern (C++) struct structalign_t
     bool isPack() const    { return pack; }
     void setPack(bool pack) { this.pack = pack; }
 }
+
+/// Use to return D arrays from C++ functions
+extern (C++) struct DArray(T)
+{
+    T[] data;
+}
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 7bd9691a429..cee1f6364bc 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -1038,6 +1038,7 @@ UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
     else if (tb.ty == Tstruct && e1.op == EXP.int64)
     {
         // Struct = 0;
+        import dmd.typesem : toDsymbol;
         StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
         assert(sd);
         auto elements = new Expressions();
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 5869a220842..93ef63f7aa3 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -1749,6 +1749,35 @@ extern (C++) final class SymbolDeclaration : Declaration
 
 /***********************************************************
  */
+private Identifier getTypeInfoIdent(Type t)
+{
+    import dmd.dmangle;
+    import core.stdc.stdlib;
+    import dmd.root.rmem;
+    // _init_10TypeInfo_%s
+    OutBuffer buf;
+    buf.reserve(32);
+    mangleToBuffer(t, buf);
+
+    const slice = buf[];
+
+    // Allocate buffer on stack, fail over to using malloc()
+    char[128] namebuf;
+    const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
+    auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
+
+    const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
+            cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
+    //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
+    assert(0 < length && length < namelen); // don't overflow the buffer
+
+    auto id = Identifier.idPool(name[0 .. length]);
+
+    if (name != namebuf.ptr)
+        free(name);
+    return id;
+}
+
 extern (C++) class TypeInfoDeclaration : VarDeclaration
 {
     Type tinfo;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index eda91d1ea05..a3b38d9fee3 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -1416,6 +1416,7 @@ Expression interpretStatement(UnionExp* pue, Statement s, InterState* istate)
             foreach (ca; *s.catches)
             {
                 Type catype = ca.type;
+                import dmd.typesem : isBaseOf;
                 if (!catype.equals(extype) && !catype.isBaseOf(extype, null))
                     continue;
 
@@ -6237,6 +6238,11 @@ public:
         {
             if (soe.offset == 0 && soe.var.isFuncDeclaration())
                 return;
+            if (soe.offset == 0 && soe.var.isVarDeclaration() && soe.var.isImmutable())
+            {
+                result = getVarExp(e.loc, istate, soe.var, CTFEGoal.RValue);
+                return;
+            }
             error(e.loc, "cannot dereference pointer to static variable `%s` at compile time", soe.var.toChars());
             result = CTFEExp.cantexp;
             return;
@@ -6359,6 +6365,7 @@ public:
             {
                 if (auto t = isType(ex.isTypeidExp().obj))
                 {
+                    import dmd.typesem : toDsymbol;
                     auto sym = t.toDsymbol(null);
                     if (auto ident = (sym ? sym.ident : null))
                     {
@@ -6643,6 +6650,7 @@ Expressions* copyArrayOnWrite(Expressions* exps, Expressions* original)
 private
 bool stopPointersEscaping(const ref Loc loc, Expression e)
 {
+    import dmd.typesem : hasPointers;
     if (!e.type.hasPointers())
         return true;
     if (isPointer(e.type))
@@ -6706,7 +6714,7 @@ Statement findGotoTarget(InterState* istate, Identifier ident)
     Statement target = null;
     if (ident)
     {
-        LabelDsymbol label = istate.fd.searchLabel(ident);
+        LabelDsymbol label = istate.fd.searchLabel(ident, Loc.initial);
         assert(label && label.statement);
         LabelStatement ls = label.statement;
         target = ls.gotoTarget ? ls.gotoTarget : ls.statement;
@@ -7263,6 +7271,33 @@ private Expression interpret_aaApply(UnionExp* pue, InterState* istate, Expressi
     return eresult;
 }
 
+/// Returns: equivalent `StringExp` from `ArrayLiteralExp ale` containing only `IntegerExp` elements
+StringExp arrayLiteralToString(ArrayLiteralExp ale)
+{
+    const len = ale.elements ? ale.elements.length : 0;
+    const size = ale.type.nextOf().size();
+
+    StringExp impl(T)()
+    {
+        T[] result = new T[len];
+        foreach (i; 0 .. len)
+            result[i] = cast(T) (*ale.elements)[i].isIntegerExp().getInteger();
+        return new StringExp(ale.loc, result[], len, cast(ubyte) size);
+    }
+
+    switch (size)
+    {
+        case 1:
+            return impl!char();
+        case 2:
+            return impl!wchar();
+        case 4:
+            return impl!dchar();
+        default:
+            assert(0);
+    }
+}
+
 /* Decoding UTF strings for foreach loops. Duplicates the functionality of
  * the twelve _aApplyXXn functions in aApply.d in the runtime.
  */
@@ -7299,8 +7334,10 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
     str = resolveSlice(str, &strTmp);
 
     auto se = str.isStringExp();
-    auto ale = str.isArrayLiteralExp();
-    if (!se && !ale)
+    if (auto ale = str.isArrayLiteralExp())
+        se = arrayLiteralToString(ale);
+
+    if (!se)
     {
         error(str.loc, "CTFE internal error: cannot foreach `%s`", str.toChars());
         return CTFEExp.cantexp;
@@ -7309,7 +7346,7 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
 
     Expression eresult = null; // ded-store to prevent spurious warning
 
-    // Buffers for encoding; also used for decoding array literals
+    // Buffers for encoding
     char[4] utf8buf = void;
     wchar[2] utf16buf = void;
 
@@ -7323,90 +7360,11 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
         dchar rawvalue; // Holds the decoded dchar
         size_t currentIndex = indx; // The index of the decoded character
 
-        if (ale)
-        {
-            // If it is an array literal, copy the code points into the buffer
-            size_t buflen = 1; // #code points in the buffer
-            size_t n = 1; // #code points in this char
-            size_t sz = cast(size_t)ale.type.nextOf().size();
+        // String literals
+        size_t saveindx; // used for reverse iteration
 
-            switch (sz)
-            {
-            case 1:
-                if (rvs)
-                {
-                    // find the start of the string
-                    --indx;
-                    buflen = 1;
-                    while (indx > 0 && buflen < 4)
-                    {
-                        Expression r = (*ale.elements)[indx];
-                        char x = cast(char)r.isIntegerExp().getInteger();
-                        if ((x & 0xC0) != 0x80)
-                            break;
-                        --indx;
-                        ++buflen;
-                    }
-                }
-                else
-                    buflen = (indx + 4 > len) ? len - indx : 4;
-                for (size_t i = 0; i < buflen; ++i)
-                {
-                    Expression r = (*ale.elements)[indx + i];
-                    utf8buf[i] = cast(char)r.isIntegerExp().getInteger();
-                }
-                n = 0;
-                errmsg = utf_decodeChar(utf8buf[0 .. buflen], n, rawvalue);
-                break;
-
-            case 2:
-                if (rvs)
-                {
-                    // find the start of the string
-                    --indx;
-                    buflen = 1;
-                    Expression r = (*ale.elements)[indx];
-                    ushort x = cast(ushort)r.isIntegerExp().getInteger();
-                    if (indx > 0 && x >= 0xDC00 && x <= 0xDFFF)
-                    {
-                        --indx;
-                        ++buflen;
-                    }
-                }
-                else
-                    buflen = (indx + 2 > len) ? len - indx : 2;
-                for (size_t i = 0; i < buflen; ++i)
-                {
-                    Expression r = (*ale.elements)[indx + i];
-                    utf16buf[i] = cast(ushort)r.isIntegerExp().getInteger();
-                }
-                n = 0;
-                errmsg = utf_decodeWchar(utf16buf[0 .. buflen], n, rawvalue);
-                break;
-
-            case 4:
-                {
-                    if (rvs)
-                        --indx;
-                    Expression r = (*ale.elements)[indx];
-                    rawvalue = cast(dchar)r.isIntegerExp().getInteger();
-                    n = 1;
-                }
-                break;
-
-            default:
-                assert(0);
-            }
-            if (!rvs)
-                indx += n;
-        }
-        else
+        switch (se.sz)
         {
-            // String literals
-            size_t saveindx; // used for reverse iteration
-
-            switch (se.sz)
-            {
             case 1:
             {
                 if (rvs)
@@ -7450,8 +7408,8 @@ private Expression foreachApplyUtf(UnionExp* pue, InterState* istate, Expression
 
             default:
                 assert(0);
-            }
         }
+
         if (errmsg)
         {
             error(deleg.loc, "`%.*s`", cast(int)errmsg.length, errmsg.ptr);
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 022231c1254..59d40655253 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -679,23 +679,23 @@ extern (C++) final class Module : Package
         /* Preprocess the file if it's a .c file
          */
         FileName filename = srcfile;
-        bool ifile = false;             // did we generate a .i file
-        scope (exit)
-        {
-            if (ifile)
-                File.remove(filename.toChars());        // remove generated file
-        }
 
+        const(ubyte)[] srctext;
         if (global.preprocess &&
             FileName.equalsExt(srcfile.toString(), c_ext) &&
             FileName.exists(srcfile.toString()))
         {
-            filename = global.preprocess(srcfile, loc, ifile, &defines);  // run C preprocessor
+            /* Apply C preprocessor to the .c file, returning the contents
+             * after preprocessing
+             */
+            srctext = global.preprocess(srcfile, loc, defines).data;
         }
+        else
+            srctext = global.fileManager.getFileContents(filename);
+        this.src = srctext;
 
-        if (auto result = global.fileManager.lookup(filename))
+        if (srctext)
         {
-            this.src = result;
             if (global.params.makeDeps.doOutput)
                 global.params.makeDeps.files.push(srcfile.toChars());
             return true;
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 810642f9f52..ec3cc91409b 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -1355,6 +1355,7 @@ void toDocBuffer(Dsymbol s, ref OutBuffer buf, Scope* sc)
             {
                 if (type.ty == Tclass || type.ty == Tstruct || type.ty == Tenum)
                 {
+                    import dmd.typesem : toDsymbol;
                     if (Dsymbol s = type.toDsymbol(null)) // elaborate type
                         prettyPrintDsymbol(s, ad.parent);
                     else
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 7e9499fd28f..e02ba9a873b 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -97,6 +97,7 @@ extern (C++) struct Scope
     Dsymbol inunion;                /// != null if processing members of a union
     bool nofree;                    /// true if shouldn't free it
     bool inLoop;                    /// true if inside a loop (where constructor calls aren't allowed)
+    bool inDefaultArg;              /// true if inside a default argument (where __FILE__, etc are evaluated at the call site)
     int intypeof;                   /// in typeof(exp)
     VarDeclaration lastVar;         /// Previous symbol used to prevent goto-skips-init
     ErrorSink eSink;                /// sink for error messages
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 23f0bc5b428..e9cdb945b57 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -6553,7 +6553,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
     TemplateDeclaration tempdecl = tempinst.tempdecl.isTemplateDeclaration();
     assert(tempdecl);
 
-    TemplateStats.incInstance(tempdecl, tempinst);
+    if (global.params.v.templates)
+        TemplateStats.incInstance(tempdecl, tempinst, global.params.v.templatesListInstances);
 
     tempdecl.checkDeprecated(tempinst.loc, sc);
 
@@ -6746,7 +6747,8 @@ void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList
     tempinst.parent = tempinst.enclosing ? tempinst.enclosing : tempdecl.parent;
     //printf("parent = '%s'\n", parent.kind());
 
-    TemplateStats.incUnique(tempdecl, tempinst);
+    if (global.params.v.templates)
+        TemplateStats.incUnique(tempdecl, tempinst);
 
     TemplateInstance tempdecl_instance_idx = tempdecl.addInstance(tempinst);
 
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 1d84ccd0295..13cc32f73e0 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -56,6 +56,7 @@ import dmd.dscope;
 import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.errors;
+import dmd.errorsink;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
@@ -150,7 +151,7 @@ extern (C++) bool isError(const RootObject o)
     if (const e = isExpression(o))
         return (e.op == EXP.error || !e.type || e.type.ty == Terror);
     if (const v = isTuple(o))
-        return arrayObjectIsError(&v.objects);
+        return arrayObjectIsError(v.objects);
     const s = isDsymbol(o);
     assert(s);
     if (s.errors)
@@ -161,9 +162,9 @@ extern (C++) bool isError(const RootObject o)
 /**************************************
  * Are any of the Objects an error?
  */
-bool arrayObjectIsError(const Objects* args)
+bool arrayObjectIsError(const ref Objects args)
 {
-    foreach (const o; *args)
+    foreach (const o; args)
     {
         if (isError(o))
             return true;
@@ -187,6 +188,13 @@ inout(Type) getType(inout RootObject o)
 
 }
 
+/***********************************
+ * If oarg represents a Dsymbol, return that Dsymbol
+ * Params:
+ *      oarg = argument to check
+ * Returns:
+ *      Dsymbol if a symbol, null if not
+ */
 Dsymbol getDsymbol(RootObject oarg)
 {
     //printf("getDsymbol()\n");
@@ -256,8 +264,11 @@ private Expression getExpression(RootObject o)
 }
 
 /******************************
- * If o1 matches o2, return true.
- * Else, return false.
+ * See if two objects match
+ * Params:
+ *      o1 = first object
+ *      o2 = second object
+ * Returns: true if they match
  */
 private bool match(RootObject o1, RootObject o2)
 {
@@ -343,7 +354,7 @@ private bool match(RootObject o1, RootObject o2)
             printf("\tu1 = %s\n", u1.toChars());
             printf("\tu2 = %s\n", u2.toChars());
         }
-        if (!arrayObjectMatch(&u1.objects, &u2.objects))
+        if (!arrayObjectMatch(u1.objects, u2.objects))
             goto Lnomatch;
 
         goto Lmatch;
@@ -362,15 +373,15 @@ Lnomatch:
 /************************************
  * Match an array of them.
  */
-private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
+private bool arrayObjectMatch(ref Objects oa1, ref Objects oa2)
 {
-    if (oa1 == oa2)
+    if (&oa1 == &oa2)
         return true;
     if (oa1.length != oa2.length)
         return false;
     immutable oa1dim = oa1.length;
-    auto oa1d = (*oa1)[].ptr;
-    auto oa2d = (*oa2)[].ptr;
+    auto oa1d = oa1[].ptr;
+    auto oa2d = oa2[].ptr;
     foreach (j; 0 .. oa1dim)
     {
         RootObject o1 = oa1d[j];
@@ -386,12 +397,12 @@ private bool arrayObjectMatch(Objects* oa1, Objects* oa2)
 /************************************
  * Return hash of Objects.
  */
-private size_t arrayObjectHash(Objects* oa1)
+private size_t arrayObjectHash(ref Objects oa1)
 {
     import dmd.root.hash : mixHash;
 
     size_t hash = 0;
-    foreach (o1; *oa1)
+    foreach (o1; oa1)
     {
         /* Must follow the logic of match()
          */
@@ -407,7 +418,7 @@ private size_t arrayObjectHash(Objects* oa1)
             hash = mixHash(hash, mixHash(cast(size_t)cast(void*)s1.getIdent(), cast(size_t)cast(void*)s1.parent));
         }
         else if (auto u1 = isTuple(o1))
-            hash = mixHash(hash, arrayObjectHash(&u1.objects));
+            hash = mixHash(hash, arrayObjectHash(u1.objects));
     }
     return hash;
 }
@@ -672,7 +683,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
     /**********************************
      * Overload existing TemplateDeclaration 'this' with the new one 's'.
-     * Return true if successful; i.e. no conflict.
+     * Params:
+     *    s = symbol to be inserted
+     * Return: true if successful; i.e. no conflict.
      */
     override bool overloadInsert(Dsymbol s)
     {
@@ -741,6 +754,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
         return toCharsMaybeConstraints(false);
     }
 
+    // Note: this function is not actually `const`, because iterating the
+    // function parameter list may run dsymbolsemantic on enum types
     const(char)* toCharsMaybeConstraints(bool includeConstraints) const
     {
         OutBuffer buf;
@@ -758,15 +773,17 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
         if (onemember)
         {
-            const FuncDeclaration fd = onemember.isFuncDeclaration();
-            if (fd && fd.type)
+            if (const fd = onemember.isFuncDeclaration())
             {
-                TypeFunction tf = cast(TypeFunction)fd.type;
-                buf.writestring(parametersTypeToChars(tf.parameterList));
-                if (tf.mod)
+                if (TypeFunction tf = cast(TypeFunction)fd.type.isTypeFunction())
                 {
-                    buf.writeByte(' ');
-                    buf.MODtoBuffer(tf.mod);
+                    // !! Casted away const
+                    buf.writestring(parametersTypeToChars(tf.parameterList));
+                    if (tf.mod)
+                    {
+                        buf.writeByte(' ');
+                        buf.MODtoBuffer(tf.mod);
+                    }
                 }
             }
         }
@@ -790,7 +807,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
     /****************************
      * Check to see if constraint is satisfied.
      */
-    extern (D) bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
+    private bool evaluateConstraint(TemplateInstance ti, Scope* sc, Scope* paramscope, Objects* dedargs, FuncDeclaration fd)
     {
         /* Detect recursive attempts to instantiate this template declaration,
          * https://issues.dlang.org/show_bug.cgi?id=4072
@@ -807,7 +824,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
         for (TemplatePrevious* p = previous; p; p = p.prev)
         {
-            if (!arrayObjectMatch(p.dedargs, dedargs))
+            if (!arrayObjectMatch(*p.dedargs, *dedargs))
                 continue;
             //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
             /* It must be a subscope of p.sc, other scope chains are not recursive
@@ -1055,7 +1072,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
      *      dedtypes        deduced arguments
      * Return match level.
      */
-    extern (D) MATCH matchWithInstance(Scope* sc, TemplateInstance ti, Objects* dedtypes, ArgumentList argumentList, int flag)
+    private MATCH matchWithInstance(Scope* sc, TemplateInstance ti, ref Objects dedtypes, ArgumentList argumentList, int flag)
     {
         enum LOGM = 0;
         static if (LOGM)
@@ -1151,7 +1168,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             /* Any parameter left without a type gets the type of
              * its corresponding arg
              */
-            foreach (i, ref dedtype; *dedtypes)
+            foreach (i, ref dedtype; dedtypes)
             {
                 if (!dedtype)
                 {
@@ -1202,7 +1219,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             }
 
             // TODO: dedtypes => ti.tiargs ?
-            if (!evaluateConstraint(ti, sc, paramscope, dedtypes, fd))
+            if (!evaluateConstraint(ti, sc, paramscope, &dedtypes, fd))
                 return nomatch();
         }
 
@@ -1283,7 +1300,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
         Objects dedtypes = Objects(td2.parameters.length);
 
         // Attempt a type deduction
-        MATCH m = td2.matchWithInstance(sc, ti, &dedtypes, argumentList, 1);
+        MATCH m = td2.matchWithInstance(sc, ti, dedtypes, argumentList, 1);
         if (m > MATCH.nomatch)
         {
             /* A non-variadic template is more specialized than a
@@ -1425,7 +1442,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             {
                 assert(i < parameters.length);
                 Declaration sparam = null;
-                MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, &sparam);
+                MATCH m = (*parameters)[i].matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, &sparam);
                 //printf("\tdeduceType m = %d\n", m);
                 if (m == MATCH.nomatch)
                     return nomatch();
@@ -1458,10 +1475,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
         ParameterList fparameters = fd.getParameterList(); // function parameter list
         const nfparams = fparameters.length; // number of function parameters
-        const nfargs = argumentList.length; // number of function arguments
         if (argumentList.hasNames)
             return matcherror(); // TODO: resolve named args
-        Expressions* fargs = argumentList.arguments; // TODO: resolve named args
+        Expression[] fargs = argumentList.arguments ? (*argumentList.arguments)[] : null;
 
         /* Check for match of function arguments with variadic template
          * parameter, such as:
@@ -1475,7 +1491,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             // TemplateTupleParameter always makes most lesser matching.
             matchTiargs = MATCH.convert;
 
-            if (nfparams == 0 && nfargs != 0) // if no function parameters
+            if (nfparams == 0 && argumentList.length != 0) // if no function parameters
             {
                 if (!declaredTuple)
                 {
@@ -1498,7 +1514,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     auto fparam = (*fparameters.parameters)[fptupindex]; // fparameters[fptupindex] ?
                     if (fparam.type.ty != Tident)
                         continue;
-                    TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+                    TypeIdentifier tid = fparam.type.isTypeIdentifier();
                     if (!tp.ident.equals(tid.ident) || tid.idents.length)
                         continue;
 
@@ -1527,7 +1543,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     hasttp = true;
 
                     Type t = new TypeIdentifier(Loc.initial, ttp.ident);
-                    MATCH m = deduceType(tthis, paramscope, t, parameters, dedtypes);
+                    MATCH m = deduceType(tthis, paramscope, t, *parameters, *dedtypes);
                     if (m == MATCH.nomatch)
                         return nomatch();
                     if (m < match)
@@ -1576,7 +1592,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             //printf("%s\n\tnfargs = %d, nfparams = %d, tuple_dim = %d\n", toChars(), nfargs, nfparams, declaredTuple ? declaredTuple.objects.length : 0);
             //printf("\ttp = %p, fptupindex = %d, found = %d, declaredTuple = %s\n", tp, fptupindex, fptupindex != IDX_NOTFOUND, declaredTuple ? declaredTuple.toChars() : NULL);
             size_t argi = 0;
-            size_t nfargs2 = nfargs; // nfargs + supplied defaultArgs
+            size_t nfargs2 = fargs.length; // nfargs + supplied defaultArgs
             uint inoutMatch = 0; // for debugging only
             for (size_t parami = 0; parami < nfparams; parami++)
             {
@@ -1592,8 +1608,8 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                  */
                 if (fptupindex != IDX_NOTFOUND && parami == fptupindex)
                 {
-                    assert(prmtype.ty == Tident);
-                    TypeIdentifier tid = cast(TypeIdentifier)prmtype;
+                    TypeIdentifier tid = prmtype.isTypeIdentifier();
+                    assert(tid);
                     if (!declaredTuple)
                     {
                         /* The types of the function arguments
@@ -1606,7 +1622,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                          * void foo(U, T...)(int y, T, U, double, int bar = 0) {}  // rem == 2 (U, double)
                          */
                         size_t rem = 0;
-                        for (size_t j = parami + 1; j < nfparams; j++)
+                        foreach (j; parami + 1 .. nfparams)
                         {
                             Parameter p = fparameters[j];
                             if (p.defaultArg)
@@ -1616,7 +1632,10 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                             if (!reliesOnTemplateParameters(p.type, (*parameters)[inferStart .. parameters.length]))
                             {
                                 Type pt = p.type.syntaxCopy().typeSemantic(fd.loc, paramscope);
-                                rem += pt.ty == Ttuple ? (cast(TypeTuple)pt).arguments.length : 1;
+                                if (auto ptt = pt.isTypeTuple())
+                                    rem += ptt.arguments.length;
+                                else
+                                    rem += 1;
                             }
                             else
                             {
@@ -1627,9 +1646,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                         if (nfargs2 - argi < rem)
                             return nomatch();
                         declaredTuple.objects.setDim(nfargs2 - argi - rem);
-                        for (size_t i = 0; i < declaredTuple.objects.length; i++)
+                        foreach (i; 0 .. declaredTuple.objects.length)
                         {
-                            farg = (*fargs)[argi + i];
+                            farg = fargs[argi + i];
 
                             // Check invalid arguments to detect errors early.
                             if (farg.op == EXP.error || farg.type.ty == Terror)
@@ -1647,7 +1666,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                             }
                             else
                             {
-                                m = deduceTypeHelper(farg.type, &tt, tid);
+                                m = deduceTypeHelper(farg.type, tt, tid);
                             }
                             if (m == MATCH.nomatch)
                                 return nomatch();
@@ -1687,20 +1706,19 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     // should copy prmtype to avoid affecting semantic result
                     prmtype = prmtype.syntaxCopy().typeSemantic(fd.loc, paramscope);
 
-                    if (prmtype.ty == Ttuple)
+                    if (TypeTuple tt = prmtype.isTypeTuple())
                     {
-                        TypeTuple tt = cast(TypeTuple)prmtype;
-                        size_t tt_dim = tt.arguments.length;
+                        const tt_dim = tt.arguments.length;
                         for (size_t j = 0; j < tt_dim; j++, ++argi)
                         {
                             Parameter p = (*tt.arguments)[j];
                             if (j == tt_dim - 1 && fparameters.varargs == VarArg.typesafe &&
-                                parami + 1 == nfparams && argi < nfargs)
+                                parami + 1 == nfparams && argi < fargs.length)
                             {
                                 prmtype = p.type;
                                 goto Lvarargs;
                             }
-                            if (argi >= nfargs)
+                            if (argi >= fargs.length)
                             {
                                 if (p.defaultArg)
                                     continue;
@@ -1711,7 +1729,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
                                 return nomatch();
                             }
-                            farg = (*fargs)[argi];
+                            farg = fargs[argi];
                             if (!farg.implicitConvTo(p.type))
                                 return nomatch();
                         }
@@ -1719,7 +1737,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     }
                 }
 
-                if (argi >= nfargs) // if not enough arguments
+                if (argi >= fargs.length) // if not enough arguments
                 {
                     if (!fparam.defaultArg)
                         goto Lvarargs;
@@ -1741,7 +1759,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                      *  // at fparam `N start = 0`, N should be 'size_t' before
                      *  // the deduction result from fparam.defaultArg.
                      */
-                    if (argi == nfargs)
+                    if (argi == fargs.length)
                     {
                         foreach (ref dedtype; *dedtypes)
                         {
@@ -1769,7 +1787,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                                      * the oded == oarg
                                      */
                                     (*dedargs)[i] = oded;
-                                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+                                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
                                     //printf("m2 = %d\n", m2);
                                     if (m2 == MATCH.nomatch)
                                         return nomatch();
@@ -1822,7 +1840,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 }
                 else
                 {
-                    farg = (*fargs)[argi];
+                    farg = fargs[argi];
                 }
                 {
                     // Check invalid arguments to detect errors early.
@@ -1851,8 +1869,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     {
                         /* Allow expressions that have CT-known boundaries and type [] to match with [dim]
                          */
-                        Type taai;
-                        if (argtype.ty == Tarray && (prmtype.ty == Tsarray || prmtype.ty == Taarray && (taai = (cast(TypeAArray)prmtype).index).ty == Tident && (cast(TypeIdentifier)taai).idents.length == 0))
+                        bool inferIndexType = (argtype.ty == Tarray) && (prmtype.ty == Tsarray || prmtype.ty == Taarray);
+                        if (auto aaType = prmtype.isTypeAArray())
+                        {
+                            if (auto indexType = aaType.index.isTypeIdentifier())
+                            {
+                                inferIndexType = indexType.idents.length == 0;
+                            }
+                        }
+                        if (inferIndexType)
                         {
                             if (StringExp se = farg.isStringExp())
                             {
@@ -1871,7 +1896,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
 
                         oarg = argtype;
                     }
-                    else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && (cast(TypeIdentifier)prmtype).idents.length == 0)
+                    else if ((fparam.storageClass & STC.out_) == 0 && (argtype.ty == Tarray || argtype.ty == Tpointer) && templateParameterLookup(prmtype, parameters) != IDX_NOTFOUND && prmtype.isTypeIdentifier().idents.length == 0)
                     {
                         /* The farg passing to the prmtype always make a copy. Therefore,
                          * we can shrink the set of the deduced type arguments for prmtype
@@ -1892,11 +1917,11 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                         }
                     }
 
-                    if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < nfargs)
+                    if (fparameters.varargs == VarArg.typesafe && parami + 1 == nfparams && argi + 1 < fargs.length)
                         goto Lvarargs;
 
                     uint im = 0;
-                    MATCH m = deduceType(oarg, paramscope, prmtype, parameters, dedtypes, &im, inferStart);
+                    MATCH m = deduceType(oarg, paramscope, prmtype, *parameters, *dedtypes, &im, inferStart);
                     //printf("\tL%d deduceType m = %d, im = x%x, inoutMatch = x%x\n", __LINE__, m, im, inoutMatch);
                     inoutMatch |= im;
 
@@ -1984,17 +2009,15 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 case Taarray:
                     {
                         // Perhaps we can do better with this, see TypeFunction.callMatch()
-                        if (tb.ty == Tsarray)
+                        if (TypeSArray tsa = tb.isTypeSArray())
                         {
-                            TypeSArray tsa = cast(TypeSArray)tb;
                             dinteger_t sz = tsa.dim.toInteger();
-                            if (sz != nfargs - argi)
+                            if (sz != fargs.length - argi)
                                 return nomatch();
                         }
-                        else if (tb.ty == Taarray)
+                        else if (TypeAArray taa = tb.isTypeAArray())
                         {
-                            TypeAArray taa = cast(TypeAArray)tb;
-                            Expression dim = new IntegerExp(instLoc, nfargs - argi, Type.tsize_t);
+                            Expression dim = new IntegerExp(instLoc, fargs.length - argi, Type.tsize_t);
 
                             size_t i = templateParameterLookup(taa.index, parameters);
                             if (i == IDX_NOTFOUND)
@@ -2057,9 +2080,9 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                     {
                         TypeArray ta = cast(TypeArray)tb;
                         Type tret = fparam.isLazyArray();
-                        for (; argi < nfargs; argi++)
+                        for (; argi < fargs.length; argi++)
                         {
-                            Expression arg = (*fargs)[argi];
+                            Expression arg = fargs[argi];
                             assert(arg);
 
                             MATCH m;
@@ -2085,7 +2108,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                             else
                             {
                                 uint wm = 0;
-                                m = deduceType(arg, paramscope, ta.next, parameters, dedtypes, &wm, inferStart);
+                                m = deduceType(arg, paramscope, ta.next, *parameters, *dedtypes, &wm, inferStart);
                                 inoutMatch |= wm;
                             }
                             if (m == MATCH.nomatch)
@@ -2112,8 +2135,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
     Lmatch:
         foreach (ref dedtype; *dedtypes)
         {
-            Type at = isType(dedtype);
-            if (at)
+            if (Type at = isType(dedtype))
             {
                 if (at.ty == Tnone)
                 {
@@ -2147,7 +2169,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                      * the oded == oarg
                      */
                     (*dedargs)[i] = oded;
-                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
                     //printf("m2 = %d\n", m2);
                     if (m2 == MATCH.nomatch)
                         return nomatch();
@@ -2194,7 +2216,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
                 if (tparam.specialization())
                 {
                     (*dedargs)[i] = oded;
-                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, dedtypes, null);
+                    MATCH m2 = tparam.matchArg(instLoc, paramscope, dedargs, i, parameters, *dedtypes, null);
                     //printf("m2 = %d\n", m2);
                     if (m2 == MATCH.nomatch)
                         return nomatch();
@@ -2233,7 +2255,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             sc2.minst = sc.minst;
             sc2.stc |= fd.storage_class & STC.deprecated_;
 
-            fd = doHeaderInstantiation(ti, sc2, fd, tthis, fargs);
+            fd = doHeaderInstantiation(ti, sc2, fd, tthis, argumentList.arguments);
 
             sc2 = sc2.pop();
             sc2 = sc2.pop();
@@ -2396,7 +2418,7 @@ extern (C++) final class TemplateDeclaration : ScopeDsymbol
             }
             if (hasttp)
             {
-                tf = cast(TypeFunction)tf.addSTC(ModToStc(tthis.mod));
+                tf = tf.addSTC(ModToStc(tthis.mod)).isTypeFunction();
                 assert(!tf.deco);
             }
         }
@@ -2602,10 +2624,10 @@ extern (C++) final class TypeDeduced : Type
  *      tiargs      = initial list of template arguments
  *      tthis       = if !NULL, the 'this' pointer argument
  *      argumentList= arguments to function
- *      pMessage    = address to store error message, or null
+ *      errorHelper = delegate to send error message to if not null
  */
 void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc, Objects* tiargs,
-    Type tthis, ArgumentList argumentList, const(char)** pMessage = null)
+    Type tthis, ArgumentList argumentList, void delegate(const(char)*) scope errorHelper = null)
 {
     version (none)
     {
@@ -2662,7 +2684,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
             return 1;
         }
         //printf("fd = %s %s, fargs = %s\n", fd.toChars(), fd.type.toChars(), fargs.toChars());
-        auto tf = cast(TypeFunction)fd.type;
+        auto tf = fd.type.isTypeFunction();
 
         int prop = tf.isproperty ? 1 : 2;
         if (property == 0)
@@ -2711,8 +2733,12 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
             else if (shared_this && !shared_dtor && tthis_fd !is null)
                 tf.mod = tthis_fd.mod;
         }
-        MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, pMessage, sc);
+        const(char)* failMessage;
+        const(char)** pMessage = errorHelper ? &failMessage : null;
+        MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, errorHelper, sc);
         //printf("test1: mfa = %d\n", mfa);
+        if (failMessage)
+            errorHelper(failMessage);
         if (mfa == MATCH.nomatch)
             return 0;
 
@@ -2850,7 +2876,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
             auto ti = new TemplateInstance(loc, td, tiargs);
             Objects dedtypes = Objects(td.parameters.length);
             assert(td.semanticRun != PASS.initial);
-            MATCH mta = td.matchWithInstance(sc, ti, &dedtypes, argumentList, 0);
+            MATCH mta = td.matchWithInstance(sc, ti, dedtypes, argumentList, 0);
             //printf("matchWithInstance = %d\n", mta);
             if (mta == MATCH.nomatch || mta < ta_last)   // no match or less match
                 return 0;
@@ -2869,7 +2895,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
                 // Check for recursive instantiation of tdx.
                 for (TemplatePrevious* p = tdx.previous; p; p = p.prev)
                 {
-                    if (arrayObjectMatch(p.dedargs, &dedtypesX))
+                    if (arrayObjectMatch(*p.dedargs, dedtypesX))
                     {
                         //printf("recursive, no match p.sc=%p %p %s\n", p.sc, this, this.toChars());
                         /* It must be a subscope of p.sc, other scope chains are not recursive
@@ -2918,7 +2944,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
 
             Type tthis_fd = fd.needThis() && !fd.isCtorDeclaration() ? tthis : null;
 
-            auto tf = cast(TypeFunction)fd.type;
+            auto tf = fd.type.isTypeFunction();
             MATCH mfa = tf.callMatch(tthis_fd, argumentList, 0, null, sc);
             if (mfa < m.last)
                 return 0;
@@ -2979,7 +3005,7 @@ void functionResolve(ref MatchAccumulator m, Dsymbol dstart, Loc loc, Scope* sc,
             if (isCtorCall)
             {
                 // Constructor call requires additional check.
-                auto tf = cast(TypeFunction)fd.type;
+                auto tf = fd.type.isTypeFunction();
                 assert(tf.next);
                 if (MODimplicitConv(tf.mod, tthis_fd.mod) ||
                     tf.isWild() && tf.isShared() == tthis_fd.isShared() ||
@@ -3175,9 +3201,8 @@ private size_t templateIdentifierLookup(Identifier id, TemplateParameters* param
 
 private size_t templateParameterLookup(Type tparam, TemplateParameters* parameters)
 {
-    if (tparam.ty == Tident)
+    if (TypeIdentifier tident = tparam.isTypeIdentifier())
     {
-        TypeIdentifier tident = cast(TypeIdentifier)tparam;
         //printf("\ttident = '%s'\n", tident.toChars());
         return templateIdentifierLookup(tident.ident, parameters);
     }
@@ -3267,7 +3292,7 @@ private Type rawTypeMerge(Type t1, Type t2)
     return null;
 }
 
-private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
+private MATCH deduceTypeHelper(Type t, out Type at, Type tparam)
 {
     // 9*9 == 81 cases
 
@@ -3297,7 +3322,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(U)                       shared(inout(const(T))) => shared(inout(const(T)))
         // foo(U)                       immutable(T)            => immutable(T)
         {
-            *at = t;
+            at = t;
             return MATCH.exact;
         }
     case X(MODFlags.const_, MODFlags.const_):
@@ -3317,7 +3342,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(shared(inout(const(U)))) shared(inout(const(T))) => T
         // foo(immutable(U))            immutable(T)            => T
         {
-            *at = t.mutableOf().unSharedOf();
+            at = t.mutableOf().unSharedOf();
             return MATCH.exact;
         }
     case X(MODFlags.const_, MODFlags.shared_ | MODFlags.const_):
@@ -3327,7 +3352,7 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(inout(U))                shared(inout(T))        => shared(T)
         // foo(inout(const(U)))         shared(inout(const(T))) => shared(T)
         {
-            *at = t.mutableOf();
+            at = t.mutableOf();
             return MATCH.exact;
         }
     case X(MODFlags.const_, 0):
@@ -3345,13 +3370,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(const(U))                immutable(T)            => T
         // foo(shared(const(U)))        immutable(T)            => T
         {
-            *at = t.mutableOf();
+            at = t.mutableOf();
             return MATCH.constant;
         }
     case X(MODFlags.const_, MODFlags.shared_):
         // foo(const(U))                shared(T)               => shared(T)
         {
-            *at = t;
+            at = t;
             return MATCH.constant;
         }
     case X(MODFlags.shared_, MODFlags.shared_ | MODFlags.const_):
@@ -3361,13 +3386,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(shared(U))               shared(inout(T))        => inout(T)
         // foo(shared(U))               shared(inout(const(T))) => inout(const(T))
         {
-            *at = t.unSharedOf();
+            at = t.unSharedOf();
             return MATCH.exact;
         }
     case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_):
         // foo(shared(const(U)))        shared(T)               => T
         {
-            *at = t.unSharedOf();
+            at = t.unSharedOf();
             return MATCH.constant;
         }
     case X(MODFlags.wildconst, MODFlags.immutable_):
@@ -3379,13 +3404,13 @@ private MATCH deduceTypeHelper(Type t, Type* at, Type tparam)
         // foo(shared(inout(const(U)))) immutable(T)            => T
         // foo(shared(inout(const(U)))) shared(inout(T))        => T
         {
-            *at = t.unSharedOf().mutableOf();
+            at = t.unSharedOf().mutableOf();
             return MATCH.constant;
         }
     case X(MODFlags.shared_ | MODFlags.const_, MODFlags.shared_ | MODFlags.wild):
         // foo(shared(const(U)))        shared(inout(T))        => T
         {
-            *at = t.unSharedOf().mutableOf();
+            at = t.unSharedOf().mutableOf();
             return MATCH.constant;
         }
     case X(MODFlags.wild, 0):
@@ -3499,30 +3524,16 @@ __gshared Expression emptyArrayElement = null;
  * Output:
  *      dedtypes = [ int ]      // Array of Expression/Type's
  */
-MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
+MATCH deduceType(RootObject o, Scope* sc, Type tparam, ref TemplateParameters parameters, ref Objects dedtypes, uint* wm = null, size_t inferStart = 0, bool ignoreAliasThis = false)
 {
     extern (C++) final class DeduceType : Visitor
     {
         alias visit = Visitor.visit;
     public:
-        Scope* sc;
-        Type tparam;
-        TemplateParameters* parameters;
-        Objects* dedtypes;
-        uint* wm;
-        size_t inferStart;
-        bool ignoreAliasThis;
         MATCH result;
 
-        extern (D) this(Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, uint* wm, size_t inferStart, bool ignoreAliasThis) @safe
+        extern (D) this() @safe
         {
-            this.sc = sc;
-            this.tparam = tparam;
-            this.parameters = parameters;
-            this.dedtypes = dedtypes;
-            this.wm = wm;
-            this.inferStart = inferStart;
-            this.ignoreAliasThis = ignoreAliasThis;
             result = MATCH.nomatch;
         }
 
@@ -3537,7 +3548,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             if (tparam.ty == Tident)
             {
                 // Determine which parameter tparam is
-                size_t i = templateParameterLookup(tparam, parameters);
+                size_t i = templateParameterLookup(tparam, &parameters);
                 if (i == IDX_NOTFOUND)
                 {
                     if (!sc)
@@ -3548,7 +3559,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     Loc loc;
                     if (parameters.length)
                     {
-                        TemplateParameter tp = (*parameters)[0];
+                        TemplateParameter tp = parameters[0];
                         loc = tp.loc;
                     }
 
@@ -3561,9 +3572,9 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     return;
                 }
 
-                TemplateParameter tp = (*parameters)[i];
+                TemplateParameter tp = parameters[i];
 
-                TypeIdentifier tident = cast(TypeIdentifier)tparam;
+                TypeIdentifier tident = tparam.isTypeIdentifier();
                 if (tident.idents.length > 0)
                 {
                     //printf("matching %s to %s\n", tparam.toChars(), t.toChars());
@@ -3601,21 +3612,21 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                         Type tt = s.getType();
                         if (!tt)
                             goto Lnomatch;
-                        Type at = cast(Type)(*dedtypes)[i];
+                        Type at = cast(Type)dedtypes[i];
                         if (at && at.ty == Tnone)
                             at = (cast(TypeDeduced)at).tded;
                         if (!at || tt.equals(at))
                         {
-                            (*dedtypes)[i] = tt;
+                            dedtypes[i] = tt;
                             goto Lexact;
                         }
                     }
                     if (tp.isTemplateAliasParameter())
                     {
-                        Dsymbol s2 = cast(Dsymbol)(*dedtypes)[i];
+                        Dsymbol s2 = cast(Dsymbol)dedtypes[i];
                         if (!s2 || s == s2)
                         {
-                            (*dedtypes)[i] = s;
+                            dedtypes[i] = s;
                             goto Lexact;
                         }
                     }
@@ -3637,7 +3648,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 +/
                 if (auto ta = tp.isTemplateAliasParameter())
                 {
-                    (*dedtypes)[i] = t;
+                    dedtypes[i] = t;
                     goto Lexact;
                 }
                 // (23578) - ensure previous behaviour for non-alias template params
@@ -3646,14 +3657,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     goto Lnomatch;
                 }
 
-                Type at = cast(Type)(*dedtypes)[i];
+                Type at = cast(Type)dedtypes[i];
                 Type tt;
                 if (ubyte wx = wm ? deduceWildHelper(t, &tt, tparam) : 0)
                 {
                     // type vs (none)
                     if (!at)
                     {
-                        (*dedtypes)[i] = tt;
+                        dedtypes[i] = tt;
                         *wm |= wx;
                         result = MATCH.constant;
                         return;
@@ -3662,11 +3673,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     // type vs expressions
                     if (at.ty == Tnone)
                     {
-                        TypeDeduced xt = cast(TypeDeduced)at;
+                        auto xt = cast(TypeDeduced)at;
                         result = xt.matchAll(tt);
                         if (result > MATCH.nomatch)
                         {
-                            (*dedtypes)[i] = tt;
+                            dedtypes[i] = tt;
                             if (result > MATCH.constant)
                                 result = MATCH.constant; // limit level for inout matches
                         }
@@ -3676,29 +3687,29 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     // type vs type
                     if (tt.equals(at))
                     {
-                        (*dedtypes)[i] = tt; // Prefer current type match
+                        dedtypes[i] = tt; // Prefer current type match
                         goto Lconst;
                     }
                     if (tt.implicitConvTo(at.constOf()))
                     {
-                        (*dedtypes)[i] = at.constOf().mutableOf();
+                        dedtypes[i] = at.constOf().mutableOf();
                         *wm |= MODFlags.const_;
                         goto Lconst;
                     }
                     if (at.implicitConvTo(tt.constOf()))
                     {
-                        (*dedtypes)[i] = tt.constOf().mutableOf();
+                        dedtypes[i] = tt.constOf().mutableOf();
                         *wm |= MODFlags.const_;
                         goto Lconst;
                     }
                     goto Lnomatch;
                 }
-                else if (MATCH m = deduceTypeHelper(t, &tt, tparam))
+                else if (MATCH m = deduceTypeHelper(t, tt, tparam))
                 {
                     // type vs (none)
                     if (!at)
                     {
-                        (*dedtypes)[i] = tt;
+                        dedtypes[i] = tt;
                         result = m;
                         return;
                     }
@@ -3706,11 +3717,11 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     // type vs expressions
                     if (at.ty == Tnone)
                     {
-                        TypeDeduced xt = cast(TypeDeduced)at;
+                        auto xt = cast(TypeDeduced)at;
                         result = xt.matchAll(tt);
                         if (result > MATCH.nomatch)
                         {
-                            (*dedtypes)[i] = tt;
+                            dedtypes[i] = tt;
                         }
                         return;
                     }
@@ -3740,7 +3751,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 Loc loc;
                 if (parameters.length)
                 {
-                    TemplateParameter tp = (*parameters)[0];
+                    TemplateParameter tp = parameters[0];
                     loc = tp.loc;
                 }
 
@@ -3757,9 +3768,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 MATCH m = t.implicitConvTo(tparam);
                 if (m == MATCH.nomatch && !ignoreAliasThis)
                 {
-                    if (t.ty == Tclass)
+                    if (auto tc = t.isTypeClass())
                     {
-                        TypeClass tc = cast(TypeClass)t;
                         if (tc.sym.aliasthis && !(tc.att & AliasThisRec.tracingDT))
                         {
                             if (auto ato = t.aliasthisOf())
@@ -3770,9 +3780,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                             }
                         }
                     }
-                    else if (t.ty == Tstruct)
+                    else if (auto ts = t.isTypeStruct())
                     {
-                        TypeStruct ts = cast(TypeStruct)t;
                         if (ts.sym.aliasthis && !(ts.att & AliasThisRec.tracingDT))
                         {
                             if (auto ato = t.aliasthisOf())
@@ -3822,9 +3831,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
 
         override void visit(TypeVector t)
         {
-            if (tparam.ty == Tvector)
+            if (auto tp = tparam.isTypeVector())
             {
-                TypeVector tp = cast(TypeVector)tparam;
                 result = deduceType(t.basetype, sc, tp.basetype, parameters, dedtypes, wm);
                 return;
             }
@@ -3851,25 +3859,23 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 TemplateParameter tp = null;
                 Expression edim = null;
                 size_t i;
-                if (tparam.ty == Tsarray)
+                if (auto tsa = tparam.isTypeSArray())
                 {
-                    TypeSArray tsa = cast(TypeSArray)tparam;
                     if (tsa.dim.isVarExp() && tsa.dim.isVarExp().var.storage_class & STC.templateparameter)
                     {
                         Identifier id = tsa.dim.isVarExp().var.ident;
-                        i = templateIdentifierLookup(id, parameters);
+                        i = templateIdentifierLookup(id, &parameters);
                         assert(i != IDX_NOTFOUND);
-                        tp = (*parameters)[i];
+                        tp = parameters[i];
                     }
                     else
                         edim = tsa.dim;
                 }
-                else if (tparam.ty == Taarray)
+                else if (auto taa = tparam.isTypeAArray())
                 {
-                    TypeAArray taa = cast(TypeAArray)tparam;
-                    i = templateParameterLookup(taa.index, parameters);
+                    i = templateParameterLookup(taa.index, &parameters);
                     if (i != IDX_NOTFOUND)
-                        tp = (*parameters)[i];
+                        tp = parameters[i];
                     else
                     {
                         Loc loc;
@@ -3878,7 +3884,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                         // so we use that for the resolution (better error message).
                         if (inferStart < parameters.length)
                         {
-                            TemplateParameter loctp = (*parameters)[inferStart];
+                            TemplateParameter loctp = parameters[inferStart];
                             loc = loctp.loc;
                         }
 
@@ -3889,7 +3895,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                         edim = s ? getValue(s) : getValue(e);
                     }
                 }
-                if (tp && tp.matchArg(sc, t.dim, i, parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
+                if (tp && tp.matchArg(sc, t.dim, i, &parameters, dedtypes, null) || edim && edim.toInteger() == t.dim.toInteger())
                 {
                     result = deduceType(t.next, sc, tparam.nextOf(), parameters, dedtypes, wm);
                     return;
@@ -3903,7 +3909,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Extra check that index type must match
             if (tparam && tparam.ty == Taarray)
             {
-                TypeAArray tp = cast(TypeAArray)tparam;
+                TypeAArray tp = tparam.isTypeAArray();
                 if (!deduceType(t.index, sc, tp.index, parameters, dedtypes))
                 {
                     result = MATCH.nomatch;
@@ -3936,7 +3942,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
 
                     // https://issues.dlang.org/show_bug.cgi?id=15243
                     // Resolve parameter type if it's not related with template parameters
-                    if (!reliesOnTemplateParameters(fparam.type, (*parameters)[inferStart .. parameters.length]))
+                    if (!reliesOnTemplateParameters(fparam.type, parameters[inferStart .. parameters.length]))
                     {
                         auto tx = fparam.type.typeSemantic(Loc.initial, sc);
                         if (tx.ty == Terror)
@@ -3948,7 +3954,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     }
                 }
 
-                size_t nfargs = t.parameterList.length;
+                const size_t nfargs = t.parameterList.length;
                 size_t nfparams = tp.parameterList.length;
 
                 /* See if tuple match
@@ -3963,7 +3969,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     assert(fparam.type);
                     if (fparam.type.ty != Tident)
                         goto L1;
-                    TypeIdentifier tid = cast(TypeIdentifier)fparam.type;
+                    TypeIdentifier tid = fparam.type.isTypeIdentifier();
                     if (tid.idents.length)
                         goto L1;
 
@@ -3974,7 +3980,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     {
                         if (tupi == parameters.length)
                             goto L1;
-                        TemplateParameter tx = (*parameters)[tupi];
+                        TemplateParameter tx = parameters[tupi];
                         TemplateTupleParameter tup = tx.isTemplateTupleParameter();
                         if (tup && tup.ident.equals(tid.ident))
                             break;
@@ -3987,7 +3993,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
 
                     /* See if existing tuple, and whether it matches or not
                      */
-                    RootObject o = (*dedtypes)[tupi];
+                    RootObject o = dedtypes[tupi];
                     if (o)
                     {
                         // Existing deduced argument must be a tuple, and must match
@@ -4016,7 +4022,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                             Parameter arg = t.parameterList[nfparams - 1 + i];
                             tup.objects[i] = arg.type;
                         }
-                        (*dedtypes)[tupi] = tup;
+                        dedtypes[tupi] = tup;
                     }
                     nfparams--; // don't consider the last parameter for type deduction
                     goto L2;
@@ -4053,7 +4059,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Extra check
             if (tparam && tparam.ty == Tident)
             {
-                TypeIdentifier tp = cast(TypeIdentifier)tparam;
+                TypeIdentifier tp = tparam.isTypeIdentifier();
                 for (size_t i = 0; i < t.idents.length; i++)
                 {
                     RootObject id1 = t.idents[i];
@@ -4076,7 +4082,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 TemplateDeclaration tempdecl = t.tempinst.tempdecl.isTemplateDeclaration();
                 assert(tempdecl);
 
-                TypeInstance tp = cast(TypeInstance)tparam;
+                TypeInstance tp = tparam.isTypeInstance();
 
                 //printf("tempinst.tempdecl = %p\n", tempdecl);
                 //printf("tp.tempinst.tempdecl = %p\n", tp.tempinst.tempdecl);
@@ -4087,7 +4093,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     /* Handle case of:
                      *  template Foo(T : sa!(T), alias sa)
                      */
-                    size_t i = templateIdentifierLookup(tp.tempinst.name, parameters);
+                    size_t i = templateIdentifierLookup(tp.tempinst.name, &parameters);
                     if (i == IDX_NOTFOUND)
                     {
                         /* Didn't find it as a parameter identifier. Try looking
@@ -4132,15 +4138,15 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                         goto Lnomatch;
                     }
 
-                    TemplateParameter tpx = (*parameters)[i];
-                    if (!tpx.matchArg(sc, tempdecl, i, parameters, dedtypes, null))
+                    TemplateParameter tpx = parameters[i];
+                    if (!tpx.matchArg(sc, tempdecl, i, &parameters, dedtypes, null))
                         goto Lnomatch;
                 }
                 else if (tempdecl != tp.tempinst.tempdecl)
                     goto Lnomatch;
 
             L2:
-                if (!resolveTemplateInstantiation(t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, dedtypes))
+                if (!resolveTemplateInstantiation(sc, &parameters, t.tempinst.tiargs, &t.tempinst.tdtypes, tempdecl, tp, &dedtypes))
                     goto Lnomatch;
             }
             visit(cast(Type)t);
@@ -4151,198 +4157,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             result = MATCH.nomatch;
         }
 
-        /********************
-         * Match template `parameters` to the target template instance.
-         * Example:
-         *    struct Temp(U, int Z) {}
-         *    void foo(T)(Temp!(T, 3));
-         *    foo(Temp!(int, 3)());
-         * Input:
-         *    this.parameters  = template params of foo -> [T]
-         *    tiargs           = <Temp!(int, 3)>.tiargs  -> [int, 3]
-         *    tdtypes          = <Temp!(int, 3)>.tdtypes -> [int, 3]
-         *    tempdecl         = <struct Temp!(T, int Z)> -> [T, Z]
-         *    tp               = <Temp!(T, 3)>
-         * Output:
-         *    dedtypes         = deduced params of `foo(Temp!(int, 3)())` -> [int]
-         */
-        private bool resolveTemplateInstantiation(Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
-        {
-            for (size_t i = 0; 1; i++)
-            {
-                //printf("\ttest: tempinst.tiargs[%zu]\n", i);
-                RootObject o1 = null;
-                if (i < tiargs.length)
-                    o1 = (*tiargs)[i];
-                else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
-                {
-                    // Pick up default arg
-                    o1 = (*tdtypes)[i];
-                }
-                else if (i >= tp.tempinst.tiargs.length)
-                    break;
-                //printf("\ttest: o1 = %s\n", o1.toChars());
-                if (i >= tp.tempinst.tiargs.length)
-                {
-                    size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
-                    while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
-                    {
-                        i++;
-                    }
-                    if (i >= dim)
-                        break; // match if all remained parameters are dependent
-                    return false;
-                }
-
-                RootObject o2 = (*tp.tempinst.tiargs)[i];
-                Type t2 = isType(o2);
-                //printf("\ttest: o2 = %s\n", o2.toChars());
-                size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
-                    ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
-                if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
-                    (*parameters)[j].isTemplateTupleParameter())
-                {
-                    /* Given:
-                         *  struct A(B...) {}
-                         *  alias A!(int, float) X;
-                         *  static if (is(X Y == A!(Z), Z...)) {}
-                         * deduce that Z is a tuple(int, float)
-                         */
-
-                    /* Create tuple from remaining args
-                         */
-                    size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
-                    auto vt = new Tuple(vtdim);
-                    for (size_t k = 0; k < vtdim; k++)
-                    {
-                        RootObject o;
-                        if (k < tiargs.length)
-                            o = (*tiargs)[i + k];
-                        else // Pick up default arg
-                            o = (*tdtypes)[i + k];
-                        vt.objects[k] = o;
-                    }
-
-                    Tuple v = cast(Tuple)(*dedtypes)[j];
-                    if (v)
-                    {
-                        if (!match(v, vt))
-                            return false;
-                    }
-                    else
-                        (*dedtypes)[j] = vt;
-                    break;
-                }
-                else if (!o1)
-                    break;
-
-                Type t1 = isType(o1);
-                Dsymbol s1 = isDsymbol(o1);
-                Dsymbol s2 = isDsymbol(o2);
-                Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
-                Expression e2 = isExpression(o2);
-                version (none)
-                {
-                    Tuple v1 = isTuple(o1);
-                    Tuple v2 = isTuple(o2);
-                    if (t1)
-                        printf("t1 = %s\n", t1.toChars());
-                    if (t2)
-                        printf("t2 = %s\n", t2.toChars());
-                    if (e1)
-                        printf("e1 = %s\n", e1.toChars());
-                    if (e2)
-                        printf("e2 = %s\n", e2.toChars());
-                    if (s1)
-                        printf("s1 = %s\n", s1.toChars());
-                    if (s2)
-                        printf("s2 = %s\n", s2.toChars());
-                    if (v1)
-                        printf("v1 = %s\n", v1.toChars());
-                    if (v2)
-                        printf("v2 = %s\n", v2.toChars());
-                }
-
-                if (t1 && t2)
-                {
-                    if (!deduceType(t1, sc, t2, parameters, dedtypes))
-                        return false;
-                }
-                else if (e1 && e2)
-                {
-                Le:
-                    e1 = e1.ctfeInterpret();
-
-                    /* If it is one of the template parameters for this template,
-                         * we should not attempt to interpret it. It already has a value.
-                         */
-                    if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
-                    {
-                        /*
-                             * (T:Number!(e2), int e2)
-                             */
-                        j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
-                        if (j != IDX_NOTFOUND)
-                            goto L1;
-                        // The template parameter was not from this template
-                        // (it may be from a parent template, for example)
-                    }
-
-                    e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
-                    e2 = e2.ctfeInterpret();
-
-                    //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
-                    //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
-                    if (!e1.equals(e2))
-                    {
-                        if (!e2.implicitConvTo(e1.type))
-                            return false;
-
-                        e2 = e2.implicitCastTo(sc, e1.type);
-                        e2 = e2.ctfeInterpret();
-                        if (!e1.equals(e2))
-                            return false;
-                    }
-                }
-                else if (e1 && t2 && t2.ty == Tident)
-                {
-                    j = templateParameterLookup(t2, parameters);
-                L1:
-                    if (j == IDX_NOTFOUND)
-                    {
-                        t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
-                        if (e2)
-                            goto Le;
-                        return false;
-                    }
-                    if (!(*parameters)[j].matchArg(sc, e1, j, parameters, dedtypes, null))
-                        return false;
-                }
-                else if (s1 && s2)
-                {
-                Ls:
-                    if (!s1.equals(s2))
-                        return false;
-                }
-                else if (s1 && t2 && t2.ty == Tident)
-                {
-                    j = templateParameterLookup(t2, parameters);
-                    if (j == IDX_NOTFOUND)
-                    {
-                        t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
-                        if (s2)
-                            goto Ls;
-                        return false;
-                    }
-                    if (!(*parameters)[j].matchArg(sc, s1, j, parameters, dedtypes, null))
-                        return false;
-                }
-                else
-                    return false;
-            }
-            return true;
-        }
-
         override void visit(TypeStruct t)
         {
             /* If this struct is a template struct, and we're matching
@@ -4368,7 +4182,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 /* Match things like:
                  *  S!(T).foo
                  */
-                TypeInstance tpi = cast(TypeInstance)tparam;
+                TypeInstance tpi = tparam.isTypeInstance();
                 if (tpi.idents.length)
                 {
                     RootObject id = tpi.idents[tpi.idents.length - 1];
@@ -4391,7 +4205,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Extra check
             if (tparam && tparam.ty == Tstruct)
             {
-                TypeStruct tp = cast(TypeStruct)tparam;
+                TypeStruct tp = tparam.isTypeStruct();
 
                 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
                 if (wm && t.deduceWild(tparam, false))
@@ -4410,7 +4224,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Extra check
             if (tparam && tparam.ty == Tenum)
             {
-                TypeEnum tp = cast(TypeEnum)tparam;
+                TypeEnum tp = tparam.isTypeEnum();
                 if (t.sym == tp.sym)
                     visit(cast(Type)t);
                 else
@@ -4428,59 +4242,6 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             visit(cast(Type)t);
         }
 
-        /* Helper for TypeClass.deduceType().
-         * Classes can match with implicit conversion to a base class or interface.
-         * This is complicated, because there may be more than one base class which
-         * matches. In such cases, one or more parameters remain ambiguous.
-         * For example,
-         *
-         *   interface I(X, Y) {}
-         *   class C : I(uint, double), I(char, double) {}
-         *   C x;
-         *   foo(T, U)( I!(T, U) x)
-         *
-         *   deduces that U is double, but T remains ambiguous (could be char or uint).
-         *
-         * Given a baseclass b, and initial deduced types 'dedtypes', this function
-         * tries to match tparam with b, and also tries all base interfaces of b.
-         * If a match occurs, numBaseClassMatches is incremented, and the new deduced
-         * types are ANDed with the current 'best' estimate for dedtypes.
-         */
-        static void deduceBaseClassParameters(ref BaseClass b, Scope* sc, Type tparam, TemplateParameters* parameters, Objects* dedtypes, Objects* best, ref int numBaseClassMatches)
-        {
-            TemplateInstance parti = b.sym ? b.sym.parent.isTemplateInstance() : null;
-            if (parti)
-            {
-                // Make a temporary copy of dedtypes so we don't destroy it
-                auto tmpdedtypes = new Objects(dedtypes.length);
-                memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
-
-                auto t = new TypeInstance(Loc.initial, parti);
-                MATCH m = deduceType(t, sc, tparam, parameters, tmpdedtypes);
-                if (m > MATCH.nomatch)
-                {
-                    // If this is the first ever match, it becomes our best estimate
-                    if (numBaseClassMatches == 0)
-                        memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
-                    else
-                        for (size_t k = 0; k < tmpdedtypes.length; ++k)
-                        {
-                            // If we've found more than one possible type for a parameter,
-                            // mark it as unknown.
-                            if ((*tmpdedtypes)[k] != (*best)[k])
-                                (*best)[k] = (*dedtypes)[k];
-                        }
-                    ++numBaseClassMatches;
-                }
-            }
-
-            // Now recursively test the inherited interfaces
-            foreach (ref bi; b.baseInterfaces)
-            {
-                deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
-            }
-        }
-
         override void visit(TypeClass t)
         {
             //printf("TypeClass.deduceType(this = %s)\n", t.toChars());
@@ -4509,7 +4270,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 /* Match things like:
                  *  S!(T).foo
                  */
-                TypeInstance tpi = cast(TypeInstance)tparam;
+                TypeInstance tpi = tparam.isTypeInstance();
                 if (tpi.idents.length)
                 {
                     RootObject id = tpi.idents[tpi.idents.length - 1];
@@ -4547,12 +4308,12 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 while (s && s.baseclasses.length > 0)
                 {
                     // Test the base class
-                    deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+                    deduceBaseClassParameters(*(*s.baseclasses)[0], sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
 
                     // Test the interfaces inherited by the base class
                     foreach (b; s.interfaces)
                     {
-                        deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+                        deduceBaseClassParameters(*b, sc, tparam, parameters, dedtypes, *best, numBaseClassMatches);
                     }
                     s = (*s.baseclasses)[0].sym;
                 }
@@ -4572,7 +4333,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Extra check
             if (tparam && tparam.ty == Tclass)
             {
-                TypeClass tp = cast(TypeClass)tparam;
+                TypeClass tp = tparam.isTypeClass();
 
                 //printf("\t%d\n", cast(MATCH) t.implicitConvTo(tp));
                 if (wm && t.deduceWild(tparam, false))
@@ -4589,8 +4350,8 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
         override void visit(Expression e)
         {
             //printf("Expression.deduceType(e = %s)\n", e.toChars());
-            size_t i = templateParameterLookup(tparam, parameters);
-            if (i == IDX_NOTFOUND || (cast(TypeIdentifier)tparam).idents.length > 0)
+            size_t i = templateParameterLookup(tparam, &parameters);
+            if (i == IDX_NOTFOUND || tparam.isTypeIdentifier().idents.length > 0)
             {
                 if (e == emptyArrayElement && tparam.ty == Tarray)
                 {
@@ -4602,13 +4363,13 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 return;
             }
 
-            TemplateTypeParameter tp = (*parameters)[i].isTemplateTypeParameter();
+            TemplateTypeParameter tp = parameters[i].isTemplateTypeParameter();
             if (!tp)
                 return; // nomatch
 
             if (e == emptyArrayElement)
             {
-                if ((*dedtypes)[i])
+                if (dedtypes[i])
                 {
                     result = MATCH.exact;
                     return;
@@ -4630,14 +4391,14 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                        tb.ty == Tstruct && tb.hasPointers();
             }
 
-            Type at = cast(Type)(*dedtypes)[i];
+            Type at = cast(Type)dedtypes[i];
             Type tt;
             if (ubyte wx = deduceWildHelper(e.type, &tt, tparam))
             {
                 *wm |= wx;
                 result = MATCH.constant;
             }
-            else if (MATCH m = deduceTypeHelper(e.type, &tt, tparam))
+            else if (MATCH m = deduceTypeHelper(e.type, tt, tparam))
             {
                 result = m;
             }
@@ -4658,7 +4419,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // expression vs (none)
             if (!at)
             {
-                (*dedtypes)[i] = new TypeDeduced(tt, e, tparam);
+                dedtypes[i] = new TypeDeduced(tt, e, tparam);
                 return;
             }
 
@@ -4716,7 +4477,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 if (xt)
                     xt.update(tt, e, tparam);
                 else
-                    (*dedtypes)[i] = tt;
+                    dedtypes[i] = tt;
                 result = match1;
                 return;
             }
@@ -4736,7 +4497,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                 if (xt)
                     xt.update(t, e, tparam);
                 else
-                    (*dedtypes)[i] = t;
+                    dedtypes[i] = t;
 
                 pt = tt.addMod(tparam.mod);
                 if (*wm)
@@ -4870,7 +4631,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
 
                 // Parameter types inference from 'tof'
                 assert(e.td._scope);
-                TypeFunction tf = cast(TypeFunction)e.fd.type;
+                TypeFunction tf = e.fd.type.isTypeFunction();
                 //printf("\ttof = %s\n", tof.toChars());
                 //printf("\ttf  = %s\n", tf.toChars());
                 const dim = tf.parameterList.length;
@@ -4895,7 +4656,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
                     if (!pto)
                         break;
                     Type t = pto.type.syntaxCopy(); // https://issues.dlang.org/show_bug.cgi?id=11774
-                    if (reliesOnTemplateParameters(t, (*parameters)[inferStart .. parameters.length]))
+                    if (reliesOnTemplateParameters(t, parameters[inferStart .. parameters.length]))
                         return;
                     t = t.typeSemantic(e.loc, sc);
                     if (t.ty == Terror)
@@ -4929,7 +4690,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
             // Allow conversion from implicit function pointer to delegate
             if (e.tok == TOK.reserved && t.ty == Tpointer && tparam.ty == Tdelegate)
             {
-                TypeFunction tf = cast(TypeFunction)t.nextOf();
+                TypeFunction tf = t.nextOf().isTypeFunction();
                 t = (new TypeDelegate(tf)).merge();
             }
             //printf("tparam = %s <= e.type = %s, t = %s\n", tparam.toChars(), e.type.toChars(), t.toChars());
@@ -4959,7 +4720,7 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
         }
     }
 
-    scope DeduceType v = new DeduceType(sc, tparam, parameters, dedtypes, wm, inferStart, ignoreAliasThis);
+    scope DeduceType v = new DeduceType();
     if (Type t = isType(o))
         t.accept(v);
     else if (Expression e = isExpression(o))
@@ -4972,6 +4733,254 @@ MATCH deduceType(RootObject o, Scope* sc, Type tparam, TemplateParameters* param
     return v.result;
 }
 
+
+/* Helper for TypeClass.deduceType().
+ * Classes can match with implicit conversion to a base class or interface.
+ * This is complicated, because there may be more than one base class which
+ * matches. In such cases, one or more parameters remain ambiguous.
+ * For example,
+ *
+ *   interface I(X, Y) {}
+ *   class C : I(uint, double), I(char, double) {}
+ *   C x;
+ *   foo(T, U)( I!(T, U) x)
+ *
+ *   deduces that U is double, but T remains ambiguous (could be char or uint).
+ *
+ * Given a baseclass b, and initial deduced types 'dedtypes', this function
+ * tries to match tparam with b, and also tries all base interfaces of b.
+ * If a match occurs, numBaseClassMatches is incremented, and the new deduced
+ * types are ANDed with the current 'best' estimate for dedtypes.
+ */
+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)
+    {
+        // Make a temporary copy of dedtypes so we don't destroy it
+        auto tmpdedtypes = new Objects(dedtypes.length);
+        memcpy(tmpdedtypes.tdata(), dedtypes.tdata(), dedtypes.length * (void*).sizeof);
+
+        auto t = new TypeInstance(Loc.initial, parti);
+        MATCH m = deduceType(t, sc, tparam, parameters, *tmpdedtypes);
+        if (m > MATCH.nomatch)
+        {
+            // If this is the first ever match, it becomes our best estimate
+            if (numBaseClassMatches == 0)
+                memcpy(best.tdata(), tmpdedtypes.tdata(), tmpdedtypes.length * (void*).sizeof);
+            else
+                for (size_t k = 0; k < tmpdedtypes.length; ++k)
+                {
+                    // If we've found more than one possible type for a parameter,
+                    // mark it as unknown.
+                    if ((*tmpdedtypes)[k] != best[k])
+                        best[k] = dedtypes[k];
+                }
+            ++numBaseClassMatches;
+        }
+    }
+
+    // Now recursively test the inherited interfaces
+    foreach (ref bi; b.baseInterfaces)
+    {
+        deduceBaseClassParameters(bi, sc, tparam, parameters, dedtypes, best, numBaseClassMatches);
+    }
+}
+
+/********************
+ * Match template `parameters` to the target template instance.
+ * Example:
+ *    struct Temp(U, int Z) {}
+ *    void foo(T)(Temp!(T, 3));
+ *    foo(Temp!(int, 3)());
+ * Input:
+ *    sc               = context
+ *    parameters       = template params of foo -> [T]
+ *    tiargs           = <Temp!(int, 3)>.tiargs  -> [int, 3]
+ *    tdtypes          = <Temp!(int, 3)>.tdtypes -> [int, 3]
+ *    tempdecl         = <struct Temp!(T, int Z)> -> [T, Z]
+ *    tp               = <Temp!(T, 3)>
+ * Output:
+ *    dedtypes         = deduced params of `foo(Temp!(int, 3)())` -> [int]
+ */
+private bool resolveTemplateInstantiation(Scope* sc, TemplateParameters* parameters, Objects* tiargs, Objects* tdtypes, TemplateDeclaration tempdecl, TypeInstance tp, Objects* dedtypes)
+{
+    for (size_t i = 0; 1; i++)
+    {
+        //printf("\ttest: tempinst.tiargs[%zu]\n", i);
+        RootObject o1 = null;
+        if (i < tiargs.length)
+            o1 = (*tiargs)[i];
+        else if (i < tdtypes.length && i < tp.tempinst.tiargs.length)
+        {
+            // Pick up default arg
+            o1 = (*tdtypes)[i];
+        }
+        else if (i >= tp.tempinst.tiargs.length)
+            break;
+        //printf("\ttest: o1 = %s\n", o1.toChars());
+        if (i >= tp.tempinst.tiargs.length)
+        {
+            size_t dim = tempdecl.parameters.length - (tempdecl.isVariadic() ? 1 : 0);
+            while (i < dim && ((*tempdecl.parameters)[i].dependent || (*tempdecl.parameters)[i].hasDefaultArg()))
+            {
+                i++;
+            }
+            if (i >= dim)
+                break; // match if all remained parameters are dependent
+            return false;
+        }
+
+        RootObject o2 = (*tp.tempinst.tiargs)[i];
+        Type t2 = isType(o2);
+        //printf("\ttest: o2 = %s\n", o2.toChars());
+        size_t j = (t2 && t2.ty == Tident && i == tp.tempinst.tiargs.length - 1)
+            ? templateParameterLookup(t2, parameters) : IDX_NOTFOUND;
+        if (j != IDX_NOTFOUND && j == parameters.length - 1 &&
+            (*parameters)[j].isTemplateTupleParameter())
+        {
+            /* Given:
+                 *  struct A(B...) {}
+                 *  alias A!(int, float) X;
+                 *  static if (is(X Y == A!(Z), Z...)) {}
+                 * deduce that Z is a tuple(int, float)
+                 */
+
+            /* Create tuple from remaining args
+                 */
+            size_t vtdim = (tempdecl.isVariadic() ? tiargs.length : tdtypes.length) - i;
+            auto vt = new Tuple(vtdim);
+            for (size_t k = 0; k < vtdim; k++)
+            {
+                RootObject o;
+                if (k < tiargs.length)
+                    o = (*tiargs)[i + k];
+                else // Pick up default arg
+                    o = (*tdtypes)[i + k];
+                vt.objects[k] = o;
+            }
+
+            Tuple v = cast(Tuple)(*dedtypes)[j];
+            if (v)
+            {
+                if (!match(v, vt))
+                    return false;
+            }
+            else
+                (*dedtypes)[j] = vt;
+            break;
+        }
+        else if (!o1)
+            break;
+
+        Type t1 = isType(o1);
+        Dsymbol s1 = isDsymbol(o1);
+        Dsymbol s2 = isDsymbol(o2);
+        Expression e1 = s1 ? getValue(s1) : getValue(isExpression(o1));
+        Expression e2 = isExpression(o2);
+        version (none)
+        {
+            Tuple v1 = isTuple(o1);
+            Tuple v2 = isTuple(o2);
+            if (t1)
+                printf("t1 = %s\n", t1.toChars());
+            if (t2)
+                printf("t2 = %s\n", t2.toChars());
+            if (e1)
+                printf("e1 = %s\n", e1.toChars());
+            if (e2)
+                printf("e2 = %s\n", e2.toChars());
+            if (s1)
+                printf("s1 = %s\n", s1.toChars());
+            if (s2)
+                printf("s2 = %s\n", s2.toChars());
+            if (v1)
+                printf("v1 = %s\n", v1.toChars());
+            if (v2)
+                printf("v2 = %s\n", v2.toChars());
+        }
+
+        if (t1 && t2)
+        {
+            if (!deduceType(t1, sc, t2, *parameters, *dedtypes))
+                return false;
+        }
+        else if (e1 && e2)
+        {
+        Le:
+            e1 = e1.ctfeInterpret();
+
+            /* If it is one of the template parameters for this template,
+                 * we should not attempt to interpret it. It already has a value.
+                 */
+            if (e2.op == EXP.variable && (e2.isVarExp().var.storage_class & STC.templateparameter))
+            {
+                /*
+                     * (T:Number!(e2), int e2)
+                     */
+                j = templateIdentifierLookup(e2.isVarExp().var.ident, parameters);
+                if (j != IDX_NOTFOUND)
+                    goto L1;
+                // The template parameter was not from this template
+                // (it may be from a parent template, for example)
+            }
+
+            e2 = e2.expressionSemantic(sc); // https://issues.dlang.org/show_bug.cgi?id=13417
+            e2 = e2.ctfeInterpret();
+
+            //printf("e1 = %s, type = %s %d\n", e1.toChars(), e1.type.toChars(), e1.type.ty);
+            //printf("e2 = %s, type = %s %d\n", e2.toChars(), e2.type.toChars(), e2.type.ty);
+            if (!e1.equals(e2))
+            {
+                if (!e2.implicitConvTo(e1.type))
+                    return false;
+
+                e2 = e2.implicitCastTo(sc, e1.type);
+                e2 = e2.ctfeInterpret();
+                if (!e1.equals(e2))
+                    return false;
+            }
+        }
+        else if (e1 && t2 && t2.ty == Tident)
+        {
+            j = templateParameterLookup(t2, parameters);
+        L1:
+            if (j == IDX_NOTFOUND)
+            {
+                t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+                if (e2)
+                    goto Le;
+                return false;
+            }
+            if (!(*parameters)[j].matchArg(sc, e1, j, parameters, *dedtypes, null))
+                return false;
+        }
+        else if (s1 && s2)
+        {
+        Ls:
+            if (!s1.equals(s2))
+                return false;
+        }
+        else if (s1 && t2 && t2.ty == Tident)
+        {
+            j = templateParameterLookup(t2, parameters);
+            if (j == IDX_NOTFOUND)
+            {
+                t2.resolve((cast(TypeIdentifier)t2).loc, sc, e2, t2, s2);
+                if (s2)
+                    goto Ls;
+                return false;
+            }
+            if (!(*parameters)[j].matchArg(sc, s1, j, parameters, *dedtypes, null))
+                return false;
+        }
+        else
+            return false;
+    }
+    return true;
+}
+
+
 /***********************************************************
  * Check whether the type t representation relies on one or more the template parameters.
  * Params:
@@ -5625,7 +5634,11 @@ extern (C++) final class TemplateValueParameter : TemplateParameter
         if (e)
         {
             e = e.syntaxCopy();
-            if ((e = e.expressionSemantic(sc)) is null)
+            Scope* sc2 = sc.push();
+            sc2.inDefaultArg = true;
+            e = e.expressionSemantic(sc2);
+            sc2.pop();
+            if (e is null)
                 return null;
             if (auto te = e.isTemplateExp())
             {
@@ -6176,7 +6189,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         }
         //printf("parent = %s, ti.parent = %s\n", parent.toPrettyChars(), ti.parent.toPrettyChars());
 
-        if (!arrayObjectMatch(&tdtypes, &ti.tdtypes))
+        if (!arrayObjectMatch(tdtypes, ti.tdtypes))
             goto Lnotequals;
 
         /* Template functions may have different instantiations based on
@@ -6221,7 +6234,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         if (!hash)
         {
             hash = cast(size_t)cast(void*)enclosing;
-            hash += arrayObjectHash(&tdtypes);
+            hash += arrayObjectHash(tdtypes);
             hash += hash == 0;
         }
         return hash;
@@ -6691,6 +6704,12 @@ extern (C++) class TemplateInstance : ScopeDsymbol
         if (!tiargs)
             return true;
         bool err = false;
+
+        // The arguments are not treated as part of a default argument,
+        // because they are evaluated at compile time.
+        sc = sc.push();
+        sc.inDefaultArg = false;
+
         for (size_t j = 0; j < tiargs.length; j++)
         {
             RootObject o = (*tiargs)[j];
@@ -6716,10 +6735,9 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                 }
 
             Ltype:
-                if (ta.ty == Ttuple)
+                if (TypeTuple tt = ta.isTypeTuple())
                 {
                     // Expand tuple
-                    TypeTuple tt = cast(TypeTuple)ta;
                     size_t dim = tt.arguments.length;
                     tiargs.remove(j);
                     if (dim)
@@ -6923,6 +6941,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             }
             //printf("1: (*tiargs)[%d] = %p\n", j, (*tiargs)[j]);
         }
+        sc.pop();
         version (none)
         {
             printf("-TemplateInstance.semanticTiargs()\n");
@@ -6982,7 +7001,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
             assert(tempdecl._scope);
             // Deduce tdtypes
             tdtypes.setDim(tempdecl.parameters.length);
-            if (!tempdecl.matchWithInstance(sc, this, &tdtypes, argumentList, 2))
+            if (!tempdecl.matchWithInstance(sc, this, tdtypes, argumentList, 2))
             {
                 .error(loc, "%s `%s` incompatible arguments for template instantiation", kind, toPrettyChars);
                 return false;
@@ -7032,7 +7051,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                 dedtypes.zero();
                 assert(td.semanticRun != PASS.initial);
 
-                MATCH m = td.matchWithInstance(sc, this, &dedtypes, argumentList, 0);
+                MATCH m = td.matchWithInstance(sc, this, dedtypes, argumentList, 0);
                 //printf("matchWithInstance = %d\n", m);
                 if (m == MATCH.nomatch) // no match at all
                     return 0;
@@ -7158,7 +7177,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                         // print additional information, e.g. `foo` is not a type
                         foreach (i, param; *tdecl.parameters)
                         {
-                            MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, &dedtypes, null);
+                            MATCH match = param.matchArg(loc, sc, tiargs, i, tdecl.parameters, dedtypes, null);
                             auto arg = (*tiargs)[i];
                             auto sym = arg.isDsymbol;
                             auto exp = arg.isExpression;
@@ -7262,7 +7281,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                  * to instantiate the template.
                  */
                 //printf("tp = %p, td.parameters.length = %d, tiargs.length = %d\n", tp, td.parameters.length, tiargs.length);
-                auto tf = cast(TypeFunction)fd.type;
+                auto tf = fd.type.isTypeFunction();
                 if (tf.parameterList.length)
                 {
                     auto tp = td.isVariadic();
@@ -7308,7 +7327,7 @@ extern (C++) class TemplateInstance : ScopeDsymbol
                             return 1;
                         }
                     }
-                    MATCH m = td.matchWithInstance(sc, this, &dedtypes, ArgumentList(), 0);
+                    MATCH m = td.matchWithInstance(sc, this, dedtypes, ArgumentList(), 0);
                     if (m == MATCH.nomatch)
                         return 0;
                 }
@@ -7992,7 +8011,7 @@ struct TemplateInstanceBox
  *      dedtypes[]      deduced arguments to template instance
  *      *psparam        set to symbol declared and initialized to dedtypes[i]
  */
-MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
 {
     MATCH matchArgNoMatch()
     {
@@ -8015,7 +8034,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
             {
                 assert(i < dedtypes.length);
                 // It might have already been deduced
-                oarg = (*dedtypes)[i];
+                oarg = dedtypes[i];
                 if (!oarg)
                     return matchArgNoMatch();
             }
@@ -8031,7 +8050,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
         assert(i + 1 == dedtypes.length); // must be the last one
         Tuple ovar;
 
-        if (Tuple u = isTuple((*dedtypes)[i]))
+        if (Tuple u = isTuple(dedtypes[i]))
         {
             // It has already been deduced
             ovar = u;
@@ -8059,7 +8078,7 @@ MATCH matchArg(TemplateParameter tp, Loc instLoc, Scope* sc, Objects* tiargs, si
         return matchArgParameter();
 }
 
-MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, Objects* dedtypes, Declaration* psparam)
+MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, TemplateParameters* parameters, ref Objects dedtypes, Declaration* psparam)
 {
     MATCH matchArgNoMatch()
     {
@@ -8087,7 +8106,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
                 return matchArgNoMatch();
 
             //printf("\tcalling deduceType(): ta is %s, specType is %s\n", ta.toChars(), ttp.specType.toChars());
-            MATCH m2 = deduceType(ta, sc, ttp.specType, parameters, dedtypes);
+            MATCH m2 = deduceType(ta, sc, ttp.specType, *parameters, dedtypes);
             if (m2 == MATCH.nomatch)
             {
                 //printf("\tfailed deduceType\n");
@@ -8096,9 +8115,9 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
 
             if (m2 < m)
                 m = m2;
-            if ((*dedtypes)[i])
+            if (dedtypes[i])
             {
-                Type t = cast(Type)(*dedtypes)[i];
+                Type t = cast(Type)dedtypes[i];
 
                 if (ttp.dependent && !t.equals(ta)) // https://issues.dlang.org/show_bug.cgi?id=14357
                     return matchArgNoMatch();
@@ -8113,10 +8132,10 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
         }
         else
         {
-            if ((*dedtypes)[i])
+            if (dedtypes[i])
             {
                 // Must match already deduced type
-                Type t = cast(Type)(*dedtypes)[i];
+                Type t = cast(Type)dedtypes[i];
 
                 if (!t.equals(ta))
                 {
@@ -8130,7 +8149,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
                 m = MATCH.convert;
             }
         }
-        (*dedtypes)[i] = ta;
+        dedtypes[i] = ta;
 
         if (psparam)
             *psparam = new AliasDeclaration(ttp.loc, ttp.ident, ta);
@@ -8235,15 +8254,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
         }
         else
         {
-            if ((*dedtypes)[i])
+            if (dedtypes[i])
             {
                 // Must match already deduced value
-                Expression e = cast(Expression)(*dedtypes)[i];
+                Expression e = cast(Expression)dedtypes[i];
                 if (!ei || !ei.equals(e))
                     return matchArgNoMatch();
             }
         }
-        (*dedtypes)[i] = ei;
+        dedtypes[i] = ei;
 
         if (psparam)
         {
@@ -8354,7 +8373,7 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
                     return matchArgNoMatch();
 
                 Type t = new TypeInstance(Loc.initial, ti);
-                MATCH m2 = deduceType(t, sc, talias, parameters, dedtypes);
+                MATCH m2 = deduceType(t, sc, talias, *parameters, dedtypes);
                 if (m2 == MATCH.nomatch)
                     return matchArgNoMatch();
             }
@@ -8375,14 +8394,14 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
                 }
             }
         }
-        else if ((*dedtypes)[i])
+        else if (dedtypes[i])
         {
             // Must match already deduced symbol
-            RootObject si = (*dedtypes)[i];
+            RootObject si = dedtypes[i];
             if (!sa || si != sa)
                 return matchArgNoMatch();
         }
-        (*dedtypes)[i] = sa;
+        dedtypes[i] = sa;
 
         if (psparam)
         {
@@ -8415,15 +8434,15 @@ MATCH matchArg(TemplateParameter tp, Scope* sc, RootObject oarg, size_t i, Templ
         Tuple ovar = isTuple(oarg);
         if (!ovar)
             return MATCH.nomatch;
-        if ((*dedtypes)[i])
+        if (dedtypes[i])
         {
-            Tuple tup = isTuple((*dedtypes)[i]);
+            Tuple tup = isTuple(dedtypes[i]);
             if (!tup)
                 return MATCH.nomatch;
             if (!match(tup, ovar))
                 return MATCH.nomatch;
         }
-        (*dedtypes)[i] = ovar;
+        dedtypes[i] = ovar;
 
         if (psparam)
             *psparam = new TupleDeclaration(ttp.loc, ttp.ident, &ovar.objects);
@@ -8457,21 +8476,24 @@ struct TemplateStats
 
     /*******************************
      * Add this instance
+     * Params:
+     *  td = template declaration
+     *  ti = instance of td
+     *  listInstances = keep track of instances of templates
      */
     static void incInstance(const TemplateDeclaration td,
-                            const TemplateInstance ti)
+                            const TemplateInstance ti,
+                            bool listInstances)
     {
         void log(ref TemplateStats ts)
         {
             if (ts.allInstances is null)
                 ts.allInstances = new TemplateInstances();
-            if (global.params.v.templatesListInstances)
+            if (listInstances)
                 ts.allInstances.push(cast() ti);
         }
 
-    // message(ti.loc, "incInstance %p %p", td, ti);
-        if (!global.params.v.templates)
-            return;
+        // message(ti.loc, "incInstance %p %p", td, ti);
         if (!td)
             return;
         assert(ti);
@@ -8494,8 +8516,6 @@ struct TemplateStats
                           const TemplateInstance ti)
     {
         // message(ti.loc, "incUnique %p %p", td, ti);
-        if (!global.params.v.templates)
-            return;
         if (!td)
             return;
         assert(ti);
@@ -8506,7 +8526,13 @@ struct TemplateStats
     }
 }
 
-extern (C++) void printTemplateStats()
+/********************************
+ * Print informational statistics on template instantiations.
+ * Params:
+ *      listInstances = list instances of templates
+ *      eSink = where the print is sent
+ */
+extern (C++) void printTemplateStats(bool listInstances, ErrorSink eSink)
 {
     static struct TemplateDeclarationStats
     {
@@ -8523,11 +8549,12 @@ extern (C++) void printTemplateStats()
         }
     }
 
-    if (!global.params.v.templates)
-        return;
+    const stats_length = TemplateStats.stats.length;
+    if (!stats_length)
+        return;         // nothing to report
 
     Array!(TemplateDeclarationStats) sortedStats;
-    sortedStats.reserve(TemplateStats.stats.length);
+    sortedStats.reserve(stats_length);
     foreach (td_, ref ts; TemplateStats.stats)
     {
         sortedStats.push(TemplateDeclarationStats(cast(TemplateDeclaration) td_, ts));
@@ -8537,10 +8564,9 @@ extern (C++) void printTemplateStats()
 
     foreach (const ref ss; sortedStats[])
     {
-        if (global.params.v.templatesListInstances &&
-            ss.ts.allInstances)
+        if (listInstances && ss.ts.allInstances)
         {
-            message(ss.td.loc,
+            eSink.message(ss.td.loc,
                     "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found, they are:",
                     ss.ts.numInstantiations,
                     ss.ts.uniqueInstantiations,
@@ -8548,14 +8574,14 @@ extern (C++) void printTemplateStats()
             foreach (const ti; (*ss.ts.allInstances)[])
             {
                 if (ti.tinst)   // if has enclosing instance
-                    message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
+                    eSink.message(ti.loc, "vtemplate: implicit instance `%s`", ti.toChars());
                 else
-                    message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
+                    eSink.message(ti.loc, "vtemplate: explicit instance `%s`", ti.toChars());
             }
         }
         else
         {
-            message(ss.td.loc,
+            eSink.message(ss.td.loc,
                     "vtemplate: %u (%u distinct) instantiation(s) of template `%s` found",
                     ss.ts.numInstantiations,
                     ss.ts.uniqueInstantiations,
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 30991c9171a..2bfa96cf76b 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -779,6 +779,17 @@ public:
             }
         }
 
+        if (tf && tf.next)
+        {
+            // Ensure return type is declared before a function that returns that is declared.
+            if (auto sty = tf.next.isTypeStruct())
+                ensureDeclared(sty.sym);
+            //else if (auto cty = tf.next.isTypeClass())
+            //    includeSymbol(cty.sym); // classes are returned by pointer only need to forward declare
+            //else if (auto ety = tf.next.isTypeEnum())
+            //    ensureDeclared(ety.sym);
+        }
+
         writeProtection(fd.visibility.kind);
 
         if (tf && tf.linkage == LINK.c)
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 433907a17be..3e17ff4736d 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -34,6 +34,7 @@ import dmd.mtype;
 import dmd.printast;
 import dmd.rootobject;
 import dmd.tokens;
+import dmd.typesem : hasPointers, parameterStorageClass;
 import dmd.visitor;
 import dmd.arraytypes;
 
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 41eeff923d8..cbf01186f98 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -189,39 +189,6 @@ extern (C++) void expandTuples(Expressions* exps, Identifiers* names = null)
     }
 }
 
-/****************************************
- * Expand alias this tuples.
- */
-TupleDeclaration isAliasThisTuple(Expression e)
-{
-    if (!e.type)
-        return null;
-
-    Type t = e.type.toBasetype();
-    while (true)
-    {
-        if (Dsymbol s = t.toDsymbol(null))
-        {
-            if (auto ad = s.isAggregateDeclaration())
-            {
-                s = ad.aliasthis ? ad.aliasthis.sym : null;
-                if (s && s.isVarDeclaration())
-                {
-                    TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
-                    if (td && td.isexp)
-                        return td;
-                }
-                if (Type att = t.aliasthisOf())
-                {
-                    t = att;
-                    continue;
-                }
-            }
-        }
-        return null;
-    }
-}
-
 /****************************************
  * If `s` is a function template, i.e. the only member of a template
  * and that member is a function, return that template.
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 9ce6f4ded9d..d4645748177 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -384,7 +384,6 @@ private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
     return Expression.combine(e0, be);
 }
 
-
 private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
 {
     auto e1 = binExp.e1;
@@ -563,6 +562,39 @@ private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
     return e0;
 }
 
+/****************************************
+ * Expand alias this tuples.
+ */
+TupleDeclaration isAliasThisTuple(Expression e)
+{
+    if (!e.type)
+        return null;
+
+    Type t = e.type.toBasetype();
+    while (true)
+    {
+        if (Dsymbol s = t.toDsymbol(null))
+        {
+            if (auto ad = s.isAggregateDeclaration())
+            {
+                s = ad.aliasthis ? ad.aliasthis.sym : null;
+                if (s && s.isVarDeclaration())
+                {
+                    TupleDeclaration td = s.isVarDeclaration().toAlias().isTupleDeclaration();
+                    if (td && td.isexp)
+                        return td;
+                }
+                if (Type att = t.aliasthisOf())
+                {
+                    t = att;
+                    continue;
+                }
+            }
+        }
+        return null;
+    }
+}
+
 /**************************************
  * Runs semantic on ae.arguments. Declares temporary variables
  * if '$' was used.
@@ -5115,7 +5147,16 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 tb = tb.isTypeDArray().next.toBasetype();
             }
 
-            if (global.params.betterC || !sc.needsCodegen())
+            if (!global.params.useGC && sc.needsCodegen())
+            {
+                version(IN_GCC)
+                    error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-fno-rtti`", exp.toChars());
+                else
+                    error(exp.loc, "expression `%s` allocates with the GC and cannot be used with switch `-betterC`", exp.toChars());
+                return setError();
+            }
+
+            if (!sc.needsCodegen())
                     goto LskipNewArrayLowering;
 
             /* Class types may inherit base classes that have errors.
@@ -6432,8 +6473,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
             }
 
-            const(char)* failMessage;
-            if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
+            void errorHelper(const(char)* failMessage) scope
             {
                 OutBuffer buf;
                 buf.writeByte('(');
@@ -6447,8 +6487,11 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     p, exp.e1.toChars(), parametersTypeToChars(tf.parameterList), buf.peekChars());
                 if (failMessage)
                     errorSupplemental(exp.loc, "%s", failMessage);
-                return setError();
             }
+
+            if (tf.callMatch(null, exp.argumentList, 0, &errorHelper, sc) == MATCH.nomatch)
+                return setError();
+
             // Purity and safety check should run after testing arguments matching
             if (exp.f)
             {
@@ -6505,8 +6548,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             {
                 exp.f = exp.f.toAliasFunc();
                 TypeFunction tf = cast(TypeFunction)exp.f.type;
-                const(char)* failMessage;
-                if (!tf.callMatch(null, exp.argumentList, 0, &failMessage, sc))
+
+                void errorHelper2(const(char)* failMessage) scope
                 {
                     OutBuffer buf;
                     buf.writeByte('(');
@@ -6527,6 +6570,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                         errorSupplemental(exp.loc, "%s", failMessage);
                     exp.f = null;
                 }
+
+                if (tf.callMatch(null, exp.argumentList, 0, &errorHelper2, sc) == MATCH.nomatch)
+                    exp.f = null;
             }
             if (!exp.f || exp.f.errors)
                 return setError();
@@ -7041,7 +7087,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             sc2.tinst = null;
             sc2.minst = null;
             sc2.flags |= SCOPE.fullinst;
-            Type t = e.targ.trySemantic(e.loc, sc2);
+            Type t = dmd.typesem.trySemantic(e.targ, e.loc, sc2);
             sc2.pop();
             if (!t) // errors, so condition is false
                 return no();
@@ -7271,7 +7317,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             Objects dedtypes = Objects(e.parameters.length);
             dedtypes.zero();
 
-            MATCH m = deduceType(e.targ, sc, e.tspec, e.parameters, &dedtypes, null, 0, e.tok == TOK.equal);
+            MATCH m = deduceType(e.targ, sc, e.tspec, *e.parameters, dedtypes, null, 0, e.tok == TOK.equal);
 
             if (m == MATCH.nomatch || (m != MATCH.exact && e.tok == TOK.equal))
             {
@@ -7292,7 +7338,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     TemplateParameter tp = (*e.parameters)[i];
                     Declaration s = null;
 
-                    m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, &dedtypes, &s);
+                    m = tp.matchArg(e.loc, sc, &tiargs, i, e.parameters, dedtypes, &s);
                     if (m == MATCH.nomatch)
                         return no();
                     s.dsymbolSemantic(sc);
@@ -7437,7 +7483,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         result = (cast(BinExp)e).reorderSettingAAElem(sc);
     }
 
-    private Expression compileIt(MixinExp exp)
+    private Expression compileIt(MixinExp exp, Scope *sc)
     {
         OutBuffer buf;
         if (expressionsToString(buf, sc, exp.exps))
@@ -7478,7 +7524,13 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             printf("MixinExp::semantic('%s')\n", exp.toChars());
         }
 
-        auto e = compileIt(exp);
+        // The expression is not treated as part of a default argument,
+        // because it is evaluated at compile time.
+        Scope* sc2 = sc.push();
+        sc2.inDefaultArg = false;
+
+        auto e = compileIt(exp, sc2);
+        sc2.pop();
         if (!e)
             return setError();
         result = e.expressionSemantic(sc);
@@ -7575,7 +7627,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         {
             auto fileName = FileName(resolvedNamez);
-            if (auto fmResult = global.fileManager.lookup(fileName))
+            if (auto fmResult = global.fileManager.getFileContents(fileName))
             {
                 se = new StringExp(e.loc, fmResult);
             }
@@ -7721,7 +7773,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             // if the assert condition is a mixin expression, try to compile it
             if (auto ce = exp.e1.isMixinExp())
             {
-                if (auto e1 = compileIt(ce))
+                if (auto e1 = compileIt(ce, sc))
                     exp.e1 = e1;
             }
 
@@ -13924,45 +13976,34 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
     {
         //printf("FileInitExp::semantic()\n");
         e.type = Type.tstring;
-        result = e;
+        result = e.resolveLoc(e.loc, sc);
     }
 
     override void visit(LineInitExp e)
     {
         e.type = Type.tint32;
-        result = e;
+        result = e.resolveLoc(e.loc, sc);
     }
 
     override void visit(ModuleInitExp e)
     {
         //printf("ModuleInitExp::semantic()\n");
         e.type = Type.tstring;
-        result = e;
+        result = e.resolveLoc(e.loc, sc);
     }
 
     override void visit(FuncInitExp e)
     {
         //printf("FuncInitExp::semantic()\n");
         e.type = Type.tstring;
-        if (sc.func)
-        {
-            result = e.resolveLoc(Loc.initial, sc);
-            return;
-        }
-        result = e;
+        result = e.resolveLoc(e.loc, sc);
     }
 
     override void visit(PrettyFuncInitExp e)
     {
         //printf("PrettyFuncInitExp::semantic()\n");
         e.type = Type.tstring;
-        if (sc.func)
-        {
-            result = e.resolveLoc(Loc.initial, sc);
-            return;
-        }
-
-        result = e;
+        result = e.resolveLoc(e.loc, sc);
     }
 }
 
@@ -15047,10 +15088,21 @@ bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
  */
 Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
 {
+    // Don't replace the special keywords, while we are inside a default
+    // argument. They are replaced later when copied to the call site.
+    if (sc.inDefaultArg)
+        return exp;
+
     exp.loc = loc;
 
     Expression visit(Expression exp)
     {
+        if (auto binExp = exp.isBinExp())
+        {
+            binExp.e1 = binExp.e1.resolveLoc(loc, sc);
+            binExp.e2 = binExp.e2.resolveLoc(loc, sc);
+            return binExp;
+        }
         if (auto unaExp = exp.isUnaExp())
         {
             unaExp.e1 = unaExp.e1.resolveLoc(loc, sc);
@@ -15059,10 +15111,121 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
         return exp;
     }
 
+    Expression visitCond(CondExp exp)
+    {
+        exp.e1 = exp.e1.resolveLoc(loc, sc);
+        exp.e2 = exp.e2.resolveLoc(loc, sc);
+        exp.econd = exp.econd.resolveLoc(loc, sc);
+        return exp;
+    }
+
     Expression visitCat(CatExp exp)
     {
         exp.e1 = exp.e1.resolveLoc(loc, sc);
         exp.e2 = exp.e2.resolveLoc(loc, sc);
+        if (exp.lowering)
+            exp.lowering = exp.lowering.resolveLoc(loc, sc);
+        return exp;
+    }
+
+    Expression visitStructLiteral(StructLiteralExp exp)
+    {
+        foreach (ref element; *exp.elements)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        return exp;
+    }
+
+    Expression visitNew(NewExp exp)
+    {
+        if (exp.thisexp)
+            exp.thisexp = exp.thisexp.resolveLoc(loc, sc);
+        if (exp.argprefix)
+            exp.argprefix = exp.argprefix.resolveLoc(loc, sc);
+        if (exp.lowering)
+            exp.lowering = exp.lowering.resolveLoc(loc, sc);
+
+        foreach (ref element; *exp.arguments)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        return exp;
+    }
+
+    Expression visitCall(CallExp exp)
+    {
+        foreach (ref element; *exp.arguments)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        return exp;
+    }
+
+    Expression visitArray(ArrayExp exp)
+    {
+        exp.e1 = exp.e1.resolveLoc(loc, sc);
+
+        foreach (ref element; *exp.arguments)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        return exp;
+    }
+
+    Expression visitSlice(SliceExp exp)
+    {
+        exp.e1 = exp.e1.resolveLoc(loc, sc);
+        exp.lwr = exp.lwr.resolveLoc(loc, sc);
+        exp.upr = exp.upr.resolveLoc(loc, sc);
+
+        return exp;
+    }
+
+    Expression visitInterval(IntervalExp exp)
+    {
+        exp.lwr = exp.lwr.resolveLoc(loc, sc);
+        exp.upr = exp.upr.resolveLoc(loc, sc);
+
+        return exp;
+    }
+
+    Expression visitArrayLiteral(ArrayLiteralExp exp)
+    {
+        if (exp.basis)
+            exp.basis = exp.basis.resolveLoc(loc, sc);
+
+        foreach (ref element; *exp.elements)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        return exp;
+    }
+
+    Expression visitAssocArrayLiteral(AssocArrayLiteralExp exp)
+    {
+        foreach (ref element; *exp.keys)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
+        foreach (ref element; *exp.values)
+        {
+            if (element)
+                element = element.resolveLoc(loc, sc);
+        }
+
         return exp;
     }
 
@@ -15079,20 +15242,20 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
         return e.expressionSemantic(sc);
     }
 
-    Expression visitLineInit(LineInitExp _)
+    Expression visitLineInit(LineInitExp exp)
     {
         Expression e = new IntegerExp(loc, loc.linnum, Type.tint32);
         return e.expressionSemantic(sc);
     }
 
-    Expression visitModuleInit(ModuleInitExp _)
+    Expression visitModuleInit(ModuleInitExp exp)
     {
         const auto s = (sc.callsc ? sc.callsc : sc)._module.toPrettyChars().toDString();
         Expression e = new StringExp(loc, s);
         return e.expressionSemantic(sc);
     }
 
-    Expression visitFuncInit(FuncInitExp _)
+    Expression visitFuncInit(FuncInitExp exp)
     {
         const(char)* s;
         if (sc.callsc && sc.callsc.func)
@@ -15105,7 +15268,7 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
         return e.expressionSemantic(sc);
     }
 
-    Expression visitPrettyFunc(PrettyFuncInitExp _)
+    Expression visitPrettyFunc(PrettyFuncInitExp exp)
     {
         FuncDeclaration fd = (sc.callsc && sc.callsc.func)
                         ? sc.callsc.func
@@ -15133,7 +15296,16 @@ Expression resolveLoc(Expression exp, const ref Loc loc, Scope* sc)
     switch(exp.op)
     {
         default:                 return visit(exp);
+        case EXP.structLiteral:  return visitStructLiteral(exp.isStructLiteralExp());
+        case EXP.new_:           return visitNew(exp.isNewExp());
         case EXP.concatenate:    return visitCat(exp.isCatExp());
+        case EXP.call:           return visitCall(exp.isCallExp());
+        case EXP.question:       return visitCond(exp.isCondExp());
+        case EXP.array:          return visitArray(exp.isArrayExp());
+        case EXP.slice:          return visitSlice(exp.isSliceExp());
+        case EXP.interval:       return visitInterval(exp.isIntervalExp());
+        case EXP.arrayLiteral:   return visitArrayLiteral(exp.isArrayLiteralExp());
+        case EXP.assocArrayLiteral: return visitAssocArrayLiteral(exp.isAssocArrayLiteralExp());
         case EXP.file:
         case EXP.fileFullPath:   return visitFileInit(exp.isFileInitExp());
         case EXP.line:           return visitLineInit(exp.isLineInitExp);
@@ -16193,7 +16365,10 @@ Expression getVarExp(EnumMember em, const ref Loc loc, Scope* sc)
     em.checkDisabled(loc, sc);
 
     if (em.depdecl && !em.depdecl._scope)
+    {
         em.depdecl._scope = sc;
+        em.depdecl._scope.setNoFree();
+    }
     em.checkDeprecated(loc, sc);
 
     if (em.errors)
diff --git a/gcc/d/dmd/file_manager.d b/gcc/d/dmd/file_manager.d
index eaef8d545e6..c696a5c240f 100644
--- a/gcc/d/dmd/file_manager.d
+++ b/gcc/d/dmd/file_manager.d
@@ -72,7 +72,7 @@ private struct PathStack
 
 final class FileManager
 {
-    private StringTable!(const(ubyte)[]) files;
+    private StringTable!(const(ubyte)[]) files;  // contents of files indexed by file name
     private StringTable!(bool) packageStatus;
 
     // check if the package path of the given path exists. The input path is
@@ -247,35 +247,37 @@ nothrow:
     }
 
     /**
-     * Looks up the given filename from the internal file buffer table.
-     * If the file does not already exist within the table, it will be read from the filesystem.
-     * If it has been read before,
-     *
-     * Returns: the loaded source file if it was found in memory,
-     *      otherwise `null`
+     * Retrieve the cached contents of the file given by `filename`.
+     * If the file has not been read before, read it and add the contents
+     * to the file cache.
+     * Params:
+     *  filename = the name of the file
+     * Returns:
+     *  the contents of the file, or `null` if it could not be read or was empty
      */
-    const(ubyte)[] lookup(FileName filename)
+    const(ubyte)[] getFileContents(FileName filename)
     {
         const name = filename.toString;
-        if (auto val = files.lookup(name))
-            return val.value;
+        if (auto val = files.lookup(name))      // if `name` is cached
+            return val.value;                   // return its contents
 
-        if (name == "__stdin.d")
+        if (name == "__stdin.d")                // special name for reading from stdin
         {
-            auto buffer = readFromStdin().extractSlice();
+            const ubyte[] buffer = readFromStdin().extractSlice();
             if (this.files.insert(name, buffer) is null)
+                // this.files already contains the name
                 assert(0, "stdin: Insert after lookup failure should never return `null`");
             return buffer;
         }
 
-        if (FileName.exists(name) != 1)
+        if (FileName.exists(name) != 1) // if not an ordinary file
             return null;
 
         auto readResult = File.read(name);
         if (!readResult.success)
             return null;
 
-        auto fb = readResult.extractSlice();
+        const ubyte[] fb = readResult.extractSlice();
         if (files.insert(name, fb) is null)
             assert(0, "Insert after lookup failure should never return `null`");
 
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 242b4dc99f9..370da6f0ee6 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -1195,7 +1195,7 @@ extern (C++) class FuncDeclaration : Declaration
      *
      * Returns: the `LabelDsymbol` for `ident`
      */
-    final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc = Loc.initial)
+    final LabelDsymbol searchLabel(Identifier ident, const ref Loc loc)
     {
         Dsymbol s;
         if (!labtab)
@@ -1471,6 +1471,9 @@ extern (C++) class FuncDeclaration : Declaration
     final PURE isPure()
     {
         //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+
+        import dmd.typesem : purityLevel;
+
         TypeFunction tf = type.toTypeFunction();
         if (purityInprocess)
             setImpure();
@@ -1782,6 +1785,7 @@ extern (C++) class FuncDeclaration : Declaration
             case Tstruct:
                 /* Drill down and check the struct's fields
                  */
+                import dmd.typesem : toDsymbol;
                 auto sym = t.toDsymbol(null).isStructDeclaration();
                 const tName = t.toChars.toDString;
                 const entry = parentTypes.insert(tName, t);
@@ -1863,6 +1867,7 @@ extern (C++) class FuncDeclaration : Declaration
                     case Tstruct:
                         /* Drill down and check the struct's fields
                          */
+                        import dmd.typesem : toDsymbol;
                         auto sym = tp.toDsymbol(null).isStructDeclaration();
                         foreach (v; sym.fields)
                         {
@@ -2727,6 +2732,7 @@ extern (C++) class FuncDeclaration : Declaration
                 {
                     Type t1 = fdv.type.nextOf().toBasetype();
                     Type t2 = this.type.nextOf().toBasetype();
+                    import dmd.typesem : isBaseOf;
                     if (t1.isBaseOf(t2, null))
                     {
                         /* Making temporary reference variable is necessary
@@ -3294,7 +3300,7 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
         printf("\tfnames: %s\n", fnames ? fnames.toChars() : "null");
     }
 
-    if (tiargs && arrayObjectIsError(tiargs))
+    if (tiargs && arrayObjectIsError(*tiargs))
         return null;
     if (fargs !is null)
         foreach (arg; *fargs)
@@ -3441,17 +3447,20 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
             return null;
         }
 
-        const(char)* failMessage;
-        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
-        if (failMessage)
+        bool calledHelper;
+        void errorHelper(const(char)* failMessage) scope
         {
             .error(loc, "%s `%s%s%s` is not callable using argument types `%s`",
                    fd.kind(), fd.toPrettyChars(), parametersTypeToChars(tf.parameterList),
                    tf.modToChars(), fargsBuf.peekChars());
             errorSupplemental(loc, failMessage);
-            return null;
+            calledHelper = true;
         }
 
+        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper);
+        if (calledHelper)
+            return null;
+
         if (fd.isCtorDeclaration())
             .error(loc, "%s%s `%s` cannot construct a %sobject",
                    funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
@@ -3505,10 +3514,13 @@ FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
                 }
             }
         }
-        const(char)* failMessage;
-        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &failMessage);
-        if (failMessage)
+
+        void errorHelper2(const(char)* failMessage) scope
+        {
             errorSupplemental(loc, failMessage);
+        }
+
+        functionResolve(m, orig_s, loc, sc, tiargs, tthis, argumentList, &errorHelper2);
     }
     return null;
 }
@@ -3624,6 +3636,7 @@ if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
  */
 Type getIndirection(Type t)
 {
+    import dmd.typesem : hasPointers;
     t = t.baseElemOf();
     if (t.ty == Tarray || t.ty == Tpointer)
         return t.nextOf().toBasetype();
@@ -3670,6 +3683,7 @@ private bool traverseIndirections(Type ta, Type tb)
 
     static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
     {
+        import dmd.typesem : hasPointers;
         //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
         ta = ta.baseElemOf();
         tb = tb.baseElemOf();
@@ -3706,6 +3720,7 @@ private bool traverseIndirections(Type ta, Type tb)
             else
                 *found = true;
 
+            import dmd.typesem : toDsymbol;
             AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
             foreach (v; sym.fields)
             {
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index b60a3f8cad1..e9e73e8af66 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -15,7 +15,9 @@ import core.stdc.stdio;
 import core.stdc.stdint;
 import core.stdc.string;
 
+import dmd.astenums;
 import dmd.root.array;
+import dmd.root.file;
 import dmd.root.filename;
 import dmd.common.outbuffer;
 import dmd.errorsink;
@@ -308,7 +310,7 @@ extern (C++) struct Global
     ErrorSink errorSink;       /// where the error messages go
     ErrorSink errorSinkNull;   /// where the error messages are ignored
 
-    extern (C++) FileName function(FileName, ref const Loc, out bool, OutBuffer*) preprocess;
+    extern (C++) DArray!ubyte function(FileName, ref const Loc, ref OutBuffer) preprocess;
 
   nothrow:
 
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index c71d2f0499d..93e7c643d4c 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -307,7 +307,7 @@ struct Global
     ErrorSink* errorSink;       // where the error messages go
     ErrorSink* errorSinkNull;   // where the error messages disappear
 
-    FileName (*preprocess)(FileName, const Loc&, bool&, OutBuffer&);
+    DArray<unsigned char> (*preprocess)(FileName, const Loc&, OutBuffer&);
 
     /* Start gagging. Return the current number of gagged errors
      */
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 4c741cdd5cc..3d88a1dfad3 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -21,16 +21,11 @@ import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
-import dmd.gluelayer;
 import dmd.dclass;
-import dmd.dcast;
 import dmd.declaration;
 import dmd.denum;
-import dmd.dmangle;
-import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
@@ -39,9 +34,7 @@ import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
-import dmd.init;
 import dmd.location;
-import dmd.opover;
 import dmd.root.ctfloat;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
@@ -256,57 +249,6 @@ bool isSomeChar(TY ty) pure nothrow @nogc @safe
     return ty == Tchar || ty == Twchar || ty == Tdchar;
 }
 
-/************************************
- * Determine mutability of indirections in (ref) t.
- *
- * Returns: When the type has any mutable indirections, returns 0.
- * When all indirections are immutable, returns 2.
- * Otherwise, when the type has const/inout indirections, returns 1.
- *
- * Params:
- *      isref = if true, check `ref t`; otherwise, check just `t`
- *      t = the type that is being checked
- */
-int mutabilityOfType(bool isref, Type t)
-{
-    if (isref)
-    {
-        if (t.mod & MODFlags.immutable_)
-            return 2;
-        if (t.mod & (MODFlags.const_ | MODFlags.wild))
-            return 1;
-        return 0;
-    }
-
-    t = t.baseElemOf();
-
-    if (!t.hasPointers() || t.mod & MODFlags.immutable_)
-        return 2;
-
-    /* Accept immutable(T)[] and immutable(T)* as being strongly pure
-     */
-    if (t.ty == Tarray || t.ty == Tpointer)
-    {
-        Type tn = t.nextOf().toBasetype();
-        if (tn.mod & MODFlags.immutable_)
-            return 2;
-        if (tn.mod & (MODFlags.const_ | MODFlags.wild))
-            return 1;
-    }
-
-    /* The rest of this is too strict; fix later.
-     * For example, the only pointer members of a struct may be immutable,
-     * which would maintain strong purity.
-     * (Just like for dynamic arrays and pointers above.)
-     */
-    if (t.mod & (MODFlags.const_ | MODFlags.wild))
-        return 1;
-
-    /* Should catch delegates and function pointers, and fold in their purity
-     */
-    return 0;
-}
-
 /****************
  * dotExp() bit flags
  */
@@ -363,7 +305,7 @@ extern (C++) abstract class Type : ASTNode
 
     TypeInfoDeclaration vtinfo;     // TypeInfo object for this Type
 
-    type* ctype;                    // for back end
+    void* ctype;                    // for back end
 
     extern (C++) __gshared Type tvoid;
     extern (C++) __gshared Type tint8;
@@ -659,31 +601,6 @@ extern (C++) abstract class Type : ASTNode
         return cast(uint)size(Loc.initial);
     }
 
-    final Type trySemantic(const ref Loc loc, Scope* sc)
-    {
-        //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
-
-        // Needed to display any deprecations that were gagged
-        auto tcopy = this.syntaxCopy();
-
-        const errors = global.startGagging();
-        Type t = typeSemantic(this, loc, sc);
-        if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
-        {
-            t = null;
-        }
-        else
-        {
-            // If `typeSemantic` succeeded, there may have been deprecations that
-            // were gagged due the `startGagging` above.  Run again to display
-            // those deprecations.  https://issues.dlang.org/show_bug.cgi?id=19107
-            if (global.gaggedWarnings > 0)
-                typeSemantic(tcopy, loc, sc);
-        }
-        //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
-        return t;
-    }
-
     /*************************************
      * This version does a merge even if the deco is already computed.
      * Necessary for types that have a deco, but are not merged.
@@ -1907,11 +1824,6 @@ extern (C++) abstract class Type : ASTNode
         return t;
     }
 
-    Dsymbol toDsymbol(Scope* sc)
-    {
-        return null;
-    }
-
     /*******************************
      * If this is a shell around another type,
      * get that other type.
@@ -1925,11 +1837,6 @@ extern (C++) abstract class Type : ASTNode
         return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
     }
 
-    bool isBaseOf(Type t, int* poffset)
-    {
-        return 0; // assume not
-    }
-
     /********************************
      * Determine if 'this' can be implicitly converted
      * to type 'to'.
@@ -2155,32 +2062,6 @@ extern (C++) abstract class Type : ASTNode
         return false; // assume not
     }
 
-    final Identifier getTypeInfoIdent()
-    {
-        // _init_10TypeInfo_%s
-        OutBuffer buf;
-        buf.reserve(32);
-        mangleToBuffer(this, buf);
-
-        const slice = buf[];
-
-        // Allocate buffer on stack, fail over to using malloc()
-        char[128] namebuf;
-        const namelen = 19 + size_t.sizeof * 3 + slice.length + 1;
-        auto name = namelen <= namebuf.length ? namebuf.ptr : cast(char*)Mem.check(malloc(namelen));
-
-        const length = snprintf(name, namelen, "_D%lluTypeInfo_%.*s6__initZ",
-                cast(ulong)(9 + slice.length), cast(int)slice.length, slice.ptr);
-        //printf("%p %s, deco = %s, name = %s\n", this, toChars(), deco, name);
-        assert(0 < length && length < namelen); // don't overflow the buffer
-
-        auto id = Identifier.idPool(name[0 .. length]);
-
-        if (name != namebuf.ptr)
-            free(name);
-        return id;
-    }
-
     /***************************************
      * Return !=0 if the type or any of its subtypes is wild.
      */
@@ -2189,16 +2070,6 @@ extern (C++) abstract class Type : ASTNode
         return mod & MODFlags.wild;
     }
 
-    /***************************************
-     * Return !=0 if type has pointers that need to
-     * be scanned by the GC during a collection cycle.
-     */
-    bool hasPointers()
-    {
-        //printf("Type::hasPointers() %s, %d\n", toChars(), ty);
-        return false;
-    }
-
     /*************************************
      * Detect if type has pointer fields that are initialized to void.
      * Local stack variables with such void fields can remain uninitialized,
@@ -2340,76 +2211,6 @@ extern (C++) abstract class Type : ASTNode
         return false;
     }
 
-    /*************************************
-     * https://issues.dlang.org/show_bug.cgi?id=14488
-     * Check if the inner most base type is complex or imaginary.
-     * Should only give alerts when set to emit transitional messages.
-     * Params:
-     *  loc = The source location.
-     *  sc = scope of the type
-     */
-    extern (D) final bool checkComplexTransition(const ref Loc loc, Scope* sc)
-    {
-        if (sc.isDeprecated())
-            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)
-            return false;
-
-        Type t = baseElemOf();
-        while (t.ty == Tpointer || t.ty == Tarray)
-            t = t.nextOf().baseElemOf();
-
-        // Basetype is an opaque enum, nothing to check.
-        if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
-            return false;
-
-        if (t.isimaginary() || t.iscomplex())
-        {
-            if (sc.flags & SCOPE.Cfile)
-                return true;            // complex/imaginary not deprecated in C code
-            Type rt;
-            switch (t.ty)
-            {
-            case Tcomplex32:
-            case Timaginary32:
-                rt = Type.tfloat32;
-                break;
-
-            case Tcomplex64:
-            case Timaginary64:
-                rt = Type.tfloat64;
-                break;
-
-            case Tcomplex80:
-            case Timaginary80:
-                rt = Type.tfloat80;
-                break;
-
-            default:
-                assert(0);
-            }
-            // @@@DEPRECATED_2.117@@@
-            // Deprecated in 2.097 - Can be made an error from 2.117.
-            // The deprecation period is longer than usual as `cfloat`,
-            // `cdouble`, and `creal` were quite widely used.
-            if (t.iscomplex())
-            {
-                deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
-                    toChars(), rt.toChars());
-                return true;
-            }
-            else
-            {
-                deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
-                    toChars(), rt.toChars());
-                return true;
-            }
-        }
-        return false;
-    }
-
     // For eliminating dynamic_cast
     TypeBasic isTypeBasic()
     {
@@ -3531,24 +3332,6 @@ extern (C++) final class TypeSArray : TypeArray
         return ae;
     }
 
-    override bool hasPointers()
-    {
-        /* Don't want to do this, because:
-         *    struct S { T* array[0]; }
-         * may be a variable length struct.
-         */
-        //if (dim.toInteger() == 0)
-        //    return false;
-
-        if (next.ty == Tvoid)
-        {
-            // Arrays of void contain arbitrary data, which may include pointers
-            return true;
-        }
-        else
-            return next.hasPointers();
-    }
-
     override bool hasSystemFields()
     {
         return next.hasSystemFields();
@@ -3673,11 +3456,6 @@ extern (C++) final class TypeDArray : TypeArray
         return Type.implicitConvTo(to);
     }
 
-    override bool hasPointers()
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3734,11 +3512,6 @@ extern (C++) final class TypeAArray : TypeArray
         return true;
     }
 
-    override bool hasPointers()
-    {
-        return true;
-    }
-
     override MATCH implicitConvTo(Type to)
     {
         //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
@@ -3877,11 +3650,6 @@ extern (C++) final class TypePointer : TypeNext
         return true;
     }
 
-    override bool hasPointers()
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4058,39 +3826,6 @@ extern (C++) final class TypeFunction : TypeNext
         return t;
     }
 
-    /********************************************
-     * Set 'purity' field of 'this'.
-     * Do this lazily, as the parameter types might be forward referenced.
-     */
-    void purityLevel()
-    {
-        TypeFunction tf = this;
-        if (tf.purity != PURE.fwdref)
-            return;
-
-        purity = PURE.const_; // assume strong until something weakens it
-
-        /* Evaluate what kind of purity based on the modifiers for the parameters
-         */
-        foreach (i, fparam; tf.parameterList)
-        {
-            Type t = fparam.type;
-            if (!t)
-                continue;
-
-            if (fparam.storageClass & (STC.lazy_ | STC.out_))
-            {
-                purity = PURE.weak;
-                break;
-            }
-            const pref = (fparam.storageClass & STC.ref_) != 0;
-            if (mutabilityOfType(pref, t) == 0)
-                purity = PURE.weak;
-        }
-
-        tf.purity = purity;
-    }
-
     /********************************************
      * Return true if there are lazy parameters.
      */
@@ -4115,122 +3850,6 @@ extern (C++) final class TypeFunction : TypeNext
         return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
     }
 
-    /************************************
-     * Take the specified storage class for p,
-     * and use the function signature to infer whether
-     * STC.scope_ and STC.return_ should be OR'd in.
-     * (This will not affect the name mangling.)
-     * Params:
-     *  tthis = type of `this` parameter, null if none
-     *  p = parameter to this function
-     *  outerVars = context variables p could escape into, if any
-     *  indirect = is this for an indirect or virtual function call?
-     * Returns:
-     *  storage class with STC.scope_ or STC.return_ OR'd in
-     */
-    StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null,
-        bool indirect = false)
-    {
-        //printf("parameterStorageClass(p: %s)\n", p.toChars());
-        auto stc = p.storageClass;
-
-        // When the preview switch is enable, `in` parameters are `scope`
-        if (stc & STC.constscoperef)
-            return stc | STC.scope_;
-
-        if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || purity == PURE.impure)
-            return stc;
-
-        /* If haven't inferred the return type yet, can't infer storage classes
-         */
-        if (!nextOf() || !isnothrow())
-            return stc;
-
-        purityLevel();
-
-        static bool mayHavePointers(Type t)
-        {
-            if (auto ts = t.isTypeStruct())
-            {
-                auto sym = ts.sym;
-                if (sym.members && !sym.determineFields() && sym.type != Type.terror)
-                    // struct is forward referenced, so "may have" pointers
-                    return true;
-            }
-            return t.hasPointers();
-        }
-
-        // See if p can escape via any of the other parameters
-        if (purity == PURE.weak)
-        {
-            /*
-             * Indirect calls may escape p through a nested context
-             * See:
-             *   https://issues.dlang.org/show_bug.cgi?id=24212
-             *   https://issues.dlang.org/show_bug.cgi?id=24213
-             */
-            if (indirect)
-                return stc;
-
-            // Check escaping through parameters
-            foreach (i, fparam; parameterList)
-            {
-                Type t = fparam.type;
-                if (!t)
-                    continue;
-                t = t.baseElemOf();     // punch thru static arrays
-                if (t.isMutable() && t.hasPointers())
-                {
-                    if (fparam.isReference() && fparam != p)
-                        return stc;
-
-                    if (t.ty == Tdelegate)
-                        return stc;     // could escape thru delegate
-
-                    if (t.ty == Tclass)
-                        return stc;
-
-                    /* if t is a pointer to mutable pointer
-                     */
-                    if (auto tn = t.nextOf())
-                    {
-                        if (tn.isMutable() && mayHavePointers(tn))
-                            return stc;   // escape through pointers
-                    }
-                }
-            }
-
-            // Check escaping through `this`
-            if (tthis && tthis.isMutable())
-            {
-                foreach (VarDeclaration v; isAggregate(tthis).fields)
-                {
-                    if (v.hasPointers())
-                        return stc;
-                }
-            }
-
-            // Check escaping through nested context
-            if (outerVars && this.isMutable())
-            {
-                foreach (VarDeclaration v; *outerVars)
-                {
-                    if (v.hasPointers())
-                        return stc;
-                }
-            }
-        }
-
-        // Check escaping through return value
-        Type tret = nextOf().toBasetype();
-        if (isref || tret.hasPointers())
-        {
-            return stc | STC.scope_ | STC.return_ | STC.returnScope;
-        }
-        else
-            return stc | STC.scope_;
-    }
-
     override Type addStorageClass(StorageClass stc)
     {
         //printf("addStorageClass(%llx) %d\n", stc, (stc & STC.scope_) != 0);
@@ -4631,11 +4250,6 @@ extern (C++) final class TypeDelegate : TypeNext
         return true;
     }
 
-    override bool hasPointers()
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4676,20 +4290,6 @@ extern (C++) final class TypeTraits : Type
         return tt;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        Type t;
-        Expression e;
-        Dsymbol s;
-        resolve(this, loc, sc, e, t, s);
-        if (t && t.ty != Terror)
-            s = t.toDsymbol(sc);
-        else if (e)
-            s = getDsymbol(e);
-
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4729,20 +4329,6 @@ extern (C++) final class TypeMixin : Type
         return new TypeMixin(loc, Expression.arraySyntaxCopy(exps));
     }
 
-   override Dsymbol toDsymbol(Scope* sc)
-    {
-        Type t;
-        Expression e;
-        Dsymbol s;
-        resolve(this, loc, sc, e, t, s);
-        if (t)
-            s = t.toDsymbol(sc);
-        else if (e)
-            s = getDsymbol(e);
-
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4867,28 +4453,6 @@ extern (C++) final class TypeIdentifier : TypeQualified
         return t;
     }
 
-    /*****************************************
-     * See if type resolves to a symbol, if so,
-     * return that symbol.
-     */
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
-        if (!sc)
-            return null;
-
-        Type t;
-        Expression e;
-        Dsymbol s;
-        resolve(this, loc, sc, e, t, s);
-        if (t && t.ty != Tident)
-            s = t.toDsymbol(sc);
-        if (e)
-            s = getDsymbol(e);
-
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4922,18 +4486,6 @@ extern (C++) final class TypeInstance : TypeQualified
         return t;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        Type t;
-        Expression e;
-        Dsymbol s;
-        //printf("TypeInstance::semantic(%s)\n", toChars());
-        resolve(this, loc, sc, e, t, s);
-        if (t && t.ty != Tinstance)
-            s = t.toDsymbol(sc);
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4967,16 +4519,6 @@ extern (C++) final class TypeTypeof : TypeQualified
         return t;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
-        Expression e;
-        Type t;
-        Dsymbol s;
-        resolve(this, loc, sc, e, t, s);
-        return s;
-    }
-
     override uinteger_t size(const ref Loc loc)
     {
         if (exp.type)
@@ -5013,15 +4555,6 @@ extern (C++) final class TypeReturn : TypeQualified
         return t;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        Expression e;
-        Type t;
-        Dsymbol s;
-        resolve(this, loc, sc, e, t, s);
-        return s;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -5068,11 +4601,6 @@ extern (C++) final class TypeStruct : Type
         return this;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        return sym;
-    }
-
     override structalign_t alignment()
     {
         if (sym.alignment.isUnknown())
@@ -5214,15 +4742,6 @@ extern (C++) final class TypeStruct : Type
         return false;
     }
 
-    override bool hasPointers()
-    {
-        if (sym.members && !sym.determineFields() && sym.type != Type.terror)
-            error(sym.loc, "no size because of forward references");
-
-        sym.determineTypeProperties();
-        return sym.hasPointerField;
-    }
-
     override bool hasVoidInitPointers()
     {
         sym.size(Loc.initial); // give error for forward references
@@ -5393,9 +4912,9 @@ extern (C++) final class TypeEnum : Type
         return sym.getMemtype(loc).size(loc);
     }
 
-    Type memType(const ref Loc loc = Loc.initial)
+    Type memType()
     {
-        return sym.getMemtype(loc);
+        return sym.getMemtype(Loc.initial);
     }
 
     override uint alignsize()
@@ -5406,11 +4925,6 @@ extern (C++) final class TypeEnum : Type
         return t.alignsize();
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        return sym;
-    }
-
     override bool isintegral()
     {
         return memType().isintegral();
@@ -5511,11 +5025,6 @@ extern (C++) final class TypeEnum : Type
         return sym.getDefaultValue(loc).toBool().hasValue(false);
     }
 
-    override bool hasPointers()
-    {
-        return memType().hasPointers();
-    }
-
     override bool hasVoidInitPointers()
     {
         return memType().hasVoidInitPointers();
@@ -5571,44 +5080,14 @@ extern (C++) final class TypeClass : Type
         return this;
     }
 
-    override Dsymbol toDsymbol(Scope* sc)
-    {
-        return sym;
-    }
-
     override inout(ClassDeclaration) isClassHandle() inout
     {
         return sym;
     }
 
-    override bool isBaseOf(Type t, int* poffset)
-    {
-        if (t && t.ty == Tclass)
-        {
-            ClassDeclaration cd = (cast(TypeClass)t).sym;
-            if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
-                cd.dsymbolSemantic(null);
-            if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
-                sym.dsymbolSemantic(null);
-
-            if (sym.isBaseOf(cd, poffset))
-                return true;
-        }
-        return false;
-    }
-
     extern (D) MATCH implicitConvToWithoutAliasThis(Type to)
     {
-        // Run semantic before checking whether class is convertible
         ClassDeclaration cdto = to.isClassHandle();
-        if (cdto)
-        {
-            //printf("TypeClass::implicitConvTo(to = '%s') %s, isbase = %d %d\n", to.toChars(), toChars(), cdto.isBaseInfoComplete(), sym.isBaseInfoComplete());
-            if (cdto.semanticRun < PASS.semanticdone && !cdto.isBaseInfoComplete())
-                cdto.dsymbolSemantic(null);
-            if (sym.semanticRun < PASS.semanticdone && !sym.isBaseInfoComplete())
-                sym.dsymbolSemantic(null);
-        }
         MATCH m = constConv(to);
         if (m > MATCH.nomatch)
             return m;
@@ -5706,11 +5185,6 @@ extern (C++) final class TypeClass : Type
         return true;
     }
 
-    override bool hasPointers()
-    {
-        return true;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -5952,14 +5426,6 @@ extern (C++) final class TypeNull : Type
         return MATCH.nomatch;
     }
 
-    override bool hasPointers()
-    {
-        /* Although null isn't dereferencable, treat it as a pointer type for
-         * attribute inference, generic code, etc.
-         */
-        return true;
-    }
-
     override bool isBoolean()
     {
         return true;
@@ -6633,39 +6099,6 @@ bool isIndexableNonAggregate(Type t)
             t.ty == Ttuple || t.ty == Tvector);
 }
 
-/***************************************************
- * Determine if type t is copyable.
- * Params:
- *      t = type to check
- * Returns:
- *      true if we can copy it
- */
-bool isCopyable(Type t)
-{
-    //printf("isCopyable() %s\n", t.toChars());
-    if (auto ts = t.isTypeStruct())
-    {
-        if (ts.sym.postblit &&
-            ts.sym.postblit.storage_class & STC.disable)
-            return false;
-        if (ts.sym.hasCopyCtor)
-        {
-            // check if there is a matching overload of the copy constructor and whether it is disabled or not
-            // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
-            Dsymbol ctor = search_function(ts.sym, Id.ctor);
-            assert(ctor);
-            scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
-            el.type = cast() ts;
-            Expressions* args = new Expressions();
-            args.push(el);
-            FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
-            if (!f || f.storage_class & STC.disable)
-                return false;
-        }
-    }
-    return true;
-}
-
 /***************************************
  * Computes how a parameter may be returned.
  * Shrinking the representation is necessary because StorageClass is so wide
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 97a7ae3c5af..c777f359da4 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -233,7 +233,6 @@ public:
     uinteger_t size();
     virtual uinteger_t size(const Loc &loc);
     virtual unsigned alignsize();
-    Type *trySemantic(const Loc &loc, Scope *sc);
     Type *merge2();
     void modToBuffer(OutBuffer& buf) const;
     char *modToChars() const;
@@ -287,9 +286,7 @@ public:
     virtual Type *makeSharedWild();
     virtual Type *makeSharedWildConst();
     virtual Type *makeMutable();
-    virtual Dsymbol *toDsymbol(Scope *sc);
     Type *toBasetype();
-    virtual bool isBaseOf(Type *t, int *poffset);
     virtual MATCH implicitConvTo(Type *to);
     virtual MATCH constConv(Type *to);
     virtual unsigned char deduceWild(Type *t, bool isRef);
@@ -302,9 +299,7 @@ public:
     virtual structalign_t alignment();
     virtual Expression *defaultInitLiteral(const Loc &loc);
     virtual bool isZeroInit(const Loc &loc = Loc()); // if initializer is 0
-    Identifier *getTypeInfoIdent();
     virtual int hasWild() const;
-    virtual bool hasPointers();
     virtual bool hasVoidInitPointers();
     virtual bool hasSystemFields();
     virtual bool hasInvariant();
@@ -451,7 +446,6 @@ public:
     MATCH constConv(Type *to) override;
     MATCH implicitConvTo(Type *to) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
-    bool hasPointers() override;
     bool hasSystemFields() override;
     bool hasVoidInitPointers() override;
     bool hasInvariant() override;
@@ -474,7 +468,6 @@ public:
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
     MATCH implicitConvTo(Type *to) override;
-    bool hasPointers() override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -491,7 +484,6 @@ public:
     uinteger_t size(const Loc &loc) override;
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
-    bool hasPointers() override;
     MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
 
@@ -509,7 +501,6 @@ public:
     MATCH constConv(Type *to) override;
     bool isscalar() override;
     bool isZeroInit(const Loc &loc) override;
-    bool hasPointers() override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -605,10 +596,8 @@ public:
     static TypeFunction *create(Parameters *parameters, Type *treturn, VarArg varargs, LINK linkage, StorageClass stc = 0);
     const char *kind() override;
     TypeFunction *syntaxCopy() override;
-    void purityLevel();
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
-    StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false);
     Type *addStorageClass(StorageClass stc) override;
 
     Type *substWildTo(unsigned mod) override;
@@ -659,7 +648,6 @@ public:
     MATCH implicitConvTo(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
-    bool hasPointers() override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -675,7 +663,6 @@ class TypeTraits final : public Type
     const char *kind() override;
     TypeTraits *syntaxCopy() override;
     uinteger_t size(const Loc &loc) override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -687,7 +674,6 @@ class TypeMixin final : public Type
 
     const char *kind() override;
     TypeMixin *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -713,7 +699,6 @@ public:
     static TypeIdentifier *create(const Loc &loc, Identifier *ident);
     const char *kind() override;
     TypeIdentifier *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -726,7 +711,6 @@ public:
 
     const char *kind() override;
     TypeInstance *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -738,7 +722,6 @@ public:
 
     const char *kind() override;
     TypeTypeof *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     uinteger_t size(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -748,7 +731,6 @@ class TypeReturn final : public TypeQualified
 public:
     const char *kind() override;
     TypeReturn *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -776,7 +758,6 @@ public:
     uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     TypeStruct *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     structalign_t alignment() override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     bool isZeroInit(const Loc &loc) override;
@@ -785,7 +766,6 @@ public:
     bool needsDestruction() override;
     bool needsCopyOrPostblit() override;
     bool needsNested() override;
-    bool hasPointers() override;
     bool hasVoidInitPointers() override;
     bool hasSystemFields() override;
     bool hasInvariant() override;
@@ -806,8 +786,7 @@ public:
     TypeEnum *syntaxCopy() override;
     uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
-    Type *memType(const Loc &loc = Loc());
-    Dsymbol *toDsymbol(Scope *sc) override;
+    Type *memType(const Loc &loc);
     bool isintegral() override;
     bool isfloating() override;
     bool isreal() override;
@@ -824,7 +803,6 @@ public:
     MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
-    bool hasPointers() override;
     bool hasVoidInitPointers() override;
     bool hasSystemFields() override;
     bool hasInvariant() override;
@@ -843,9 +821,7 @@ public:
     const char *kind() override;
     uinteger_t size(const Loc &loc) override;
     TypeClass *syntaxCopy() override;
-    Dsymbol *toDsymbol(Scope *sc) override;
     ClassDeclaration *isClassHandle() override;
-    bool isBaseOf(Type *t, int *poffset) override;
     MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override;
@@ -853,7 +829,6 @@ public:
     bool isZeroInit(const Loc &loc) override;
     bool isscope() override;
     bool isBoolean() override;
-    bool hasPointers() override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -894,7 +869,6 @@ public:
 
     TypeNull *syntaxCopy() override;
     MATCH implicitConvTo(Type *to) override;
-    bool hasPointers() override;
     bool isBoolean() override;
 
     uinteger_t size(const Loc &loc) override;
@@ -925,6 +899,13 @@ public:
 
 /**************************************************************/
 
+
 // If the type is a class or struct, returns the symbol for it, else null.
 AggregateDeclaration *isAggregate(Type *t);
+bool hasPointers(Type *t);
+// return the symbol to which type t resolves
+Dsymbol *toDsymbol(Type *t, Scope *sc);
 Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
+bool isBaseOf(Type *tthis, Type *t, int *poffset);
+Type *trySemantic(Type *type, const Loc &loc, Scope *sc);
+void purityLevel(TypeFunction *type);
diff --git a/gcc/d/dmd/mustuse.d b/gcc/d/dmd/mustuse.d
index b5601a214dc..c2fa5fbd023 100644
--- a/gcc/d/dmd/mustuse.d
+++ b/gcc/d/dmd/mustuse.d
@@ -31,6 +31,7 @@ import dmd.location;
 bool checkMustUse(Expression e, Scope* sc)
 {
     import dmd.id : Id;
+    import dmd.typesem : toDsymbol;
 
     assert(e.type);
     if (auto sym = e.type.toDsymbol(sc))
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 785912e1968..0a5981589c6 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -2566,6 +2566,7 @@ void checkObErrors(ref ObState obstate)
                 //printf("%s: ", obstate.vars[i].toChars()); pvs.print(obstate.vars[]);
                 if (pvs.state == PtrState.Owner)
                 {
+                    import dmd.typesem : hasPointers;
                     auto v = obstate.vars[i];
                     if (v.type.hasPointers())
                         .error(v.loc, "%s `%s` is not disposed of before return", v.kind, v.toPrettyChars);
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index a012e0c7c5b..268622a82fc 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1675,7 +1675,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                     if (token.value == TOK.assign) // = CondExpression
                     {
                         nextToken();
-                        tp_defaultvalue = parseDefaultInitExp();
+                        tp_defaultvalue = parseAssignExp();
                     }
                     tp = new AST.TemplateValueParameter(loc, tp_ident, tp_valtype, tp_specvalue, tp_defaultvalue);
                 }
@@ -2969,7 +2969,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                         if (token.value == TOK.assign) // = defaultArg
                         {
                             nextToken();
-                            ae = parseDefaultInitExp();
+                            ae = parseAssignExp();
                         }
                         auto param = new AST.Parameter(loc, storageClass | STC.parameter, at, ai, ae, null);
                         if (udas)
@@ -6949,33 +6949,6 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         }
     }
 
-    /*****************************************
-     * Parses default argument initializer expression that is an assign expression,
-     * with special handling for __FILE__, __FILE_DIR__, __LINE__, __MODULE__, __FUNCTION__, and __PRETTY_FUNCTION__.
-     */
-    private AST.Expression parseDefaultInitExp()
-    {
-        AST.Expression e = null;
-        const tv = peekNext();
-        if (tv == TOK.comma || tv == TOK.rightParenthesis)
-        {
-            switch (token.value)
-            {
-            case TOK.file:           e = new AST.FileInitExp(token.loc, EXP.file); break;
-            case TOK.fileFullPath:   e = new AST.FileInitExp(token.loc, EXP.fileFullPath); break;
-            case TOK.line:           e = new AST.LineInitExp(token.loc); break;
-            case TOK.moduleString:   e = new AST.ModuleInitExp(token.loc); break;
-            case TOK.functionString: e = new AST.FuncInitExp(token.loc); break;
-            case TOK.prettyFunction: e = new AST.PrettyFuncInitExp(token.loc); break;
-            default: goto LExp;
-            }
-            nextToken();
-            return e;
-        }
-        LExp:
-        return parseAssignExp();
-    }
-
     /********************
      * Parse inline assembler block.
      * Enters with token on the `asm`.
@@ -8152,33 +8125,23 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
             break;
 
         case TOK.file:
-            {
-                const(char)* s = loc.filename ? loc.filename : mod.ident.toChars();
-                e = new AST.StringExp(loc, s.toDString());
-                nextToken();
-                break;
-            }
+            e = new AST.FileInitExp(loc, EXP.file);
+            nextToken();
+            break;
         case TOK.fileFullPath:
-            {
-                assert(loc.isValid(), "__FILE_FULL_PATH__ does not work with an invalid location");
-                const s = FileName.toAbsolute(loc.filename);
-                e = new AST.StringExp(loc, s.toDString());
-                nextToken();
-                break;
-            }
+            e = new AST.FileInitExp(loc, EXP.fileFullPath);
+            nextToken();
+            break;
 
         case TOK.line:
-            e = new AST.IntegerExp(loc, loc.linnum, AST.Type.tint32);
+            e = new AST.LineInitExp(loc);
             nextToken();
             break;
 
         case TOK.moduleString:
-            {
-                const(char)* s = md ? md.toChars() : mod.toChars();
-                e = new AST.StringExp(loc, s.toDString());
-                nextToken();
-                break;
-            }
+            e = new AST.ModuleInitExp(loc);
+            nextToken();
+            break;
         case TOK.functionString:
             e = new AST.FuncInitExp(loc);
             nextToken();
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index af81bff0dd1..8b57f7fe249 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -26,6 +26,7 @@ import dmd.identifier;
 import dmd.mtype;
 import dmd.target;
 import dmd.tokens;
+import dmd.typesem : hasPointers;
 import dmd.func : setUnsafe, setUnsafePreview;
 
 /*************************************************************
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index 1535fd07755..4b157cc9ee7 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -87,6 +87,7 @@ struct Scope
     Dsymbol *inunion;           // !=null if processing members of a union
     d_bool nofree;                // true if shouldn't free it
     d_bool inLoop;                // true if inside a loop (where constructor calls aren't allowed)
+    d_bool inDefaultArg;          // true if inside a default argument (where __FILE__, etc are evaluated at the call site)
     int intypeof;               // in typeof(exp)
     VarDeclaration *lastVar;    // Previous symbol used to prevent goto-skips-init
     ErrorSink *eSink;           // sink for error messages
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 520e05f4190..174d9b4dc14 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -231,8 +231,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
             if (sc.flags & SCOPE.Cfile && funcdecl.isCMain() && f.next.ty == Tint32)
                 return true;
 
-            return f.next.ty == Tvoid &&
-                (funcdecl.isMain() || global.params.betterC && funcdecl.isCMain());
+            return f.next.ty == Tvoid && (funcdecl.isMain() || funcdecl.isCMain());
         }
 
         VarDeclaration _arguments = null;
@@ -346,6 +345,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
             sc2.tf = null;
             sc2.os = null;
             sc2.inLoop = false;
+            sc2.inDefaultArg = false;
             sc2.userAttribDecl = null;
             if (sc2.intypeof == 1)
                 sc2.intypeof = 2;
@@ -570,7 +570,7 @@ private extern(C++) final class Semantic3Visitor : Visitor
 
                 if ((needEnsure && global.params.useOut == CHECKENABLE.on) || fpostinv)
                 {
-                    funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel);
+                    funcdecl.returnLabel = funcdecl.searchLabel(Id.returnLabel, Loc.initial);
                 }
 
                 // scope of out contract (need for vresult.semantic)
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 59398a70cb8..8038770b291 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -24,6 +24,7 @@ import dmd.init;
 import dmd.mtype;
 import dmd.postordervisitor;
 import dmd.tokens;
+import dmd.typesem;
 import dmd.visitor;
 
 /**************************************************
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 229cf17bb6a..d4827ae6aa1 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -3753,7 +3753,10 @@ public bool throwSemantic(const ref Loc loc, ref Expression exp, Scope* sc)
 {
     if (!global.params.useExceptions)
     {
-        loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr);
+        version (IN_GCC)
+            loc.error("cannot use `throw` statements with `-fno-exceptions`");
+        else
+            loc.error("cannot use `throw` statements with %s", global.params.betterC ? "-betterC".ptr : "-nothrow".ptr);
         return false;
     }
 
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 09c4912a521..153eb4eb68b 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -324,4 +324,4 @@ Tuple *isTuple(RootObject *o);
 Parameter *isParameter(RootObject *o);
 TemplateParameter *isTemplateParameter(RootObject *o);
 bool isError(const RootObject *const o);
-void printTemplateStats();
+void printTemplateStats(bool listInstances, ErrorSink* eSink);
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 51b4ef885f1..714af8a0568 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -430,6 +430,123 @@ private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject i
     return sm;
 }
 
+/***************************************************
+ * Determine if type t is copyable.
+ * Params:
+ *      t = type to check
+ * Returns:
+ *      true if we can copy it
+ */
+bool isCopyable(Type t)
+{
+    //printf("isCopyable() %s\n", t.toChars());
+    if (auto ts = t.isTypeStruct())
+    {
+        if (ts.sym.postblit &&
+            ts.sym.postblit.storage_class & STC.disable)
+            return false;
+        if (ts.sym.hasCopyCtor)
+        {
+            // check if there is a matching overload of the copy constructor and whether it is disabled or not
+            // `assert(ctor)` fails on Win32 and Win_32_64. See: https://auto-tester.puremagic.com/pull-history.ghtml?projectid=1&repoid=1&pullid=10575
+            Dsymbol ctor = search_function(ts.sym, Id.ctor);
+            assert(ctor);
+            scope el = new IdentifierExp(Loc.initial, Id.p); // dummy lvalue
+            el.type = cast() ts;
+            Expressions* args = new Expressions();
+            args.push(el);
+            FuncDeclaration f = resolveFuncCall(Loc.initial, null, ctor, null, cast()ts, ArgumentList(args), FuncResolveFlag.quiet);
+            if (!f || f.storage_class & STC.disable)
+                return false;
+        }
+    }
+    return true;
+}
+
+/************************************
+ * Determine mutability of indirections in (ref) t.
+ *
+ * Returns: When the type has any mutable indirections, returns 0.
+ * When all indirections are immutable, returns 2.
+ * Otherwise, when the type has const/inout indirections, returns 1.
+ *
+ * Params:
+ *      isref = if true, check `ref t`; otherwise, check just `t`
+ *      t = the type that is being checked
+ */
+int mutabilityOfType(bool isref, Type t)
+{
+    if (isref)
+    {
+        if (t.mod & MODFlags.immutable_)
+            return 2;
+        if (t.mod & (MODFlags.const_ | MODFlags.wild))
+            return 1;
+        return 0;
+    }
+
+    t = t.baseElemOf();
+
+    if (!t.hasPointers() || t.mod & MODFlags.immutable_)
+        return 2;
+
+    /* Accept immutable(T)[] and immutable(T)* as being strongly pure
+     */
+    if (t.ty == Tarray || t.ty == Tpointer)
+    {
+        Type tn = t.nextOf().toBasetype();
+        if (tn.mod & MODFlags.immutable_)
+            return 2;
+        if (tn.mod & (MODFlags.const_ | MODFlags.wild))
+            return 1;
+    }
+
+    /* The rest of this is too strict; fix later.
+     * For example, the only pointer members of a struct may be immutable,
+     * which would maintain strong purity.
+     * (Just like for dynamic arrays and pointers above.)
+     */
+    if (t.mod & (MODFlags.const_ | MODFlags.wild))
+        return 1;
+
+    /* Should catch delegates and function pointers, and fold in their purity
+     */
+    return 0;
+}
+
+/********************************************
+ * Set 'purity' field of 'typeFunction'.
+ * Do this lazily, as the parameter types might be forward referenced.
+ */
+extern(C++) void purityLevel(TypeFunction typeFunction)
+{
+    TypeFunction tf = typeFunction;
+    if (tf.purity != PURE.fwdref)
+        return;
+
+    typeFunction.purity = PURE.const_; // assume strong until something weakens it
+
+    /* Evaluate what kind of purity based on the modifiers for the parameters
+     */
+    foreach (i, fparam; tf.parameterList)
+    {
+        Type t = fparam.type;
+        if (!t)
+            continue;
+
+        if (fparam.storageClass & (STC.lazy_ | STC.out_))
+        {
+            typeFunction.purity = PURE.weak;
+            break;
+        }
+        const pref = (fparam.storageClass & STC.ref_) != 0;
+        if (mutabilityOfType(pref, t) == 0)
+            typeFunction.purity = PURE.weak;
+    }
+
+    tf.purity = typeFunction.purity;
+}
+
 /******************************************
  * We've mistakenly parsed `t` as a type.
  * Redo `t` as an Expression only if there are no type modifiers.
@@ -486,6 +603,77 @@ Expression typeToExpression(Type t)
     }
 }
 
+/*************************************
+ * https://issues.dlang.org/show_bug.cgi?id=14488
+ * Check if the inner most base type is complex or imaginary.
+ * Should only give alerts when set to emit transitional messages.
+ * Params:
+ *  type = type to check
+ *  loc = The source location.
+ *  sc = scope of the type
+ */
+extern (D) bool checkComplexTransition(Type type, const ref Loc loc, Scope* sc)
+{
+    if (sc.isDeprecated())
+        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)
+        return false;
+
+    Type t = type.baseElemOf();
+    while (t.ty == Tpointer || t.ty == Tarray)
+        t = t.nextOf().baseElemOf();
+
+    // Basetype is an opaque enum, nothing to check.
+    if (t.ty == Tenum && !(cast(TypeEnum)t).sym.memtype)
+        return false;
+
+    if (t.isimaginary() || t.iscomplex())
+    {
+        if (sc.flags & SCOPE.Cfile)
+            return true;            // complex/imaginary not deprecated in C code
+        Type rt;
+        switch (t.ty)
+        {
+        case Tcomplex32:
+        case Timaginary32:
+            rt = Type.tfloat32;
+            break;
+
+        case Tcomplex64:
+        case Timaginary64:
+            rt = Type.tfloat64;
+            break;
+
+        case Tcomplex80:
+        case Timaginary80:
+            rt = Type.tfloat80;
+            break;
+
+        default:
+            assert(0);
+        }
+        // @@@DEPRECATED_2.117@@@
+        // Deprecated in 2.097 - Can be made an error from 2.117.
+        // The deprecation period is longer than usual as `cfloat`,
+        // `cdouble`, and `creal` were quite widely used.
+        if (t.iscomplex())
+        {
+            deprecation(loc, "use of complex type `%s` is deprecated, use `std.complex.Complex!(%s)` instead",
+                type.toChars(), rt.toChars());
+            return true;
+        }
+        else
+        {
+            deprecation(loc, "use of imaginary type `%s` is deprecated, use `%s` instead",
+                type.toChars(), rt.toChars());
+            return true;
+        }
+    }
+    return false;
+}
+
 /********************************
  * 'args' are being matched to function type 'tf'
  * Determine match level.
@@ -494,12 +682,12 @@ Expression typeToExpression(Type t)
  *      tthis = type of `this` pointer, null if not member function
  *      argumentList = arguments to function call
  *      flag = 1: performing a partial ordering match
- *      pMessage = address to store error message, or null
+ *      errorHelper = delegate to call for error messages
  *      sc = context
  * Returns:
  *      MATCHxxxx
  */
-extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, void delegate(const(char)*) scope errorHelper = null, Scope* sc = null)
 {
     //printf("TypeFunction::callMatch() %s\n", tf.toChars());
     MATCH match = MATCH.exact; // assume exact match
@@ -542,7 +730,7 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
         {
             // suppress early exit if an error message is wanted,
             // so we can check any matching args are valid
-            if (!pMessage)
+            if (!errorHelper)
                 return MATCH.nomatch;
         }
         // too many args; no match
@@ -552,18 +740,25 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
     // https://issues.dlang.org/show_bug.cgi?id=22997
     if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
     {
-        OutBuffer buf;
-        buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
-        if (pMessage)
-            *pMessage = buf.extractChars();
+        if (errorHelper)
+        {
+            OutBuffer buf;
+            buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
+            errorHelper(buf.peekChars());
+        }
         return MATCH.nomatch;
     }
+    const(char)* failMessage;
+    const(char)** pMessage = errorHelper ? &failMessage : null;
     auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
     Expression[] args;
     if (!resolvedArgs)
     {
-        if (!pMessage || *pMessage)
+        if (failMessage)
+        {
+            errorHelper(failMessage);
             return MATCH.nomatch;
+        }
 
         // if no message was provided, it was because of overflow which will be diagnosed below
         match = MATCH.nomatch;
@@ -642,6 +837,8 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
                 if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
                     return vmatch < match ? vmatch : match;
                 // Error message was already generated in `matchTypeSafeVarArgs`
+                if (failMessage)
+                    errorHelper(failMessage);
                 return MATCH.nomatch;
             }
             if (pMessage && u >= args.length)
@@ -651,16 +848,18 @@ extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentLis
             else if (pMessage && !*pMessage)
                 *pMessage = tf.getParamError(args[u], p);
 
+            if (errorHelper)
+                errorHelper(*pMessage);
             return MATCH.nomatch;
         }
         if (m < match)
             match = m; // pick worst match
     }
 
-    if (pMessage && !parameterList.varargs && args.length > nparams)
+    if (errorHelper && !parameterList.varargs && args.length > nparams)
     {
         // all parameters had a match, but there are surplus args
-        *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length);
+        errorHelper(tf.getMatchError("expected %d argument(s), not %d", nparams, args.length));
         return MATCH.nomatch;
     }
     //printf("match = %d\n", match);
@@ -687,7 +886,7 @@ private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
     Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
     e = new CallExp(arg.loc, e, arg);
     //printf("e = %s\n", e.toChars());
-    if (.trySemantic(e, sc))
+    if (dmd.expressionsem.trySemantic(e, sc))
         return true;
 
     if (pMessage)
@@ -1017,6 +1216,70 @@ private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
     }
 }
 
+/***************************************
+ * Return !=0 if type has pointers that need to
+ * be scanned by the GC during a collection cycle.
+ */
+extern(C++) bool hasPointers(Type t)
+{
+    bool visitType(Type _)              { return false; }
+    bool visitDArray(TypeDArray _)      { return true; }
+    bool visitAArray(TypeAArray _)      { return true; }
+    bool visitPointer(TypePointer _)    { return true; }
+    bool visitDelegate(TypeDelegate _)  { return true; }
+    bool visitClass(TypeClass _)        { return true; }
+    bool visitEnum(TypeEnum t)          { return t.memType().hasPointers(); }
+
+    /* Although null isn't dereferencable, treat it as a pointer type for
+     * attribute inference, generic code, etc.
+     */
+    bool visitNull(TypeNull _)          { return true; }
+
+    bool visitSArray(TypeSArray t)
+    {
+        /* Don't want to do this, because:
+         *    struct S { T* array[0]; }
+         * may be a variable length struct.
+         */
+        //if (dim.toInteger() == 0)
+        //    return false;
+
+        if (t.next.ty == Tvoid)
+        {
+            // Arrays of void contain arbitrary data, which may include pointers
+            return true;
+        }
+        else
+            return t.next.hasPointers();
+    }
+
+    bool visitStruct(TypeStruct t)
+    {
+        StructDeclaration sym = t.sym;
+
+        if (sym.members && !sym.determineFields() && sym.type != Type.terror)
+            error(sym.loc, "no size because of forward references");
+
+        sym.determineTypeProperties();
+        return sym.hasPointerField;
+    }
+
+
+    switch(t.ty)
+    {
+        default:            return visitType(t);
+        case Tsarray:       return visitSArray(t.isTypeSArray());
+        case Tarray:        return visitDArray(t.isTypeDArray());
+        case Taarray:       return visitAArray(t.isTypeAArray());
+        case Tpointer:      return visitPointer(t.isTypePointer());
+        case Tdelegate:     return visitDelegate(t.isTypeDelegate());
+        case Tstruct:       return visitStruct(t.isTypeStruct());
+        case Tenum:         return visitEnum(t.isTypeEnum());
+        case Tclass:        return visitClass(t.isTypeClass());
+        case Tnull:         return visitNull(t.isTypeNull());
+    }
+}
+
 /******************************************
  * Perform semantic analysis on a type.
  * Params:
@@ -1661,9 +1924,12 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             else
             {
                 e = inferType(e, fparam.type);
+                Scope* sc2 = sc.push();
+                sc2.inDefaultArg = true;
                 Initializer iz = new ExpInitializer(e.loc, e);
-                iz = iz.initializerSemantic(sc, fparam.type, INITnointerpret);
+                iz = iz.initializerSemantic(sc2, fparam.type, INITnointerpret);
                 e = iz.initializerToExpression();
+                sc2.pop();
             }
             if (e.op == EXP.function_) // https://issues.dlang.org/show_bug.cgi?id=4820
             {
@@ -2553,6 +2819,31 @@ extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
     }
 }
 
+extern(C++) Type trySemantic(Type type, const ref Loc loc, Scope* sc)
+{
+    //printf("+trySemantic(%s) %d\n", toChars(), global.errors);
+
+    // Needed to display any deprecations that were gagged
+    auto tcopy = type.syntaxCopy();
+
+    const errors = global.startGagging();
+    Type t = typeSemantic(type, loc, sc);
+    if (global.endGagging(errors) || t.ty == Terror) // if any errors happened
+    {
+        t = null;
+    }
+    else
+    {
+        // If `typeSemantic` succeeded, there may have been deprecations that
+        // were gagged due the `startGagging` above.  Run again to display
+        // those deprecations.  https://issues.dlang.org/show_bug.cgi?id=19107
+        if (global.gaggedWarnings > 0)
+            typeSemantic(tcopy, loc, sc);
+    }
+    //printf("-trySemantic(%s) %d\n", toChars(), global.errors);
+    return t;
+}
+
 /************************************
  * If an identical type to `type` is in `type.stringtable`, return
  * the latter one. Otherwise, add it to `type.stringtable`.
@@ -5216,6 +5507,117 @@ extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
     }
 }
 
+/*
+If `type` resolves to a dsymbol, then that
+dsymbol is returned.
+
+Params:
+  type = the type that is checked
+  sc   = the scope where the type is used
+
+Returns:
+  The dsymbol to which the type resolve or `null`
+  if the type does resolve to any symbol (for example,
+  in the case of basic types).
+*/
+extern(C++) Dsymbol toDsymbol(Type type, Scope* sc)
+{
+    Dsymbol visitType(Type _)            { return null; }
+    Dsymbol visitStruct(TypeStruct type) { return type.sym; }
+    Dsymbol visitEnum(TypeEnum type)     { return type.sym; }
+    Dsymbol visitClass(TypeClass type)   { return type.sym; }
+
+    Dsymbol visitTraits(TypeTraits type)
+    {
+        Type t;
+        Expression e;
+        Dsymbol s;
+        resolve(type, type.loc, sc, e, t, s);
+        if (t && t.ty != Terror)
+            s = t.toDsymbol(sc);
+        else if (e)
+            s = getDsymbol(e);
+
+        return s;
+    }
+
+    Dsymbol visitMixin(TypeMixin type)
+    {
+        Type t;
+        Expression e;
+        Dsymbol s;
+        resolve(type, type.loc, sc, e, t, s);
+        if (t)
+            s = t.toDsymbol(sc);
+        else if (e)
+            s = getDsymbol(e);
+
+        return s;
+    }
+
+    Dsymbol visitIdentifier(TypeIdentifier type)
+    {
+        //printf("TypeIdentifier::toDsymbol('%s')\n", toChars());
+        if (!sc)
+            return null;
+
+        Type t;
+        Expression e;
+        Dsymbol s;
+        resolve(type, type.loc, sc, e, t, s);
+        if (t && t.ty != Tident)
+            s = t.toDsymbol(sc);
+        if (e)
+            s = getDsymbol(e);
+
+        return s;
+    }
+
+    Dsymbol visitInstance(TypeInstance type)
+    {
+        Type t;
+        Expression e;
+        Dsymbol s;
+        //printf("TypeInstance::semantic(%s)\n", toChars());
+        resolve(type, type.loc, sc, e, t, s);
+        if (t && t.ty != Tinstance)
+            s = t.toDsymbol(sc);
+        return s;
+    }
+
+    Dsymbol visitTypeof(TypeTypeof type)
+    {
+        //printf("TypeTypeof::toDsymbol('%s')\n", toChars());
+        Expression e;
+        Type t;
+        Dsymbol s;
+        resolve(type, type.loc, sc, e, t, s);
+        return s;
+    }
+
+    Dsymbol visitReturn(TypeReturn type)
+    {
+        Expression e;
+        Type t;
+        Dsymbol s;
+        resolve(type, type.loc, sc, e, t, s);
+        return s;
+    }
+
+    switch(type.ty)
+    {
+        default:                return visitType(type);
+        case Ttraits:           return visitTraits(type.isTypeTraits());
+        case Tmixin:            return visitMixin(type.isTypeMixin());
+        case Tident:            return visitIdentifier(type.isTypeIdentifier());
+        case Tinstance:         return visitInstance(type.isTypeInstance());
+        case Ttypeof:           return visitTypeof(type.isTypeTypeof());
+        case Treturn:           return visitReturn(type.isTypeReturn());
+        case Tstruct:           return visitStruct(type.isTypeStruct());
+        case Tenum:             return visitEnum(type.isTypeEnum());
+        case Tclass:            return visitClass(type.isTypeClass());
+    }
+}
 
 /**********************************************
  * Extract complex type from core.stdc.config
@@ -5541,6 +5943,144 @@ Lnotcovariant:
     return Covariant.no;
 }
 
+/************************************
+ * Take the specified storage class for p,
+ * and use the function signature to infer whether
+ * STC.scope_ and STC.return_ should be OR'd in.
+ * (This will not affect the name mangling.)
+ * Params:
+ *  tf = TypeFunction to use to get the signature from
+ *  tthis = type of `this` parameter, null if none
+ *  p = parameter to this function
+ *  outerVars = context variables p could escape into, if any
+ *  indirect = is this for an indirect or virtual function call?
+ * Returns:
+ *  storage class with STC.scope_ or STC.return_ OR'd in
+ */
+StorageClass parameterStorageClass(TypeFunction tf, Type tthis, Parameter p, VarDeclarations* outerVars = null,
+    bool indirect = false)
+{
+    //printf("parameterStorageClass(p: %s)\n", p.toChars());
+    auto stc = p.storageClass;
+
+    // When the preview switch is enable, `in` parameters are `scope`
+    if (stc & STC.constscoperef)
+        return stc | STC.scope_;
+
+    if (stc & (STC.scope_ | STC.return_ | STC.lazy_) || tf.purity == PURE.impure)
+        return stc;
+
+    /* If haven't inferred the return type yet, can't infer storage classes
+     */
+    if (!tf.nextOf() || !tf.isnothrow())
+        return stc;
+
+    tf.purityLevel();
+
+    static bool mayHavePointers(Type t)
+    {
+        if (auto ts = t.isTypeStruct())
+        {
+            auto sym = ts.sym;
+            if (sym.members && !sym.determineFields() && sym.type != Type.terror)
+                // struct is forward referenced, so "may have" pointers
+                return true;
+        }
+        return t.hasPointers();
+    }
+
+    // See if p can escape via any of the other parameters
+    if (tf.purity == PURE.weak)
+    {
+        /*
+         * Indirect calls may escape p through a nested context
+         * See:
+         *   https://issues.dlang.org/show_bug.cgi?id=24212
+         *   https://issues.dlang.org/show_bug.cgi?id=24213
+         */
+        if (indirect)
+            return stc;
+
+        // Check escaping through parameters
+        foreach (i, fparam; tf.parameterList)
+        {
+            Type t = fparam.type;
+            if (!t)
+                continue;
+            t = t.baseElemOf();     // punch thru static arrays
+            if (t.isMutable() && t.hasPointers())
+            {
+                if (fparam.isReference() && fparam != p)
+                    return stc;
+
+                if (t.ty == Tdelegate)
+                    return stc;     // could escape thru delegate
+
+                if (t.ty == Tclass)
+                    return stc;
+
+                /* if t is a pointer to mutable pointer
+                 */
+                if (auto tn = t.nextOf())
+                {
+                    if (tn.isMutable() && mayHavePointers(tn))
+                        return stc;   // escape through pointers
+                }
+            }
+        }
+
+        // Check escaping through `this`
+        if (tthis && tthis.isMutable())
+        {
+            foreach (VarDeclaration v; isAggregate(tthis).fields)
+            {
+                if (v.hasPointers())
+                    return stc;
+            }
+        }
+
+        // Check escaping through nested context
+        if (outerVars && tf.isMutable())
+        {
+            foreach (VarDeclaration v; *outerVars)
+            {
+                if (v.hasPointers())
+                    return stc;
+            }
+        }
+    }
+
+    // Check escaping through return value
+    Type tret = tf.nextOf().toBasetype();
+    if (tf.isref || tret.hasPointers())
+    {
+        return stc | STC.scope_ | STC.return_ | STC.returnScope;
+    }
+    else
+        return stc | STC.scope_;
+}
+
+extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
+{
+    auto tc = tthis.isTypeClass();
+    if (!tc)
+        return false;
+
+    if (!t || t.ty != Tclass)
+        return false;
+
+    ClassDeclaration cd = t.isTypeClass().sym;
+    if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
+        cd.dsymbolSemantic(null);
+    if (tc.sym.semanticRun < PASS.semanticdone && !tc.sym.isBaseInfoComplete())
+        tc.sym.dsymbolSemantic(null);
+
+    if (tc.sym.isBaseOf(cd, poffset))
+        return true;
+
+    return false;
+}
+
 /******************************* Private *****************************************/
 
 private:
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 7e63b0ba890..6f596c5ac20 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -204,6 +204,22 @@ binop_assignment (tree_code code, Expression *e1, Expression *e2)
   return compound_expr (lexpr, expr);
 }
 
+/* Compile the function literal body.  */
+
+static void
+build_lambda_tree (FuncLiteralDeclaration *fld, Type *type = NULL)
+{
+  /* This check is for lambda's, remove `vthis' as function isn't nested.  */
+  if (fld->tok == TOK::reserved && (type == NULL || type->ty == TY::Tpointer))
+    {
+      fld->tok = TOK::function_;
+      fld->vthis = NULL;
+    }
+
+  /* Compile the function literal body.  */
+  build_decl_tree (fld);
+}
+
 /* Implements the visitor interface to build the GCC trees of all Expression
    AST classes emitted from the D Front-end.
    All visit methods accept one parameter E, which holds the frontend AST
@@ -2012,17 +2028,8 @@ public:
 
   void visit (FuncExp *e) final override
   {
-    Type *ftype = e->type->toBasetype ();
-
-    /* This check is for lambda's, remove `vthis' as function isn't nested.  */
-    if (e->fd->tok == TOK::reserved && ftype->ty == TY::Tpointer)
-      {
-	e->fd->tok = TOK::function_;
-	e->fd->vthis = NULL;
-      }
-
-    /* Compile the function literal body.  */
-    build_decl_tree (e->fd);
+    /* Compile the declaration.  */
+    build_lambda_tree (e->fd, e->type->toBasetype ());
 
     /* If nested, this will be a trampoline.  */
     if (e->fd->isNested ())
@@ -2071,6 +2078,10 @@ public:
     if (e->var->isFuncDeclaration ())
       result = maybe_reject_intrinsic (result);
 
+    /* Emit lambdas, same as is done in FuncExp.  */
+    if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ())
+      build_lambda_tree (fld);
+
     if (declaration_reference_p (e->var))
       gcc_assert (POINTER_TYPE_P (TREE_TYPE (result)));
     else
@@ -2105,19 +2116,9 @@ public:
 	return;
       }
 
-    /* This check is same as is done in FuncExp for lambdas.  */
-    FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ();
-    if (fld != NULL)
-      {
-	if (fld->tok == TOK::reserved)
-	  {
-	    fld->tok = TOK::function_;
-	    fld->vthis = NULL;
-	  }
-
-	/* Compiler the function literal body.  */
-	build_decl_tree (fld);
-      }
+    /* Emit lambdas, same as is done in FuncExp.  */
+    if (FuncLiteralDeclaration *fld = e->var->isFuncLiteralDeclaration ())
+      build_lambda_tree (fld);
 
     if (this->constp_)
       {
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index 257a2abe5d7..dfab0e651b9 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -259,7 +259,8 @@ create_tinfo_types (Module *mod)
 			  array_type_node, array_type_node, array_type_node,
 			  array_type_node, ptr_type_node, ptr_type_node,
 			  ptr_type_node, d_uint_type, ptr_type_node,
-			  array_type_node, ptr_type_node, ptr_type_node, NULL);
+			  array_type_node, ptr_type_node, d_ulong_type,
+			  d_ulong_type, ptr_type_node, NULL);
 
   object_module = mod;
 }
@@ -814,6 +815,7 @@ public:
 	void *deallocator;
 	OffsetTypeInfo[] m_offTi;
 	void function(Object) defaultConstructor;
+	ulong[2] nameSig
 	immutable(void)* m_RTInfo;
 
      Information relating to interfaces, and their vtables are laid out
@@ -932,6 +934,10 @@ public:
 	else
 	  this->layout_field (null_pointer_node);
 
+	/* ulong[2] nameSig;  */
+	this->layout_field (build_zero_cst (d_ulong_type));
+	this->layout_field (build_zero_cst (d_ulong_type));
+
 	/* immutable(void)* m_RTInfo;  */
 	if (cd->getRTInfo)
 	  this->layout_field (build_expr (cd->getRTInfo, true));
@@ -979,6 +985,10 @@ public:
 	this->layout_field (null_array_node);
 	this->layout_field (null_pointer_node);
 
+	/* ulong[2] nameSig;  */
+	this->layout_field (build_zero_cst (d_ulong_type));
+	this->layout_field (build_zero_cst (d_ulong_type));
+
 	/* immutable(void)* m_RTInfo;  */
 	if (cd->getRTInfo)
 	  this->layout_field (build_expr (cd->getRTInfo, true));
@@ -1084,7 +1094,7 @@ public:
 
     /* StructFlags m_flags;  */
     int m_flags = StructFlags::none;
-    if (ti->hasPointers ())
+    if (hasPointers (ti))
       m_flags |= StructFlags::hasPointers;
     this->layout_field (build_integer_cst (m_flags, d_uint_type));
 
diff --git a/gcc/testsuite/gdc.test/compilable/b18242.d b/gcc/testsuite/gdc.test/compilable/b18242.d
index 3bc699aa7da..9909620ae3f 100644
--- a/gcc/testsuite/gdc.test/compilable/b18242.d
+++ b/gcc/testsuite/gdc.test/compilable/b18242.d
@@ -7,7 +7,7 @@ class Object { }
 class TypeInfo { }
 class TypeInfo_Class : TypeInfo
 {
-    version(D_LP64) { ubyte[136] _x; } else { ubyte[68] _x; }
+    version(D_LP64) { ubyte[136+16] _x; } else { ubyte[68+16] _x; }
 }
 
 class Throwable { }
diff --git a/gcc/testsuite/gdc.test/compilable/issue24316.d b/gcc/testsuite/gdc.test/compilable/issue24316.d
new file mode 100644
index 00000000000..16d8a8b09b7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue24316.d
@@ -0,0 +1,13 @@
+struct S
+{
+    int i;
+}
+
+int f(immutable S *s)
+{
+    return s.i;
+}
+
+immutable S globalS = S(5);
+
+static assert (f(&globalS) == 5);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24295.d b/gcc/testsuite/gdc.test/fail_compilation/test24295.d
new file mode 100644
index 00000000000..58b6e92df8f
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24295.d
@@ -0,0 +1,13 @@
+// REQUIRED_ARGS: -betterC
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24295.d(12): Error: expression `new int[](1$?:32=u|64=LU$)` allocates with the GC and cannot be used with switch `-betterC`
+---
+*/
+
+void f()
+{
+   int[] overlaps = new int[1];
+}
diff --git a/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d
new file mode 100644
index 00000000000..4278f7f5cde
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/imports/issue18919b.d
@@ -0,0 +1,250 @@
+module imports.issue18919b;
+
+import core.stdc.stdio;
+
+// Remove directories from paths. Used to make the output platform-independent.
+string baseName(string path)
+{
+    foreach_reverse (i, char c; path)
+    {
+        if (c == '/' || c == '\\')
+            return path[i + 1 .. $];
+    }
+    return path;
+}
+const(char)* baseName(const(char)* path)
+{
+    for (const(char)* ptr = path; *ptr; ptr++)
+    {
+        if (*ptr == '/' || *ptr == '\\')
+            path = ptr + 1;
+    }
+    return path;
+}
+
+void func1(string file = __FILE__, size_t line = __LINE__,
+    string func = __FUNCTION__,
+    string pfunc = __PRETTY_FUNCTION__,
+    string mod = __MODULE__)
+{
+    file = baseName(file);
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) file.length, file.ptr, cast(int) line,
+        cast(int) func.length, func.ptr,
+        cast(int) pfunc.length, pfunc.ptr,
+        cast(int) mod.length, mod.ptr);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=21211
+void func2(const(char)* file = __FILE__.ptr, size_t line = __LINE__,
+    const(char)* func = __FUNCTION__.ptr,
+    const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+    const(char)* mod = __MODULE__.ptr)
+{
+    file = baseName(file);
+    printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+        file, cast(int) line, func, pfunc, mod);
+}
+
+// https://issues.dlang.org/show_bug.cgi?id=18919
+struct Loc3
+{
+    string file;
+    size_t line;
+    string func;
+    string pfunc;
+    string mod;
+}
+void func3(Loc3 loc = Loc3(__FILE__, __LINE__,
+    __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+        cast(int) loc.func.length, loc.func.ptr,
+        cast(int) loc.pfunc.length, loc.pfunc.ptr,
+        cast(int) loc.mod.length, loc.mod.ptr);
+}
+Loc3 defaultLoc3(string file = __FILE__, size_t line = __LINE__,
+    string func = __FUNCTION__,
+    string pfunc = __PRETTY_FUNCTION__,
+    string mod = __MODULE__)
+{
+    return Loc3(file, line, func, pfunc, mod);
+}
+void func3b(Loc3 loc = defaultLoc3)
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+        cast(int) loc.func.length, loc.func.ptr,
+        cast(int) loc.pfunc.length, loc.pfunc.ptr,
+        cast(int) loc.mod.length, loc.mod.ptr);
+}
+enum Loc3Mixin = q{Loc3(__FILE__, __LINE__,
+    __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__)};
+void func3c(Loc3 loc = mixin(Loc3Mixin))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+        cast(int) loc.func.length, loc.func.ptr,
+        cast(int) loc.pfunc.length, loc.pfunc.ptr,
+        cast(int) loc.mod.length, loc.mod.ptr);
+}
+void func3d(Loc3* loc = new Loc3(__FILE__, __LINE__,
+    __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+        cast(int) loc.func.length, loc.func.ptr,
+        cast(int) loc.pfunc.length, loc.pfunc.ptr,
+        cast(int) loc.mod.length, loc.mod.ptr);
+}
+
+struct Loc4
+{
+    const(char)* file;
+    size_t line;
+    const(char)* func;
+    const(char)* pfunc;
+    const(char)* mod;
+}
+void func4(Loc4 loc = Loc4(__FILE__.ptr, __LINE__,
+    __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+        loc.file, cast(int) loc.line,
+        loc.func,
+        loc.pfunc,
+        loc.mod);
+}
+Loc4 defaultLoc4(const(char)* file = __FILE__.ptr, size_t line = __LINE__,
+    const(char)* func = __FUNCTION__.ptr,
+    const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+    const(char)* mod = __MODULE__.ptr)
+{
+    return Loc4(file, line, func, pfunc, mod);
+}
+void func4b(Loc4 loc = defaultLoc4)
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+        loc.file, cast(int) loc.line,
+        loc.func,
+        loc.pfunc,
+        loc.mod);
+}
+enum Loc4Mixin = q{Loc4(__FILE__.ptr, __LINE__,
+    __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr)};
+void func4c(Loc4 loc = mixin(Loc4Mixin))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+        loc.file, cast(int) loc.line,
+        loc.func,
+        loc.pfunc,
+        loc.mod);
+}
+void func4d(Loc4* loc = new Loc4(__FILE__.ptr, __LINE__,
+    __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr))
+{
+    loc.file = baseName(loc.file);
+    printf("%s: %s:%d %s %s %s\n", __FUNCTION__.ptr,
+        loc.file, cast(int) loc.line,
+        loc.func,
+        loc.pfunc,
+        loc.mod);
+}
+
+void func5(string file = baseName(__FILE__), int line = __LINE__,
+    string func = __FUNCTION__,
+    string pfunc = __PRETTY_FUNCTION__,
+    string mod = __MODULE__)()
+{
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) file.length, file.ptr, line,
+        cast(int) func.length, func.ptr,
+        cast(int) pfunc.length, pfunc.ptr,
+        cast(int) mod.length, mod.ptr);
+}
+
+void func6(string file = baseName(__FILE__), int line = __LINE__,
+    const(char)* func = __FUNCTION__.ptr,
+    const(char)* pfunc = __PRETTY_FUNCTION__.ptr,
+    const(char)* mod = __MODULE__.ptr)()
+{
+    printf("%s: %.*s:%d %s %s %s\n", __FUNCTION__.ptr,
+        cast(int) file.length, file.ptr, line, func, pfunc, mod);
+}
+
+void func7(int expr1 = 1000 +  __LINE__ * 2,
+    string expr2 = "file=" ~ baseName(__FILE__) ~ " func=" ~ __FUNCTION__,
+    int expr3 = __LINE__ > 5 ? 1 : 2)
+{
+    printf("%s: expr1=%d, %.*s, expr3=%d\n", __FUNCTION__.ptr, expr1, cast(int) expr2.length, expr2.ptr, expr3);
+}
+
+immutable string[2] constants = ["constant1", "constant2"];
+void func8(int[] expr1 = [__LINE__, __LINE__ + 1000],
+    int[string] expr2 = [baseName(__FILE__): __LINE__],
+    string expr3 = constants[__LINE__ > 5],
+    string expr4 = __FILE__[0 .. __FILE__.length - 2])
+{
+    expr4 = baseName(expr4);
+    printf("%s: expr1=[", __FUNCTION__.ptr);
+    foreach (i, x; expr1)
+        printf("%d, ", x);
+    printf("], expr2=[");
+    foreach (k, v; expr2)
+        printf("%.*s: %d, ", cast(int) k.length, k.ptr, v);
+    printf("], expr3=%.*s", cast(int) expr3.length, expr3.ptr);
+    printf(", expr4=%.*s\n", cast(int) expr4.length, expr4.ptr);
+}
+
+void func9(void function(string file = __FILE__, size_t line = __LINE__, string mod = __MODULE__)
+    fp = (string file, size_t line, string mod)
+    {
+        file = baseName(file);
+        printf("imports.issue18919b.func9.fp: %.*s:%d %.*s\n",
+             cast(int) file.length, file.ptr, cast(int) line,
+             cast(int) mod.length, mod.ptr);
+    })
+{
+    fp();
+}
+
+void func10(string expr1 = mixin(() { return "\"expr1=" ~ __MODULE__ ~ "\""; } ()),
+    string expr2 = mixin("\"expr2=" ~ __MODULE__ ~ "\""))
+{
+    printf("%s: %.*s, %.*s\n", __FUNCTION__.ptr,
+        cast(int) expr1.length, expr1.ptr,
+        cast(int) expr2.length, expr2.ptr);
+}
+
+template ctLoc3(string file, int line,
+    string func, string pfunc, string mod)
+{
+    enum Loc3 ctLoc3 = Loc3(file, line, func, pfunc, mod);
+}
+
+void func11(Loc3 loc = ctLoc3!(baseName(__FILE__), __LINE__,
+    __FUNCTION__, __PRETTY_FUNCTION__, __MODULE__))
+{
+    printf("%s: %.*s:%d %.*s %.*s %.*s\n", __FUNCTION__.ptr,
+        cast(int) loc.file.length, loc.file.ptr, cast(int) loc.line,
+        cast(int) loc.func.length, loc.func.ptr,
+        cast(int) loc.pfunc.length, loc.pfunc.ptr,
+        cast(int) loc.mod.length, loc.mod.ptr);
+}
+
+void func12(const(char)*[] args = [baseName(__FILE__.ptr),
+    __FUNCTION__.ptr, __PRETTY_FUNCTION__.ptr, __MODULE__.ptr])
+{
+    printf("%s:", __FUNCTION__.ptr);
+    foreach (arg; args)
+        printf(" %s", arg);
+    printf("\n");
+}
diff --git a/gcc/testsuite/gdc.test/runnable/issue18919.d b/gcc/testsuite/gdc.test/runnable/issue18919.d
new file mode 100644
index 00000000000..815e018d649
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/issue18919.d
@@ -0,0 +1,47 @@
+/*
+EXTRA_SOURCES: imports/issue18919b.d
+RUN_OUTPUT:
+---
+imports.issue18919b.func1: issue18919.d:29 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func2: issue18919.d:30 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3: issue18919.d:31 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3b: issue18919.d:32 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3c: issue18919.d:33 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func3d: issue18919.d:34 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4: issue18919.d:35 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4b: issue18919.d:36 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4c: issue18919.d:37 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func4d: issue18919.d:38 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func5!("issue18919.d", 39, "issue18919.main", "void issue18919.main()", "issue18919").func5: issue18919.d:39 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func6!("issue18919.d", 40, "issue18919.main", "void issue18919.main()", "issue18919").func6: issue18919.d:40 issue18919.main void issue18919.main() issue18919
+imports.issue18919b.func7: expr1=1082, file=issue18919.d func=issue18919.main, expr3=1
+imports.issue18919b.func8: expr1=[42, 1042, ], expr2=[issue18919.d: 42, ], expr3=constant2, expr4=issue18919
+imports.issue18919b.func9.fp: issue18919b.d:216 imports.issue18919b
+imports.issue18919b.func10: expr1=imports.issue18919b, expr2=imports.issue18919b
+imports.issue18919b.func11: issue18919b.d:233   imports.issue18919b
+imports.issue18919b.func12: issue18919.d issue18919.main void issue18919.main() issue18919
+---
+*/
+import imports.issue18919b;
+
+void main()
+{
+    func1();
+    func2();
+    func3();
+    func3b();
+    func3c();
+    func3d();
+    func4();
+    func4b();
+    func4c();
+    func4d();
+    func5();
+    func6();
+    func7();
+    func8();
+    func9();
+    func10();
+    func11();
+    func12();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test18916.d b/gcc/testsuite/gdc.test/runnable/test18916.d
index 0e844ada15a..f14f32c31eb 100644
--- a/gcc/testsuite/gdc.test/runnable/test18916.d
+++ b/gcc/testsuite/gdc.test/runnable/test18916.d
@@ -11,9 +11,9 @@ struct Line
 
 void foo(Line line1 = __LINE__, int line2 = __LINE__, int line3 = int(__LINE__))
 {
-    assert(line1 == 12);
+    assert(line1 == 21);
     assert(line2 == 21);
-    assert(line3 == 12);
+    assert(line3 == 21);
 }
 
 void main()
diff --git a/gcc/testsuite/gdc.test/runnable/testptrref.d b/gcc/testsuite/gdc.test/runnable/testptrref.d
index 7255595cb57..af101b92464 100644
--- a/gcc/testsuite/gdc.test/runnable/testptrref.d
+++ b/gcc/testsuite/gdc.test/runnable/testptrref.d
@@ -3,6 +3,7 @@ version(CRuntime_Microsoft)
 {
     extern(C)
     {
+        extern __gshared void* __ImageBase;
         extern __gshared uint _DP_beg;
         extern __gshared uint _DP_end;
         extern __gshared uint _TP_beg;
@@ -18,8 +19,8 @@ version(CRuntime_Microsoft)
     {
         import core.internal.traits : externDFunc;
         alias findImageSection = externDFunc!("rt.sections_win64.findImageSection",
-                                              void[] function(string name) nothrow @nogc);
-        dataSection = findImageSection(".data");
+                                              void[] function(void* handle, string name) nothrow @nogc);
+        dataSection = findImageSection(&__ImageBase, ".data");
     }
 
     void[] tlsRange;
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d
index aeb2aab8336..cbcbd1a97f1 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest46.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest46.d
@@ -179,7 +179,7 @@ void test7()
 
 void foo8(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)
 {
-    assert(n1 < n2);
+    assert(n1 == n2);
     printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
 }
 
@@ -192,7 +192,7 @@ void test8()
 
 void foo9(int n1 = __LINE__ + 0, int n2 = __LINE__, string s = __FILE__)()
 {
-    assert(n1 < n2);
+    assert(n1 == n2);
     printf("n1 = %d, n2 = %d, s = %.*s\n", n1, n2, cast(int)s.length, s.ptr);
 }
 
@@ -8031,6 +8031,29 @@ void test18232()
     assert(u.method() == Canary.init);
 }
 
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=24332
+
+void test24332()
+{
+    class A {}
+    final class B : A {}
+
+    auto foo(A a) {
+        return cast(B) a;
+    }
+
+    auto a = new A();
+    auto n = cast(B) a;
+    assert(n is null);
+    auto b = cast(A) new B();
+    auto c = cast(B) b;
+    assert(c);
+    B e;
+    auto d = cast(B) cast(A) e;
+    assert(d is null);
+}
+
 /***************************************************/
 
 int main()
@@ -8352,6 +8375,7 @@ int main()
     test17349();
     test17915();
     test18232();
+    test24332();
 
     printf("Success\n");
     return 0;
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 2b4400f398e..138b0b6fa7c 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-d8e3976a58d6aef7c2c9371028a2ca4460b5b2ce
+bce5c1f7b521d22dcf1ea4e2bc3f76d9d28274fa
 
 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/exception.d b/libphobos/libdruntime/core/exception.d
index d2016b115f1..959ce83f02e 100644
--- a/libphobos/libdruntime/core/exception.d
+++ b/libphobos/libdruntime/core/exception.d
@@ -697,17 +697,17 @@ else
      * Throws:
      *  $(LREF OutOfMemoryError).
      */
-    extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+    extern (C) noreturn onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
     {
         // NOTE: Since an out of memory condition exists, no allocation must occur
         //       while generating this object.
-        throw staticError!OutOfMemoryError();
+        throw staticError!OutOfMemoryError(file, line);
     }
 
-    extern (C) noreturn onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
+    extern (C) noreturn onOutOfMemoryErrorNoGC(string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc
     {
         // suppress stacktrace until they are @nogc
-        throw staticError!OutOfMemoryError(false);
+        throw staticError!OutOfMemoryError(false, file, line);
     }
 }
 
@@ -718,11 +718,11 @@ else
  * Throws:
  *  $(LREF InvalidMemoryOperationError).
  */
-extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+extern (C) noreturn onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
 {
     // The same restriction applies as for onOutOfMemoryError. The GC is in an
     // undefined state, thus no allocation must occur while generating this object.
-    throw staticError!InvalidMemoryOperationError();
+    throw staticError!InvalidMemoryOperationError(file, line);
 }
 
 
diff --git a/libphobos/libdruntime/core/internal/container/array.d b/libphobos/libdruntime/core/internal/container/array.d
index 27292cdb1c3..b583341d06b 100644
--- a/libphobos/libdruntime/core/internal/container/array.d
+++ b/libphobos/libdruntime/core/internal/container/array.d
@@ -9,7 +9,7 @@ module core.internal.container.array;
 
 static import common = core.internal.container.common;
 
-import core.exception : onOutOfMemoryErrorNoGC;
+import core.exception : onOutOfMemoryError;
 
 struct Array(T)
 {
@@ -47,7 +47,7 @@ nothrow:
             _length = nlength;
         }
         else
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
 
     }
 
@@ -103,7 +103,7 @@ nothrow:
             back = val;
         }
         else
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
     }
 
     void popBack()
diff --git a/libphobos/libdruntime/core/internal/container/common.d b/libphobos/libdruntime/core/internal/container/common.d
index 582d63ba2a2..659b2b5e49c 100644
--- a/libphobos/libdruntime/core/internal/container/common.d
+++ b/libphobos/libdruntime/core/internal/container/common.d
@@ -18,7 +18,7 @@ void* xrealloc(void* ptr, size_t sz) nothrow @nogc
 
     if (!sz) { .free(ptr); return null; }
     if (auto nptr = .realloc(ptr, sz)) return nptr;
-    .free(ptr); onOutOfMemoryErrorNoGC();
+    .free(ptr); onOutOfMemoryError();
     assert(0);
 }
 
@@ -27,7 +27,7 @@ void* xmalloc(size_t sz) nothrow @nogc
     import core.exception;
     if (auto nptr = .malloc(sz))
         return nptr;
-    onOutOfMemoryErrorNoGC();
+    onOutOfMemoryError();
     assert(0);
 }
 
diff --git a/libphobos/libdruntime/core/internal/dassert.d b/libphobos/libdruntime/core/internal/dassert.d
index dbad0e6064f..76948c8bde8 100644
--- a/libphobos/libdruntime/core/internal/dassert.d
+++ b/libphobos/libdruntime/core/internal/dassert.d
@@ -180,6 +180,8 @@ private string miniFormat(V)(const scope ref V v)
     /// `shared` values are formatted as their base type
     static if (is(V == shared T, T))
     {
+        import core.atomic : atomicLoad;
+
         // Use atomics to avoid race conditions whenever possible
         static if (__traits(compiles, atomicLoad(v)))
         {
@@ -472,11 +474,6 @@ private bool[] calcFieldOverlap(const scope size_t[] offsets)
     return overlaps;
 }
 
-// This should be a local import in miniFormat but fails with a cyclic dependency error
-// core.thread.osthread -> core.time -> object -> core.internal.array.capacity
-// -> core.atomic -> core.thread -> core.thread.osthread
-import core.atomic : atomicLoad;
-
 /// Negates a comparison token, e.g. `==` is mapped to `!=`
 private string invertCompToken(scope string comp) pure nothrow @nogc @safe
 {
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index 6f194126e7e..ca4577f0195 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -94,8 +94,8 @@ private
 
         // Declared as an extern instead of importing core.exception
         // to avoid inlining - see https://issues.dlang.org/show_bug.cgi?id=13725.
-        void onInvalidMemoryOperationError(void* pretend_sideffect = null) @trusted pure nothrow @nogc;
-        void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc;
+        void onInvalidMemoryOperationError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted pure nothrow @nogc;
+        void onOutOfMemoryError(void* pretend_sideffect = null, string file = __FILE__, size_t line = __LINE__) @trusted nothrow @nogc;
 
         version (COLLECT_FORK)
             version (OSX)
@@ -141,7 +141,7 @@ private GC initialize()
 
     auto gc = cast(ConservativeGC) cstdlib.malloc(__traits(classInstanceSize, ConservativeGC));
     if (!gc)
-        onOutOfMemoryErrorNoGC();
+        onOutOfMemoryError();
 
     return emplace(gc);
 }
@@ -160,7 +160,7 @@ class ConservativeGC : GC
 
     Gcx *gcx;                   // implementation
 
-    static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.lengthy);
+    static gcLock = shared(AlignedSpinLock)(SpinLock.Contention.brief);
     static bool _inFinalizer;
     __gshared bool isPrecise = false;
 
@@ -188,7 +188,7 @@ class ConservativeGC : GC
 
         gcx = cast(Gcx*)cstdlib.calloc(1, Gcx.sizeof);
         if (!gcx)
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
         gcx.initialize();
 
         if (config.initReserve)
@@ -509,7 +509,7 @@ class ConservativeGC : GC
 
         auto p = gcx.alloc(size + SENTINEL_EXTRA, alloc_size, bits, ti);
         if (!p)
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
 
         debug (SENTINEL)
         {
@@ -1968,7 +1968,7 @@ struct Gcx
             // tryAlloc will succeed if a new pool was allocated above, if it fails allocate a new pool now
             if (!tryAlloc() && (!newPool(1, false) || !tryAlloc()))
                 // out of luck or memory
-                onOutOfMemoryErrorNoGC();
+                onOutOfMemoryError();
         }
         assert(p !is null);
     L_hasBin:
@@ -2008,7 +2008,7 @@ struct Gcx
         size_t pn;
         immutable npages = LargeObjectPool.numPages(size);
         if (npages == size_t.max)
-            onOutOfMemoryErrorNoGC(); // size just below size_t.max requested
+            onOutOfMemoryError(); // size just below size_t.max requested
 
         bool tryAlloc() nothrow
         {
@@ -2248,7 +2248,7 @@ struct Gcx
             enum initSize = 64 * 1024; // Windows VirtualAlloc granularity
             immutable ncap = _cap ? 2 * _cap : initSize / RANGE.sizeof;
             auto p = cast(RANGE*)os_mem_map(ncap * RANGE.sizeof);
-            if (p is null) onOutOfMemoryErrorNoGC();
+            if (p is null) onOutOfMemoryError();
             debug (VALGRIND) makeMemUndefined(p[0..ncap]);
             if (_p !is null)
             {
@@ -3394,7 +3394,7 @@ Lmark:
 
         scanThreadData = cast(ScanThreadData*) cstdlib.calloc(numScanThreads, ScanThreadData.sizeof);
         if (!scanThreadData)
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
 
         evStart.initialize(false, false);
         evDone.initialize(false, false);
@@ -3610,7 +3610,7 @@ struct Pool
             {
                 rtinfo = cast(immutable(size_t)**)cstdlib.malloc(npages * (size_t*).sizeof);
                 if (!rtinfo)
-                    onOutOfMemoryErrorNoGC();
+                    onOutOfMemoryError();
                 memset(rtinfo, 0, npages * (size_t*).sizeof);
             }
             else
@@ -3633,13 +3633,13 @@ struct Pool
 
         pagetable = cast(Bins*)cstdlib.malloc(npages * Bins.sizeof);
         if (!pagetable)
-            onOutOfMemoryErrorNoGC();
+            onOutOfMemoryError();
 
         if (npages > 0)
         {
             bPageOffsets = cast(uint*)cstdlib.malloc(npages * uint.sizeof);
             if (!bPageOffsets)
-                onOutOfMemoryErrorNoGC();
+                onOutOfMemoryError();
 
             if (isLargeObject)
             {
@@ -4643,14 +4643,14 @@ debug (LOGGING)
                 {
                     data = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
                     if (!data && allocdim)
-                        onOutOfMemoryErrorNoGC();
+                        onOutOfMemoryError();
                 }
                 else
                 {   Log *newdata;
 
                     newdata = cast(Log*)cstdlib.malloc(allocdim * Log.sizeof);
                     if (!newdata && allocdim)
-                        onOutOfMemoryErrorNoGC();
+                        onOutOfMemoryError();
                     memcpy(newdata, data, dim * Log.sizeof);
                     cstdlib.free(data);
                     data = newdata;
@@ -4989,8 +4989,8 @@ version (D_LP64) unittest
         // only run if the system has enough physical memory
         size_t sz = 2L^^32;
         //import core.stdc.stdio;
-        //printf("availphys = %lld", os_physical_mem());
-        if (os_physical_mem() > sz)
+        //printf("availphys = %lld", os_physical_mem(true));
+        if (os_physical_mem(true) > sz)
         {
             import core.memory;
             GC.collect();
diff --git a/libphobos/libdruntime/core/internal/gc/os.d b/libphobos/libdruntime/core/internal/gc/os.d
index 38b60cbbcc4..0db1753575b 100644
--- a/libphobos/libdruntime/core/internal/gc/os.d
+++ b/libphobos/libdruntime/core/internal/gc/os.d
@@ -254,23 +254,26 @@ bool isLowOnMem(size_t mapped) nothrow @nogc
 /**
    Get the size of available physical memory
 
+   Params:
+       avail = if supported on the current platform, return the currently unused memory
+               rather than the installed physical memory
    Returns:
        size of installed physical RAM
 */
 version (Windows)
 {
-    ulong os_physical_mem() nothrow @nogc
+    ulong os_physical_mem(bool avail) nothrow @nogc
     {
         import core.sys.windows.winbase : GlobalMemoryStatus, MEMORYSTATUS;
         MEMORYSTATUS stat;
         GlobalMemoryStatus(&stat);
-        return stat.dwTotalPhys; // limited to 4GB for Win32
+        return avail ? stat.dwAvailPhys : stat.dwTotalPhys; // limited to 4GB for Win32
     }
 }
 else version (Darwin)
 {
     extern (C) int sysctl(const int* name, uint namelen, void* oldp, size_t* oldlenp, const void* newp, size_t newlen) @nogc nothrow;
-    ulong os_physical_mem() nothrow @nogc
+    ulong os_physical_mem(bool avail) nothrow @nogc
     {
         enum
         {
@@ -287,11 +290,15 @@ else version (Darwin)
 }
 else version (Posix)
 {
-    ulong os_physical_mem() nothrow @nogc
+    ulong os_physical_mem(bool avail) nothrow @nogc
     {
-        import core.sys.posix.unistd : sysconf, _SC_PAGESIZE, _SC_PHYS_PAGES;
+        import core.sys.posix.unistd;
         const pageSize = sysconf(_SC_PAGESIZE);
-        const pages = sysconf(_SC_PHYS_PAGES);
+        static if (__traits(compiles, _SC_AVPHYS_PAGES)) // not available on all platforms
+            const sc = avail ? _SC_AVPHYS_PAGES : _SC_PHYS_PAGES;
+        else
+            const sc = _SC_PHYS_PAGES;
+        const pages = sysconf(sc);
         return pageSize * pages;
     }
 }
diff --git a/libphobos/libdruntime/core/internal/spinlock.d b/libphobos/libdruntime/core/internal/spinlock.d
index 36d806ad014..b0ea8f6c902 100644
--- a/libphobos/libdruntime/core/internal/spinlock.d
+++ b/libphobos/libdruntime/core/internal/spinlock.d
@@ -53,9 +53,9 @@ shared struct SpinLock
         import core.time;
         if (k < pauseThresh)
             return core.atomic.pause();
-        else if (k < 32)
+        else // if (k < 32)
             return Thread.yield();
-        Thread.sleep(1.msecs);
+        // Thread.sleep(1.msecs);
     }
 
 private:
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index 4f44b604c45..f2a48f9a3ae 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -266,8 +266,8 @@ extern(C):
 
     /**
      * Enables automatic garbage collection behavior if collections have
-     * previously been suspended by a call to disable.  This function is
-     * reentrant, and must be called once for every call to disable before
+     * previously been suspended by a call to `GC.disable()`.  This function is
+     * reentrant, and must be called once for every call to `GC.disable()` before
      * automatic collections are enabled.
      */
     pragma(mangle, "gc_enable") static void enable() @safe nothrow pure;
@@ -278,7 +278,12 @@ extern(C):
      * process footprint.  Collections may continue to occur in instances
      * where the implementation deems necessary for correct program behavior,
      * such as during an out of memory condition.  This function is reentrant,
-     * but enable must be called once for each call to disable.
+     * but `GC.enable()` must be called once for each call to `GC.disable()`.
+     * Unlike the
+     * $(LINK2 https://dlang.org/spec/function.html#nogc-functions, `@nogc` attribute),
+     * `GC.disable()` halts
+     * collections across all threads, yet still allows GC allocations.
+     * Disabling collections eliminates GC pauses.
      */
     pragma(mangle, "gc_disable") static void disable() @safe nothrow pure;
 
diff --git a/libphobos/libdruntime/core/stdc/assert_.d b/libphobos/libdruntime/core/stdc/assert_.d
index d6cb8a608a0..c6d9d9f6cc2 100644
--- a/libphobos/libdruntime/core/stdc/assert_.d
+++ b/libphobos/libdruntime/core/stdc/assert_.d
@@ -113,6 +113,15 @@ else version (CRuntime_Musl)
      */
     noreturn __assert_fail(const(char)* exp, const(char)* file, uint line, const(char)* func);
 }
+else version (CRuntime_Newlib)
+{
+    /***
+     * Assert failure function in the Newlib library.
+     */
+    noreturn __assert(const(char)* file, int line, const(char)* exp);
+    ///
+    noreturn __assert_func(const(char)* file, int line, const(char)* func, const(char)* exp);
+}
 else version (CRuntime_UClibc)
 {
     noreturn __assert(const(char)* exp, const(char)* file, uint line, const(char)* func);
diff --git a/libphobos/libdruntime/core/stdc/errno.d b/libphobos/libdruntime/core/stdc/errno.d
index e503dd96195..ddec70f7af3 100644
--- a/libphobos/libdruntime/core/stdc/errno.d
+++ b/libphobos/libdruntime/core/stdc/errno.d
@@ -75,6 +75,14 @@ else version (CRuntime_Musl)
         alias errno = __errno_location;
     }
 }
+else version (CRuntime_Newlib)
+{
+    extern (C)
+    {
+        ref int __errno();
+        alias errno = __errno;
+    }
+}
 else version (OpenBSD)
 {
     // https://github.com/openbsd/src/blob/master/include/errno.h
@@ -164,7 +172,7 @@ else
 extern (C):
 
 
-version (Windows)
+version (CRuntime_DigitalMars)
 {
     enum EPERM              = 1;        /// Operation not permitted
     enum ENOENT             = 2;        /// No such file or directory
@@ -250,6 +258,230 @@ version (Windows)
     enum ETXTBSY            = 139;
     enum EWOULDBLOCK        = 140;
 }
+else version (CRuntime_Microsoft)
+{
+    enum EPERM              = 1;        /// Operation not permitted
+    enum ENOENT             = 2;        /// No such file or directory
+    enum ESRCH              = 3;        /// No such process
+    enum EINTR              = 4;        /// Interrupted system call
+    enum EIO                = 5;        /// I/O error
+    enum ENXIO              = 6;        /// No such device or address
+    enum E2BIG              = 7;        /// Argument list too long
+    enum ENOEXEC            = 8;        /// Exec format error
+    enum EBADF              = 9;        /// Bad file number
+    enum ECHILD             = 10;       /// No child processes
+    enum EAGAIN             = 11;       /// Try again
+    enum ENOMEM             = 12;       /// Out of memory
+    enum EACCES             = 13;       /// Permission denied
+    enum EFAULT             = 14;       /// Bad address
+    enum EBUSY              = 16;       /// Device or resource busy
+    enum EEXIST             = 17;       /// File exists
+    enum EXDEV              = 18;       /// Cross-device link
+    enum ENODEV             = 19;       /// No such device
+    enum ENOTDIR            = 20;       /// Not a directory
+    enum EISDIR             = 21;       /// Is a directory
+    enum EINVAL             = 22;       /// Invalid argument
+    enum ENFILE             = 23;       /// File table overflow
+    enum EMFILE             = 24;       /// Too many open files
+    enum ENOTTY             = 25;       /// Not a typewriter
+    enum EFBIG              = 27;       /// File too large
+    enum ENOSPC             = 28;       /// No space left on device
+    enum ESPIPE             = 29;       /// Illegal seek
+    enum EROFS              = 30;       /// Read-only file system
+    enum EMLINK             = 31;       /// Too many links
+    enum EPIPE              = 32;       /// Broken pipe
+    enum EDOM               = 33;       /// Math argument out of domain of func
+    enum ERANGE             = 34;       /// Math result not representable
+    enum EDEADLK            = 36;       /// Resource deadlock would occur
+    enum ENAMETOOLONG       = 38;       /// File name too long
+    enum ENOLCK             = 39;       /// No record locks available
+    enum ENOSYS             = 40;       /// Function not implemented
+    enum ENOTEMPTY          = 41;       /// Directory not empty
+    enum EILSEQ             = 42;       /// Illegal byte sequence
+    enum EDEADLOCK          = EDEADLK;  /// Resource deadlock would occur
+
+    // POSIX compatibility
+    // See_Also: https://docs.microsoft.com/en-us/cpp/c-runtime-library/errno-constants
+    enum EADDRINUSE         = 100;
+    enum EADDRNOTAVAIL      = 101;
+    enum EAFNOSUPPORT       = 102;
+    enum EALREADY           = 103;
+    enum EBADMSG            = 104;
+    enum ECANCELED          = 105;
+    enum ECONNABORTED       = 106;
+    enum ECONNREFUSED       = 107;
+    enum ECONNRESET         = 108;
+    enum EDESTADDRREQ       = 109;
+    enum EHOSTUNREACH       = 110;
+    enum EIDRM              = 111;
+    enum EINPROGRESS        = 112;
+    enum EISCONN            = 113;
+    enum ELOOP              = 114;
+    enum EMSGSIZE           = 115;
+    enum ENETDOWN           = 116;
+    enum ENETRESET          = 117;
+    enum ENETUNREACH        = 118;
+    enum ENOBUFS            = 119;
+    enum ENODATA            = 120;
+    enum ENOLINK            = 121;
+    enum ENOMSG             = 122;
+    enum ENOPROTOOPT        = 123;
+    enum ENOSR              = 124;
+    enum ENOSTR             = 125;
+    enum ENOTCONN           = 126;
+    enum ENOTRECOVERABLE    = 127;
+    enum ENOTSOCK           = 128;
+    enum ENOTSUP            = 129;
+    enum EOPNOTSUPP         = 130;
+    enum EOTHER             = 131;
+    enum EOVERFLOW          = 132;
+    enum EOWNERDEAD         = 133;
+    enum EPROTO             = 134;
+    enum EPROTONOSUPPORT    = 135;
+    enum EPROTOTYPE         = 136;
+    enum ETIME              = 137;
+    enum ETIMEDOUT          = 138;
+    enum ETXTBSY            = 139;
+    enum EWOULDBLOCK        = 140;
+}
+else version (CRuntime_Newlib)
+{
+    enum EPERM = 1;
+    enum ENOENT = 2;
+    enum ESRCH = 3;
+    enum EINTR = 4;
+    enum EIO = 5;
+    enum ENXIO = 6;
+    enum E2BIG = 7;
+    enum ENOEXEC = 8;
+    enum EBADF = 9;
+    enum ECHILD = 10;
+    enum EAGAIN = 11;
+    enum ENOMEM = 12;
+    enum EACCES = 13;
+    enum EFAULT = 14;
+    enum EBUSY = 16;
+    enum EEXIST = 17;
+    enum EXDEV = 18;
+    enum ENODEV = 19;
+    enum ENOTDIR = 20;
+    enum EISDIR = 21;
+    enum EINVAL = 22;
+    enum ENFILE = 23;
+    enum EMFILE = 24;
+    enum ENOTTY = 25;
+    enum ETXTBSY = 26;
+    enum EFBIG = 27;
+    enum ENOSPC = 28;
+    enum ESPIPE = 29;
+    enum EROFS = 30;
+    enum EMLINK = 31;
+    enum EPIPE = 32;
+    enum EDOM = 33;
+    enum ERANGE = 34;
+    enum ENOMSG = 35;
+    enum EIDRM = 36;
+    enum EDEADLK = 45;
+    enum ENOLCK = 46;
+    enum ENOSTR = 60;
+    enum ENODATA = 61;
+    enum ETIME = 62;
+    enum ENOSR = 63;
+    enum ENOLINK = 67;
+    enum EPROTO = 71;
+    enum EMULTIHOP = 74;
+    enum EBADMSG = 77;
+    enum EFTYPE = 79;
+    enum ENOSYS = 88;
+    enum ENOTEMPTY = 90;
+    enum ENAMETOOLONG = 91;
+    enum ELOOP = 92;
+    enum EOPNOTSUPP = 95;
+    enum EPFNOSUPPORT = 96;
+    enum ECONNRESET = 104;
+    enum ENOBUFS = 105;
+    enum EAFNOSUPPORT = 106;
+    enum EPROTOTYPE = 107;
+    enum ENOTSOCK = 108;
+    enum ENOPROTOOPT = 109;
+    enum ECONNREFUSED = 111;
+    enum EADDRINUSE = 112;
+    enum ECONNABORTED = 113;
+    enum ENETUNREACH = 114;
+    enum ENETDOWN = 115;
+    enum ETIMEDOUT = 116;
+    enum EHOSTDOWN = 117;
+    enum EHOSTUNREACH = 118;
+    enum EINPROGRESS = 119;
+    enum EALREADY = 120;
+    enum EDESTADDRREQ = 121;
+    enum EMSGSIZE = 122;
+    enum EPROTONOSUPPORT = 123;
+    enum EADDRNOTAVAIL = 125;
+    enum ENETRESET = 126;
+    enum EISCONN = 127;
+    enum ENOTCONN = 128;
+    enum ETOOMANYREFS = 129;
+    enum EDQUOT = 132;
+    enum ESTALE = 133;
+    enum ENOTSUP = 134;
+    enum EILSEQ = 138;
+    enum EOVERFLOW = 139;
+    enum ECANCELED = 140;
+    enum ENOTRECOVERABLE = 141;
+    enum EOWNERDEAD = 142;
+
+    enum EWOULDBLOCK = EAGAIN;
+
+    enum __ELASTERROR = 2000;
+
+    // Linux errno extensions
+    version (Cygwin)
+    {
+        enum ENOTBLK = 15;
+        enum ECHRNG = 37;
+        enum EL2NSYNC = 38;
+        enum EL3HLT = 39;
+        enum EL3RST = 40;
+        enum ELNRNG = 41;
+        enum EUNATCH = 42;
+        enum ENOCSI = 43;
+        enum EL2HLT = 44;
+        enum EBADE = 50;
+        enum EBADR = 51;
+        enum EXFULL = 52;
+        enum ENOANO = 53;
+        enum EBADRQC = 54;
+        enum EBADSLT = 55;
+        enum EDEADLOCK = 56;
+        enum EBFONT = 57;
+        enum ENONET = 64;
+        enum ENOPKG = 65;
+        enum EREMOTE = 66;
+        enum EADV = 68;
+        enum ESRMNT = 69;
+        enum ECOMM = 70;
+        enum ELBIN = 75;
+        enum EDOTDOT = 76;
+        enum ENOTUNIQ = 80;
+        enum EBADFD = 81;
+        enum EREMCHG = 82;
+        enum ELIBACC = 83;
+        enum ELIBBAD = 84;
+        enum ELIBSCN = 85;
+        enum ELIBMAX = 86;
+        enum ELIBEXEC = 87;
+        enum ENMFILE = 89;
+        enum ESHUTDOWN = 110;
+        enum ESOCKTNOSUPPORT = 124;
+        enum EPROCLIM = 130;
+        enum EUSERS = 131;
+        enum ENOMEDIUM = 135;
+        enum ENOSHARE = 136;
+        enum ECASECLASH = 137;
+        enum ESTRPIPE = 143;
+    }
+}
 else version (linux)
 {
     enum EPERM              = 1;  ///
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index 0051ecdb7c9..a7364c0a211 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -448,6 +448,49 @@ else version (CRuntime_Musl)
         static assert(false, "Architecture not supported.");
     }
 }
+else version (CRuntime_Newlib)
+{
+    version (AArch64)
+    {
+        alias fenv_t = ulong;
+        alias fexcept_t = ulong;
+    }
+    else version (RISCV_Any)
+    {
+        alias fenv_t = size_t;
+        alias fexcept_t = size_t;
+    }
+    else version (X86_Any)
+    {
+        struct fenv_t
+        {
+            uint _fpu_cw;
+            uint _fpu_sw;
+            uint _fpu_tagw;
+            uint _fpu_ipoff;
+            uint _fpu_ipsel;
+            uint _fpu_opoff;
+            uint _fpu_opsel;
+            uint _sse_mxcsr;
+        }
+        alias fexcept_t = uint;
+    }
+    else version (SPARC64)
+    {
+        alias fenv_t = ulong;
+        alias fexcept_t = ulong;
+    }
+    else version (SPARC)
+    {
+        alias fenv_t = uint;
+        alias fexcept_t = uint;
+    }
+    else
+    {
+        alias fenv_t = int;
+        alias fexcept_t = int;
+    }
+}
 else version (CRuntime_UClibc)
 {
     version (X86)
diff --git a/libphobos/libdruntime/core/stdc/locale.d b/libphobos/libdruntime/core/stdc/locale.d
index 4b8d5c82e02..357d75e9589 100644
--- a/libphobos/libdruntime/core/stdc/locale.d
+++ b/libphobos/libdruntime/core/stdc/locale.d
@@ -252,6 +252,23 @@ else version (CRuntime_Musl)
     ///
     enum LC_ALL            = 6;
 }
+else version (CRuntime_Newlib)
+{
+    ///
+    enum LC_ALL            = 0;
+    ///
+    enum LC_COLLATE        = 1;
+    ///
+    enum LC_CTYPE          = 2;
+    ///
+    enum LC_MONETARY       = 3;
+    ///
+    enum LC_NUMERIC        = 4;
+    ///
+    enum LC_TIME           = 5;
+    ///
+    enum LC_MESSAGES       = 6;
+}
 else version (CRuntime_UClibc)
 {
     ///
diff --git a/libphobos/libdruntime/core/stdc/stdio.d b/libphobos/libdruntime/core/stdc/stdio.d
index ee37da1a5dd..1fc046163ee 100644
--- a/libphobos/libdruntime/core/stdc/stdio.d
+++ b/libphobos/libdruntime/core/stdc/stdio.d
@@ -328,6 +328,30 @@ else version (CRuntime_Bionic)
         int _size;
     }
 }
+else version (CRuntime_Newlib)
+{
+    enum
+    {
+        ///
+        BUFSIZ       = 1024,
+        ///
+        EOF          = -1,
+        ///
+        FOPEN_MAX    = 20,
+        ///
+        FILENAME_MAX = 1024,
+        ///
+        TMP_MAX      = 26,
+        ///
+        L_tmpnam     = 1024
+    }
+
+    struct __sbuf
+    {
+        ubyte* _base;
+        int _size;
+    }
+}
 else version (CRuntime_UClibc)
 {
     enum
@@ -769,6 +793,57 @@ else version (CRuntime_Bionic)
     ///
     alias shared(__sFILE) FILE;
 }
+else version (CRuntime_Newlib)
+{
+    import core.sys.posix.sys.types : ssize_t;
+    import core.stdc.wchar_ : mbstate_t;
+
+    ///
+    alias fpos_t = c_long;
+
+    ///
+    struct __sFILE
+    {
+        ubyte* _p;
+        int _r;
+        int _w;
+        short _flags;
+        short _file;
+        __sbuf _bf;
+        int _lbfsize;
+
+        void* _data;
+        void* _cookie;
+
+        ssize_t function(void*, void*, scope char*, size_t) _read;
+        ssize_t function(void*, void*, scope const char*, size_t) _write;
+        fpos_t function(void*, void*, fpos_t, int) _seek;
+        int function(void*, void*) _close;
+
+        __sbuf _ub;
+        ubyte* _up;
+        int _ur;
+
+        ubyte[3] _ubuf;
+        ubyte[1] _nbuf;
+
+        __sbuf _lb;
+
+        int _blksize;
+        int _flags2;
+
+        long _offset;
+        void* _unused;
+
+        void* _lock;
+        mbstate_t _mbstate;
+    }
+
+    ///
+    alias __sFILE _iobuf; // needed for phobos
+    ///
+    alias shared(__sFILE) FILE;
+}
 else version (CRuntime_UClibc)
 {
     import core.stdc.wchar_ : mbstate_t;
@@ -1137,6 +1212,40 @@ else version (CRuntime_Musl)
         _IONBF = 2,
     }
 }
+else version (CRuntime_Newlib)
+{
+    enum
+    {
+        ///
+        _IOFBF = 0,
+        ///
+        _IOLBF = 1,
+        ///
+        _IONBF = 2,
+    }
+
+    private
+    {
+        shared struct _reent
+        {
+            int _errno;
+            __sFILE* _stdin;
+            __sFILE* _stdout;
+            __sFILE* _stderr;
+        }
+        _reent* __getreent();
+    }
+
+    pragma(inline, true)
+    {
+        ///
+        @property auto stdin()() { return __getreent()._stdin; }
+        ///
+        @property auto stdout()() { return __getreent()._stdout; }
+        ///
+        @property auto stderr()() { return __getreent()._stderr; }
+    }
+}
 else version (CRuntime_UClibc)
 {
     enum
@@ -1869,6 +1978,47 @@ else version (CRuntime_Musl)
     pragma(printf)
     int vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg);
 }
+else version (CRuntime_Newlib)
+{
+  // No unsafe pointer manipulation.
+  @trusted
+  {
+    ///
+    void rewind(FILE* stream);
+    ///
+    pure void clearerr(FILE* stream);
+    ///
+    pure int  feof(FILE* stream);
+    ///
+    pure int  ferror(FILE* stream);
+    ///
+    int  fileno(FILE *);
+  }
+
+    ///
+    pragma(printf)
+    int  snprintf(scope char* s, size_t n, scope const char* format, scope const ...);
+    ///
+    pragma(printf)
+    int  vsnprintf(scope char* s, size_t n, scope const char* format, va_list arg);
+
+    //
+    // Gnu under-the-hood C I/O functions. Uses _iobuf* for the unshared
+    // version of FILE*, usable when the FILE is locked.
+    // See http://gnu.org/software/libc/manual/html_node/I_002fO-on-Streams.html
+    //
+    import core.stdc.wchar_ : wint_t;
+    import core.stdc.stddef : wchar_t;
+
+    ///
+    int fputc_unlocked(int c, _iobuf* stream);
+    ///
+    int fgetc_unlocked(_iobuf* stream);
+    ///
+    wint_t fputwc_unlocked(wchar_t wc, _iobuf* stream);
+    ///
+    wint_t fgetwc_unlocked(_iobuf* stream);
+}
 else version (CRuntime_UClibc)
 {
   // No unsafe pointer manipulation.
diff --git a/libphobos/libdruntime/core/stdc/stdlib.d b/libphobos/libdruntime/core/stdc/stdlib.d
index 0b42de8ec3b..bd5fc2b15ea 100644
--- a/libphobos/libdruntime/core/stdc/stdlib.d
+++ b/libphobos/libdruntime/core/stdc/stdlib.d
@@ -28,6 +28,8 @@ else version (WatchOS)
 
 version (CRuntime_Glibc)
     version = AlignedAllocSupported;
+else version (CRuntime_Newlib)
+    version = AlignedAllocSupported;
 else {}
 
 extern (C):
@@ -97,6 +99,7 @@ else version (DragonFlyBSD) enum RAND_MAX = 0x7fffffff;
 else version (Solaris) enum RAND_MAX = 0x7fff;
 else version (CRuntime_Bionic) enum RAND_MAX = 0x7fffffff;
 else version (CRuntime_Musl) enum RAND_MAX = 0x7fffffff;
+else version (CRuntime_Newlib) enum RAND_MAX = 0x7fffffff;
 else version (CRuntime_UClibc) enum RAND_MAX = 0x7fffffff;
 else version (WASI) enum RAND_MAX = 0x7fffffff;
 else static assert( false, "Unsupported platform" );
diff --git a/libphobos/libdruntime/core/stdc/string.d b/libphobos/libdruntime/core/stdc/string.d
index 3591a6d2d77..b9e3bb7568c 100644
--- a/libphobos/libdruntime/core/stdc/string.d
+++ b/libphobos/libdruntime/core/stdc/string.d
@@ -72,8 +72,15 @@ version (ReturnStrerrorR)
     const(char)* strerror_r(int errnum, return scope char* buf, size_t buflen);
 }
 // This one is
+else version (CRuntime_Newlib)
+{
+    ///
+    pragma(mangle, "__xpg_strerror_r")
+    int strerror_r(int errnum, scope char* buf, size_t buflen);
+}
 else
 {
+    ///
     int strerror_r(int errnum, scope char* buf, size_t buflen);
 }
 ///
diff --git a/libphobos/libdruntime/core/stdc/wchar_.d b/libphobos/libdruntime/core/stdc/wchar_.d
index 2d01e2634dc..6ed2dfe8318 100644
--- a/libphobos/libdruntime/core/stdc/wchar_.d
+++ b/libphobos/libdruntime/core/stdc/wchar_.d
@@ -106,6 +106,20 @@ else version (Solaris)
     ///
     alias mbstate_t = __mbstate_t;
 }
+else version (CRuntime_Newlib)
+{
+    ///
+    struct mbstate_t
+    {
+        int __count;
+        union ___value
+        {
+            wint_t __wch = 0;
+            char[4] __wchb;
+        }
+        ___value __value;
+    }
+}
 else version (CRuntime_UClibc)
 {
     ///
diff --git a/libphobos/libdruntime/core/sys/windows/basetsd.d b/libphobos/libdruntime/core/sys/windows/basetsd.d
index e70dbdc6c22..1e5a45427c7 100644
--- a/libphobos/libdruntime/core/sys/windows/basetsd.d
+++ b/libphobos/libdruntime/core/sys/windows/basetsd.d
@@ -15,9 +15,6 @@ version (Windows):
 // import.
 alias HANDLE = void*;
 
-package template DECLARE_HANDLE(string name, base = HANDLE) {
-    mixin ("alias " ~ base.stringof ~ " " ~ name ~ ";");
-}
 alias HANDLE* PHANDLE, LPHANDLE;
 
 // helper for aligned structs
diff --git a/libphobos/libdruntime/core/sys/windows/commctrl.d b/libphobos/libdruntime/core/sys/windows/commctrl.d
index dabee5672b9..fe4ebbc75d8 100644
--- a/libphobos/libdruntime/core/sys/windows/commctrl.d
+++ b/libphobos/libdruntime/core/sys/windows/commctrl.d
@@ -1740,8 +1740,8 @@ enum {
     I_CHILDRENCALLBACK = -1
 }
 
-mixin DECLARE_HANDLE!("HTREEITEM");
-mixin DECLARE_HANDLE!("HIMAGELIST");
+alias HTREEITEM = HANDLE;
+alias HIMAGELIST = HANDLE;
 
 version (Win64)
 {
@@ -4482,8 +4482,8 @@ static if (_WIN32_IE >= 0x400) {
     alias RBHITTESTINFO* LPRBHITTESTINFO;
 }
 
-mixin DECLARE_HANDLE!("HDSA");
-mixin DECLARE_HANDLE!("HDPA");
+alias HDSA = HANDLE;
+alias HDPA = HANDLE;
 
 version (Unicode) {
     alias HDITEMW HDITEM;
diff --git a/libphobos/libdruntime/core/sys/windows/ddeml.d b/libphobos/libdruntime/core/sys/windows/ddeml.d
index 00bad1d300d..2e8e3ee25d6 100644
--- a/libphobos/libdruntime/core/sys/windows/ddeml.d
+++ b/libphobos/libdruntime/core/sys/windows/ddeml.d
@@ -15,10 +15,10 @@ pragma(lib, "user32");
 
 import core.sys.windows.basetsd, core.sys.windows.windef, core.sys.windows.winnt;
 
-mixin DECLARE_HANDLE!("HCONVLIST");
-mixin DECLARE_HANDLE!("HCONV");
-mixin DECLARE_HANDLE!("HSZ");
-mixin DECLARE_HANDLE!("HDDEDATA");
+alias HCONVLIST = HANDLE;
+alias HCONV = HANDLE;
+alias HSZ = HANDLE;
+alias HDDEDATA = HANDLE;
 
 enum : int {
     CP_WINANSI    = 1004,
diff --git a/libphobos/libdruntime/core/sys/windows/dll.d b/libphobos/libdruntime/core/sys/windows/dll.d
index 5b02fb55801..77141d5deb3 100644
--- a/libphobos/libdruntime/core/sys/windows/dll.d
+++ b/libphobos/libdruntime/core/sys/windows/dll.d
@@ -487,10 +487,20 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads,
         }, null );
 }
 
-/** same as above, but only usable if druntime is linked statically
+version (Shared) version (DigitalMars) private extern(C) extern __gshared void* __ImageBase;
+
+/** same as above, but checking for shared runtime
  */
+pragma(inline, false) // version (Shared) only set when compiling druntime
 bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true )
 {
+    version (Shared) version (DigitalMars)
+    {
+        // cannot declare rt_initSharedModule globally as it then conflicts with the definition in sections_win64.d
+        pragma(mangle, "rt_initSharedModule") extern(C) bool rt_initSharedModule( void* handle );
+        if ( hInstance != &__ImageBase )
+            return rt_initSharedModule( hInstance );
+    }
     version (Win64)
     {
         return dll_process_attach( hInstance, attach_threads,
@@ -506,8 +516,16 @@ bool dll_process_attach( HINSTANCE hInstance, bool attach_threads = true )
 /**
  * to be called from DllMain with reason DLL_PROCESS_DETACH
  */
+pragma(inline, false) // version (Shared) only set when compiling druntime
 void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true )
 {
+    version (Shared) version (DigitalMars)
+    {
+        // cannot declare rt_termSharedModule globally as it then conflicts with the definition in sections_win64.d
+        pragma(mangle, "rt_termSharedModule") extern(C) bool rt_termSharedModule( void* handle );
+        if ( hInstance != &__ImageBase )
+            return cast(void) rt_termSharedModule( hInstance );
+    }
     // notify core.thread.joinLowLevelThread that the DLL is about to be unloaded
     thread_DLLProcessDetaching = true;
 
@@ -531,6 +549,21 @@ void dll_process_detach( HINSTANCE hInstance, bool detach_threads = true )
     Runtime.terminate();
 }
 
+/*****************************
+* Check whether the D runtime is built as a DLL or linked statically
+*
+* Returns:
+*	true = DLL, false = static library
+*/
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool isSharedDRuntime()
+{
+    version (Shared)
+        return true;
+    else
+        return false;
+}
+
 /* Make sure that tlsCtorRun is itself a tls variable
  */
 static bool tlsCtorRun;
@@ -542,8 +575,15 @@ static ~this() { tlsCtorRun = false; }
  * Returns:
  *	true for success, false for failure
  */
-bool dll_thread_attach( bool attach_thread = true, bool initTls = true )
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool dll_thread_attach( bool attach_thread = true, bool initTls = true, HINSTANCE hInstance = null )
 {
+    version (Shared) version (DigitalMars)
+    {
+        if ( hInstance && hInstance != &__ImageBase )
+            return true;
+    }
+
     // if the OS has not prepared TLS for us, don't attach to the thread
     //  (happened when running under x64 OS)
     auto tid = GetCurrentThreadId();
@@ -565,8 +605,15 @@ bool dll_thread_attach( bool attach_thread = true, bool initTls = true )
  * Returns:
  *	true for success, false for failure
  */
-bool dll_thread_detach( bool detach_thread = true, bool exitTls = true )
+pragma(inline, false) // version (Shared) only set when compiling druntime
+bool dll_thread_detach( bool detach_thread = true, bool exitTls = true, HINSTANCE hInstance = null )
 {
+    version (Shared) version (DigitalMars)
+    {
+        if ( hInstance && hInstance != &__ImageBase )
+            return true;
+    }
+
     // if the OS has not prepared TLS for us, we did not attach to the thread
     if ( !GetTlsDataAddress( GetCurrentThreadId() ) )
          return false;
@@ -613,10 +660,10 @@ mixin template SimpleDllMain()
                 return true;
 
             case DLL_THREAD_ATTACH:
-                return dll_thread_attach( true, true );
+                return dll_thread_attach( true, true, hInstance );
 
             case DLL_THREAD_DETACH:
-                return dll_thread_detach( true, true );
+                return dll_thread_detach( true, true, hInstance );
         }
     }
 }
diff --git a/libphobos/libdruntime/core/sys/windows/httpext.d b/libphobos/libdruntime/core/sys/windows/httpext.d
index 6973879abf3..200b2843c4d 100644
--- a/libphobos/libdruntime/core/sys/windows/httpext.d
+++ b/libphobos/libdruntime/core/sys/windows/httpext.d
@@ -19,7 +19,7 @@ version (Windows):
        MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 */
 
-import core.sys.windows.basetsd /+: DECLARE_HANDLE, HANDLE+/;
+import core.sys.windows.basetsd /+: HANDLE+/;
 import core.sys.windows.windef /+: BOOL, CHAR, DWORD, LPBYTE, LPDWORD+/;
 import core.sys.windows.winnt /+: LPCSTR, LPSTR, LPVOID, PVOID, VOID+/;
 
@@ -47,7 +47,7 @@ enum {
     HSE_IO_SEND_HEADERS             = 0x00000008
 }
 
-mixin DECLARE_HANDLE!("HCONN");
+alias HCONN = HANDLE;
 
 struct HSE_VERSION_INFO {
     DWORD dwExtensionVersion;
diff --git a/libphobos/libdruntime/core/sys/windows/imagehlp.d b/libphobos/libdruntime/core/sys/windows/imagehlp.d
index 399c0b2b1af..68d88d78780 100644
--- a/libphobos/libdruntime/core/sys/windows/imagehlp.d
+++ b/libphobos/libdruntime/core/sys/windows/imagehlp.d
@@ -275,7 +275,7 @@ struct IMAGEHLP_DUPLICATE_SYMBOL {
 }
 alias IMAGEHLP_DUPLICATE_SYMBOL* PIMAGEHLP_DUPLICATE_SYMBOL;
 
-mixin DECLARE_HANDLE!("DIGEST_HANDLE");
+alias DIGEST_HANDLE = HANDLE;
 
 extern (Windows) {
     alias BOOL function(IMAGEHLP_STATUS_REASON, LPSTR, LPSTR, ULONG_PTR, ULONG_PTR)
diff --git a/libphobos/libdruntime/core/sys/windows/msacm.d b/libphobos/libdruntime/core/sys/windows/msacm.d
index 645e40d4ecb..df4d6c4fc92 100644
--- a/libphobos/libdruntime/core/sys/windows/msacm.d
+++ b/libphobos/libdruntime/core/sys/windows/msacm.d
@@ -14,8 +14,8 @@ version (ANSI) {} else version = Unicode;
 
 import core.sys.windows.basetsd, core.sys.windows.mmsystem, core.sys.windows.windef;
 
-mixin DECLARE_HANDLE!("HACMDRIVERID");
-mixin DECLARE_HANDLE!("HACMDRIVER");
+alias HACMDRIVERID = HANDLE;
+alias HACMDRIVER = HANDLE;
 alias HACMDRIVER* LPHACMDRIVER;
 
 enum size_t
diff --git a/libphobos/libdruntime/core/sys/windows/ntsecapi.d b/libphobos/libdruntime/core/sys/windows/ntsecapi.d
index fbc6b7f6b99..fa08a74ee5b 100644
--- a/libphobos/libdruntime/core/sys/windows/ntsecapi.d
+++ b/libphobos/libdruntime/core/sys/windows/ntsecapi.d
@@ -666,7 +666,7 @@ struct POLICY_DOMAIN_KERBEROS_TICKET_INFO {
 }
 alias POLICY_DOMAIN_KERBEROS_TICKET_INFO* PPOLICY_DOMAIN_KERBEROS_TICKET_INFO;
 
-mixin DECLARE_HANDLE!("LSA_HANDLE");
+alias LSA_HANDLE = HANDLE;
 alias LSA_HANDLE* PLSA_HANDLE;
 
 struct TRUSTED_DOMAIN_NAME_INFO {
diff --git a/libphobos/libdruntime/core/sys/windows/ole.d b/libphobos/libdruntime/core/sys/windows/ole.d
index a844124bdb7..b9e55a3b129 100644
--- a/libphobos/libdruntime/core/sys/windows/ole.d
+++ b/libphobos/libdruntime/core/sys/windows/ole.d
@@ -155,7 +155,7 @@ enum OLEOPT_UPDATE {
 // #endif
 }
 
-mixin DECLARE_HANDLE!("HOBJECT");
+alias HOBJECT = HANDLE;
 alias LONG_PTR LHSERVER, LHCLIENTDOC, LHSERVERDOC;
 
 struct OLEOBJECTVTBL {
diff --git a/libphobos/libdruntime/core/sys/windows/prsht.d b/libphobos/libdruntime/core/sys/windows/prsht.d
index 92596b5b548..053b1fa2ac9 100644
--- a/libphobos/libdruntime/core/sys/windows/prsht.d
+++ b/libphobos/libdruntime/core/sys/windows/prsht.d
@@ -247,7 +247,7 @@ struct PROPSHEETPAGEW {
 alias PROPSHEETPAGEW*        LPPROPSHEETPAGEW;
 alias const(PROPSHEETPAGEW)* LPCPROPSHEETPAGEW;
 
-mixin DECLARE_HANDLE!("HPROPSHEETPAGE");
+alias HPROPSHEETPAGE = HANDLE;
 
 struct PROPSHEETHEADERA {
     DWORD dwSize = PROPSHEETHEADERA.sizeof;
diff --git a/libphobos/libdruntime/core/sys/windows/rpcdce.d b/libphobos/libdruntime/core/sys/windows/rpcdce.d
index 4f3f3cc1f66..951480b955d 100644
--- a/libphobos/libdruntime/core/sys/windows/rpcdce.d
+++ b/libphobos/libdruntime/core/sys/windows/rpcdce.d
@@ -160,8 +160,8 @@ struct RPC_IF_ID_VECTOR {
     uint          Count;
     RPC_IF_ID*[1] IfId;
 }
-mixin DECLARE_HANDLE!("RPC_AUTH_IDENTITY_HANDLE");
-mixin DECLARE_HANDLE!("RPC_AUTHZ_HANDLE");
+alias RPC_AUTH_IDENTITY_HANDLE = HANDLE;
+alias RPC_AUTHZ_HANDLE = HANDLE;
 
 struct RPC_SECURITY_QOS {
     uint Version;
diff --git a/libphobos/libdruntime/core/sys/windows/rpcdcep.d b/libphobos/libdruntime/core/sys/windows/rpcdcep.d
index 71b82be7a7f..421c2752b1c 100644
--- a/libphobos/libdruntime/core/sys/windows/rpcdcep.d
+++ b/libphobos/libdruntime/core/sys/windows/rpcdcep.d
@@ -15,7 +15,7 @@ import core.sys.windows.basetyps;
 import core.sys.windows.w32api;
 import core.sys.windows.windef;
 
-mixin DECLARE_HANDLE!("I_RPC_HANDLE");
+alias I_RPC_HANDLE = HANDLE;
 alias long RPC_STATUS;
 
 enum RPC_NCA_FLAGS_DEFAULT=0;
diff --git a/libphobos/libdruntime/core/sys/windows/rpcnsi.d b/libphobos/libdruntime/core/sys/windows/rpcnsi.d
index 1294d0dc08c..60c7b0972af 100644
--- a/libphobos/libdruntime/core/sys/windows/rpcnsi.d
+++ b/libphobos/libdruntime/core/sys/windows/rpcnsi.d
@@ -18,7 +18,7 @@ import core.sys.windows.basetyps, core.sys.windows.rpcdcep, core.sys.windows.rpc
   core.sys.windows.w32api;
 import core.sys.windows.windef;  // for HANDLE
 
-mixin DECLARE_HANDLE!("RPC_NS_HANDLE");
+alias RPC_NS_HANDLE = HANDLE;
 
 enum RPC_C_NS_SYNTAX_DEFAULT=0;
 enum RPC_C_NS_SYNTAX_DCE=3;
diff --git a/libphobos/libdruntime/core/sys/windows/setupapi.d b/libphobos/libdruntime/core/sys/windows/setupapi.d
index 7a052cde2b4..da503864787 100644
--- a/libphobos/libdruntime/core/sys/windows/setupapi.d
+++ b/libphobos/libdruntime/core/sys/windows/setupapi.d
@@ -858,7 +858,7 @@ enum : DWORD {
 
 alias PVOID HINF;
 alias PVOID HDSKSPC;
-mixin DECLARE_HANDLE!("HDEVINFO");
+alias HDEVINFO = HANDLE;
 alias PVOID HSPFILEQ;
 alias PVOID HSPFILELOG;
 
diff --git a/libphobos/libdruntime/core/sys/windows/shellapi.d b/libphobos/libdruntime/core/sys/windows/shellapi.d
index fdd9938d908..2ddf680e1f0 100644
--- a/libphobos/libdruntime/core/sys/windows/shellapi.d
+++ b/libphobos/libdruntime/core/sys/windows/shellapi.d
@@ -188,7 +188,7 @@ enum SHERB_NOPROGRESSUI   = 2;
 enum SHERB_NOSOUND        = 4;
 
 alias WORD FILEOP_FLAGS, PRINTEROP_FLAGS;
-mixin DECLARE_HANDLE!("HDROP");
+alias HDROP = HANDLE;
 
 //align(2): // 1 in Win32, default in Win64
 
diff --git a/libphobos/libdruntime/core/sys/windows/shlwapi.d b/libphobos/libdruntime/core/sys/windows/shlwapi.d
index cfabbada223..3562003a41f 100644
--- a/libphobos/libdruntime/core/sys/windows/shlwapi.d
+++ b/libphobos/libdruntime/core/sys/windows/shlwapi.d
@@ -120,7 +120,7 @@ enum URLIS
     URLIS_HASQUERY
 }
 
-mixin DECLARE_HANDLE!("HUSKEY");
+alias HUSKEY = HANDLE;
 alias HUSKEY* PHUSKEY;
 
 extern (Windows)
diff --git a/libphobos/libdruntime/core/sys/windows/subauth.d b/libphobos/libdruntime/core/sys/windows/subauth.d
index a48fb9955c4..8240d9f4781 100644
--- a/libphobos/libdruntime/core/sys/windows/subauth.d
+++ b/libphobos/libdruntime/core/sys/windows/subauth.d
@@ -106,7 +106,7 @@ struct STRING {
 alias STRING* PSTRING;
 +/
 
-mixin DECLARE_HANDLE!("SAM_HANDLE");
+alias SAM_HANDLE = HANDLE;
 alias SAM_HANDLE* PSAM_HANDLE;
 
 struct OLD_LARGE_INTEGER {
diff --git a/libphobos/libdruntime/core/sys/windows/vfw.d b/libphobos/libdruntime/core/sys/windows/vfw.d
index e8ca74e888d..c0f22a9fb5b 100644
--- a/libphobos/libdruntime/core/sys/windows/vfw.d
+++ b/libphobos/libdruntime/core/sys/windows/vfw.d
@@ -678,7 +678,7 @@ extern (Windows) {
     void ICCompressorFree(PCOMPVARS pc);
 }
 
-mixin DECLARE_HANDLE!("HDRAWDIB");
+alias HDRAWDIB = HANDLE;
 
 enum {
     DDF_0001            = 0x0001,
diff --git a/libphobos/libdruntime/core/sys/windows/windef.d b/libphobos/libdruntime/core/sys/windows/windef.d
index 4e951f3ddac..105be44c5b6 100644
--- a/libphobos/libdruntime/core/sys/windows/windef.d
+++ b/libphobos/libdruntime/core/sys/windows/windef.d
@@ -74,43 +74,43 @@ alias const(void)* PCVOID, LPCVOID;
 alias UINT_PTR WPARAM;
 alias LONG_PTR LPARAM, LRESULT;
 
-mixin DECLARE_HANDLE!("HHOOK");
-mixin DECLARE_HANDLE!("HGLOBAL");
-mixin DECLARE_HANDLE!("HLOCAL");
-mixin DECLARE_HANDLE!("GLOBALHANDLE");
-mixin DECLARE_HANDLE!("LOCALHANDLE");
-mixin DECLARE_HANDLE!("HGDIOBJ");
-mixin DECLARE_HANDLE!("HACCEL");
-mixin DECLARE_HANDLE!("HBITMAP", HGDIOBJ);
-mixin DECLARE_HANDLE!("HBRUSH", HGDIOBJ);
-mixin DECLARE_HANDLE!("HCOLORSPACE");
-mixin DECLARE_HANDLE!("HDC");
-mixin DECLARE_HANDLE!("HGLRC");
-mixin DECLARE_HANDLE!("HDESK");
-mixin DECLARE_HANDLE!("HENHMETAFILE");
-mixin DECLARE_HANDLE!("HFONT", HGDIOBJ);
-mixin DECLARE_HANDLE!("HICON");
-mixin DECLARE_HANDLE!("HINSTANCE");
-mixin DECLARE_HANDLE!("HKEY");
-mixin DECLARE_HANDLE!("HMENU");
-mixin DECLARE_HANDLE!("HMETAFILE");
-mixin DECLARE_HANDLE!("HMODULE");
-mixin DECLARE_HANDLE!("HMONITOR");
-mixin DECLARE_HANDLE!("HPALETTE");
-mixin DECLARE_HANDLE!("HPEN", HGDIOBJ);
-mixin DECLARE_HANDLE!("HRGN", HGDIOBJ);
-mixin DECLARE_HANDLE!("HRSRC");
-mixin DECLARE_HANDLE!("HSTR");
-mixin DECLARE_HANDLE!("HTASK");
-mixin DECLARE_HANDLE!("HWND");
-mixin DECLARE_HANDLE!("HWINSTA");
-mixin DECLARE_HANDLE!("HKL");
-mixin DECLARE_HANDLE!("HCURSOR");
+alias HHOOK = HANDLE;
+alias HGLOBAL = HANDLE;
+alias HLOCAL = HANDLE;
+alias GLOBALHANDLE = HANDLE;
+alias LOCALHANDLE = HANDLE;
+alias HGDIOBJ = HANDLE;
+alias HACCEL = HANDLE;
+alias HBITMAP = HGDIOBJ;
+alias HBRUSH = HGDIOBJ;
+alias HCOLORSPACE = HANDLE;
+alias HDC = HANDLE;
+alias HGLRC = HANDLE;
+alias HDESK = HANDLE;
+alias HENHMETAFILE = HANDLE;
+alias HFONT = HGDIOBJ;
+alias HICON = HANDLE;
+alias HINSTANCE = HANDLE;
+alias HKEY = HANDLE;
+alias HMENU = HANDLE;
+alias HMETAFILE = HANDLE;
+alias HMODULE = HANDLE;
+alias HMONITOR = HANDLE;
+alias HPALETTE = HANDLE;
+alias HPEN = HGDIOBJ;
+alias HRGN = HGDIOBJ;
+alias HRSRC = HANDLE;
+alias HSTR = HANDLE;
+alias HTASK = HANDLE;
+alias HWND = HANDLE;
+alias HWINSTA = HANDLE;
+alias HKL = HANDLE;
+alias HCURSOR = HANDLE;
 alias HKEY* PHKEY;
 
 static if (_WIN32_WINNT >= 0x500) {
-    mixin DECLARE_HANDLE!("HTERMINAL");
-    mixin DECLARE_HANDLE!("HWINEVENTHOOK");
+    alias HTERMINAL = HANDLE;
+    alias HWINEVENTHOOK = HANDLE;
 }
 
 alias extern (Windows) INT_PTR function() nothrow FARPROC, NEARPROC, PROC;
diff --git a/libphobos/libdruntime/core/sys/windows/wininet.d b/libphobos/libdruntime/core/sys/windows/wininet.d
index 328af503a4c..790d4d01dcb 100644
--- a/libphobos/libdruntime/core/sys/windows/wininet.d
+++ b/libphobos/libdruntime/core/sys/windows/wininet.d
@@ -740,7 +740,8 @@ enum {
     INTERNET_CACHE_GROUP_REMOVE = 1
 }
 
-mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug
+alias HINTERNET = HANDLE;
+// mixin DECLARE_HANDLE!("HINTERNET"); // doesn't work - bug
 /*struct HINTERNET {
     HANDLE h;
     alias h this;
diff --git a/libphobos/libdruntime/core/sys/windows/winsvc.d b/libphobos/libdruntime/core/sys/windows/winsvc.d
index f7f2fa7d27d..e6418ac8ac6 100644
--- a/libphobos/libdruntime/core/sys/windows/winsvc.d
+++ b/libphobos/libdruntime/core/sys/windows/winsvc.d
@@ -184,10 +184,10 @@ struct SERVICE_TABLE_ENTRYW {
 }
 alias SERVICE_TABLE_ENTRYW* LPSERVICE_TABLE_ENTRYW;
 
-mixin DECLARE_HANDLE!("SC_HANDLE");
+alias SC_HANDLE = HANDLE;
 alias SC_HANDLE* LPSC_HANDLE;
 alias void* SC_LOCK;
-mixin DECLARE_HANDLE!("SERVICE_STATUS_HANDLE");
+alias SERVICE_STATUS_HANDLE = HANDLE;
 
 extern (Windows) {
     alias void function(DWORD) LPHANDLER_FUNCTION;
diff --git a/libphobos/libdruntime/core/sys/windows/winuser.d b/libphobos/libdruntime/core/sys/windows/winuser.d
index 829952dfdb5..469e68e6668 100644
--- a/libphobos/libdruntime/core/sys/windows/winuser.d
+++ b/libphobos/libdruntime/core/sys/windows/winuser.d
@@ -2495,8 +2495,8 @@ extern (Windows) nothrow {
     alias NAMEENUMPROCW WINSTAENUMPROCW;
 }
 
-mixin DECLARE_HANDLE!("HDWP");
-mixin DECLARE_HANDLE!("HDEVNOTIFY");
+alias HDWP = HANDLE;
+alias HDEVNOTIFY = HANDLE;
 
 struct MENUGETOBJECTINFO {
     DWORD dwFlags;
diff --git a/libphobos/libdruntime/core/sys/windows/wtypes.d b/libphobos/libdruntime/core/sys/windows/wtypes.d
index 0206839ebf2..881f05a650c 100644
--- a/libphobos/libdruntime/core/sys/windows/wtypes.d
+++ b/libphobos/libdruntime/core/sys/windows/wtypes.d
@@ -96,8 +96,8 @@ alias OLECHAR* BSTR;
 alias FLAGGED_WORD_BLOB* wireBSTR;
 alias BSTR* LPBSTR;
 //alias LONG SCODE; // also in winerror
-mixin DECLARE_HANDLE!("HCONTEXT");
-mixin DECLARE_HANDLE!("HMETAFILEPICT");
+alias HCONTEXT = HANDLE;
+alias HMETAFILEPICT = HANDLE;
 
 union CY {
     struct {
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index 1b39a27c102..710f4cc90d1 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -1646,10 +1646,10 @@ class TypeInfo_Class : TypeInfo
     string      name;           /// class name
     void*[]     vtbl;           /// virtual function pointer table
     Interface[] interfaces;     /// interfaces this class implements
-    TypeInfo_Class   base;           /// base class
+    TypeInfo_Class   base;      /// base class
     void*       destructor;
     void function(Object) classInvariant;
-    enum ClassFlags : uint
+    enum ClassFlags : ushort
     {
         isCOMclass = 0x1,
         noPointers = 0x2,
@@ -1660,11 +1660,14 @@ class TypeInfo_Class : TypeInfo
         isAbstract = 0x40,
         isCPPclass = 0x80,
         hasDtor = 0x100,
+        hasNameSig = 0x200,
     }
     ClassFlags m_flags;
-    void*       deallocator;
+    ushort     depth;           /// inheritance distance from Object
+    void*      deallocator;
     OffsetTypeInfo[] m_offTi;
     void function(Object) defaultConstructor;   // default Constructor
+    ulong[2] nameSig;            /// unique signature for `name`
 
     immutable(void)* m_RTInfo;        // data for precise GC
     override @property immutable(void)* rtInfo() const { return m_RTInfo; }
diff --git a/libphobos/libdruntime/rt/cast_.d b/libphobos/libdruntime/rt/cast_.d
index 925599e0159..44e0f7a9ccc 100644
--- a/libphobos/libdruntime/rt/cast_.d
+++ b/libphobos/libdruntime/rt/cast_.d
@@ -23,10 +23,12 @@ pure:
 // but we are trying to implement dynamic cast.
 extern (D) private bool areClassInfosEqual(scope const ClassInfo a, scope const ClassInfo b) @safe
 {
-    if (a is b)
-        return true;
-    // take care of potential duplicates across binaries
-    return a.name == b.name;
+    // same class if signatures match, works with potential duplicates across binaries
+    return a is b ||
+        (a.m_flags & TypeInfo_Class.ClassFlags.hasNameSig
+        ? (a.nameSig[0] == b.nameSig[0] &&
+           a.nameSig[1] == b.nameSig[1])  // new fast way
+        : (a is b || a.name == b.name));  // old slow way for temporary binary compatibility
 }
 
 /******************************************
@@ -58,7 +60,7 @@ Object _d_toObject(return scope void* p)
 }
 
 /*************************************
- * Attempts to cast Object o to class c.
+ * Attempts to cast interface Object o to class c.
  * Returns o if successful, null if not.
  */
 void* _d_interface_cast(void* p, ClassInfo c)
@@ -70,9 +72,26 @@ void* _d_interface_cast(void* p, ClassInfo c)
     Interface* pi = **cast(Interface***) p;
 
     debug(cast_) printf("\tpi.offset = %d\n", pi.offset);
-    return _d_dynamic_cast(cast(Object)(p - pi.offset), c);
+    Object o2 = cast(Object)(p - pi.offset);
+    void* res = null;
+    size_t offset = 0;
+    if (o2 && _d_isbaseof2(typeid(o2), c, offset))
+    {
+        debug(cast_) printf("\toffset = %d\n", offset);
+        res = cast(void*) o2 + offset;
+    }
+    debug(cast_) printf("\tresult = %p\n", res);
+    return res;
 }
 
+/*****
+ * Dynamic cast from a class object `o` to class or interface `c`, where `c` is a subtype of `o`.
+ * Params:
+ *      o = instance of class
+ *      c = a subclass of o
+ * Returns:
+ *      null if o is null or c is not a subclass of o. Otherwise, return o.
+ */
 void* _d_dynamic_cast(Object o, ClassInfo c)
 {
     debug(cast_) printf("_d_dynamic_cast(o = %p, c = '%.*s')\n", o, c.name);
@@ -88,6 +107,64 @@ void* _d_dynamic_cast(Object o, ClassInfo c)
     return res;
 }
 
+/*****
+ * Dynamic cast from a class object o to class c, where c is a subclass of o.
+ * Params:
+ *      o = instance of class
+ *      c = a subclass of o
+ * Returns:
+ *      null if o is null or c is not a subclass of o. Otherwise, return o.
+ */
+void* _d_class_cast(Object o, ClassInfo c)
+{
+    debug(cast_) printf("_d_cast_cast(o = %p, c = '%.*s', level %d)\n", o, c.name, level);
+
+    if (!o)
+        return null;
+
+    ClassInfo oc = typeid(o);
+    int delta = oc.depth;
+
+    if (delta && c.depth)
+    {
+        delta -= c.depth;
+        if (delta < 0)
+            return null;
+
+        while (delta--)
+            oc = oc.base;
+        if (areClassInfosEqual(oc, c))
+            return cast(void*)o;
+        return null;
+    }
+
+    // no depth data - support the old way
+    do
+    {
+        if (areClassInfosEqual(oc, c))
+            return cast(void*)o;
+        oc = oc.base;
+    } while (oc);
+    return null;
+}
+
+/**
+ * Dynamic cast `o` to final class `c` only one level down
+ * Params:
+ *      o = object that is instance of a class
+ *      c = class to cast it to
+ * Returns:
+ *      o if it succeeds, null if it fails
+ */
+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);
+    debug assert(cast(void*)p is cast(void*)_d_dynamic_cast(o, c));
+    return cast(void*)p;
+}
+
 int _d_isbaseof2(scope ClassInfo oc, scope const ClassInfo c, scope ref size_t offset) @safe
 {
     if (areClassInfosEqual(oc, c))
diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d
index 8a10aac8fcb..5ac053cef15 100644
--- a/libphobos/libdruntime/rt/dmain2.d
+++ b/libphobos/libdruntime/rt/dmain2.d
@@ -496,6 +496,13 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF
     {
         if (rt_init())
         {
+            version(Shared) version(CRuntime_Microsoft) version (DigitalMars)
+            {
+                auto exeHandle = handleForAddr(mainFunc);
+                if (exeHandle)
+                    if (!rt_initSharedModule(exeHandle))
+                        exeHandle = null;
+            }
             auto utResult = runModuleUnitTests();
             assert(utResult.passed <= utResult.executed);
             if (utResult.passed == utResult.executed)
@@ -521,6 +528,11 @@ private extern (C) int _d_run_main2(char[][] args, size_t totalArgsLength, MainF
                              cast(int)utResult.executed);
                 result = EXIT_FAILURE;
             }
+            version(Shared) version(CRuntime_Microsoft) version (DigitalMars)
+            {
+                if (exeHandle)
+                    rt_termSharedModule(exeHandle);
+            }
         }
         else
             result = EXIT_FAILURE;
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 103a93f5ad6..b29da3b4ce7 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-7a6e9568862f5a0d9eb34707d85dcf7ff889c26f
+e4d0dd5136be3c539a02cc2f1618cb989a685837
 
 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/bitmanip.d b/libphobos/src/std/bitmanip.d
index b84a6762d19..e9f61919b0d 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -279,10 +279,8 @@ See_Also: $(REF BitFlags, std,typecons)
 */
 string bitfields(T...)()
 {
-    import std.conv : to;
-
     static assert(T.length % 3 == 0,
-                  "Wrong number of arguments (" ~ to!string(T.length) ~ "): Must be a multiple of 3");
+                  "Wrong number of arguments (" ~ T.length.stringof ~ "): Must be a multiple of 3");
 
     static foreach (i, ARG; T)
     {
diff --git a/libphobos/src/std/complex.d b/libphobos/src/std/complex.d
index 347e351c26a..60746f98ef7 100644
--- a/libphobos/src/std/complex.d
+++ b/libphobos/src/std/complex.d
@@ -1892,7 +1892,7 @@ Complex!T pow(T)(const T x, Complex!T n) @trusted pure nothrow @nogc
 @safe pure nothrow @nogc unittest
 {
     import std.meta : AliasSeq;
-    import std.math : RealFormat, floatTraits;
+    import std.math.traits : floatTraits, RealFormat;
     static foreach (T; AliasSeq!(float, double, real))
     {{
          static if (floatTraits!T.realFormat == RealFormat.ibmExtended)
diff --git a/libphobos/src/std/conv.d b/libphobos/src/std/conv.d
index 23b33c4d78c..5d02df08bf9 100644
--- a/libphobos/src/std/conv.d
+++ b/libphobos/src/std/conv.d
@@ -1804,7 +1804,7 @@ if (!is(S : T) && isAssociativeArray!S &&
     }
     static void testFloatingToIntegral(Floating, Integral)()
     {
-        import std.math : floatTraits, RealFormat;
+        import std.math.traits : floatTraits, RealFormat;
 
         bool convFails(Source, Target, E)(Source src)
         {
@@ -3430,7 +3430,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
     Target result = cast(Target) (sign ? -ldval : ldval);
 
     // if overflow occurred
-    import std.math : isFinite;
+    import std.math.traits : isFinite;
     enforce(isFinite(result), new ConvException("Range error"));
 
     advanceSource();
@@ -3598,7 +3598,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
 @system unittest
 {
     // @system because strtod is not @safe.
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     static if (floatTraits!real.realFormat == RealFormat.ieeeDouble)
     {
@@ -3682,7 +3682,7 @@ if (isFloatingPoint!Target && !is(Target == enum) &&
 {
     import core.stdc.errno;
     import core.stdc.stdlib;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     errno = 0;  // In case it was set by another unittest in a different module.
     struct longdouble
diff --git a/libphobos/src/std/exception.d b/libphobos/src/std/exception.d
index 5c786859c8e..58a667c1d85 100644
--- a/libphobos/src/std/exception.d
+++ b/libphobos/src/std/exception.d
@@ -1632,6 +1632,9 @@ class ErrnoException : Exception
     /// Operating system error code.
     final @property uint errno() nothrow pure scope @nogc @safe { return _errno; }
     private uint _errno;
+    /// Localized error message generated through $(REF strerror_r, core,stdc,string) or $(REF strerror, core,stdc,string).
+    final @property string errnoMsg() nothrow pure scope @nogc @safe { return _errnoMsg; }
+    private string _errnoMsg;
     /// Constructor which takes an error message. The current global $(REF errno, core,stdc,errno) value is used as error code.
     this(string msg, string file = null, size_t line = 0) @safe
     {
@@ -1642,7 +1645,8 @@ class ErrnoException : Exception
     this(string msg, int errno, string file = null, size_t line = 0) @safe
     {
         _errno = errno;
-        super(msg ~ " (" ~ errnoString(errno) ~ ")", file, line);
+        _errnoMsg = errnoString(errno);
+        super(msg ~ " (" ~ errnoMsg ~ ")", file, line);
     }
 }
 
diff --git a/libphobos/src/std/format/internal/floats.d b/libphobos/src/std/format/internal/floats.d
index afe0bfa3cb5..88b9d22d7d9 100644
--- a/libphobos/src/std/format/internal/floats.d
+++ b/libphobos/src/std/format/internal/floats.d
@@ -28,6 +28,15 @@ if (is(T == float) || is(T == double)
     return w.data;
 }
 
+/// Returns: whether `c` is a supported format specifier for floats
+package(std.format) bool isFloatSpec(char c) nothrow @nogc pure @safe
+{
+    return c == 'a' || c == 'A'
+           || c == 'e' || c == 'E'
+           || c == 'f' || c == 'F'
+           || c == 'g' || c == 'G';
+}
+
 package(std.format) void printFloat(Writer, T, Char)(auto ref Writer w, const(T) val, FormatSpec!Char f)
 if (is(T == float) || is(T == double)
     || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -43,10 +52,7 @@ if (is(T == float) || is(T == double)
     if (sgn == "" && f.flPlus) sgn = "+";
     if (sgn == "" && f.flSpace) sgn = " ";
 
-    assert(f.spec == 'a' || f.spec == 'A'
-           || f.spec == 'e' || f.spec == 'E'
-           || f.spec == 'f' || f.spec == 'F'
-           || f.spec == 'g' || f.spec == 'G', "unsupported format specifier");
+    assert(isFloatSpec(f.spec), "unsupported format specifier");
     bool is_upper = f.spec == 'A' || f.spec == 'E' || f.spec=='F' || f.spec=='G';
 
     // special treatment for nan and inf
diff --git a/libphobos/src/std/format/internal/write.d b/libphobos/src/std/format/internal/write.d
index 85954faa35e..16c7a51d8c6 100644
--- a/libphobos/src/std/format/internal/write.d
+++ b/libphobos/src/std/format/internal/write.d
@@ -570,9 +570,9 @@ void formatValueImpl(Writer, T, Char)(auto ref Writer w, const(T) obj,
                                       scope const ref FormatSpec!Char f)
 if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
 {
-    import std.algorithm.searching : find;
     import std.format : enforceFmt;
     import std.range.primitives : put;
+    import std.format.internal.floats : printFloat, isFloatSpec;
 
     FloatingPointTypeOf!T val = obj;
     const char spec = f.spec;
@@ -597,11 +597,9 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
         return;
     }
 
-    enforceFmt(find("fgFGaAeEs", spec).length,
-        "incompatible format character for floating point argument: %" ~ spec);
-
     FormatSpec!Char fs = f; // fs is copy for change its values.
     fs.spec = spec == 's' ? 'g' : spec;
+    enforceFmt(isFloatSpec(fs.spec), "incompatible format character for floating point argument: %" ~ spec);
 
     static if (is(T == float) || is(T == double)
                || (is(T == real) && (T.mant_dig == double.mant_dig || T.mant_dig == 64)))
@@ -631,7 +629,6 @@ if (is(FloatingPointTypeOf!T) && !is(T == enum) && !hasToString!(T, Char))
             tval = -doubleLowest;
     }
 
-    import std.format.internal.floats : printFloat;
     printFloat(w, tval, fs);
 }
 
diff --git a/libphobos/src/std/math/algebraic.d b/libphobos/src/std/math/algebraic.d
index 99990716460..fd305231d08 100644
--- a/libphobos/src/std/math/algebraic.d
+++ b/libphobos/src/std/math/algebraic.d
@@ -308,7 +308,7 @@ if (isFloatingPoint!T)
     // If both are huge, avoid overflow by scaling by 2^^-N.
     // If both are tiny, avoid underflow by scaling by 2^^N.
     import core.math : fabs, sqrt;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias F = floatTraits!T;
 
diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d
index 8290479248d..5e90f0de897 100644
--- a/libphobos/src/std/math/exponential.d
+++ b/libphobos/src/std/math/exponential.d
@@ -1002,8 +1002,7 @@ float exp(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) exp(ca
 
 private T expImpl(T)(T x) @safe pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
-    import std.math.traits : isNaN;
+    import std.math.traits : floatTraits, RealFormat, isNaN;
     import std.math.rounding : floor;
     import std.math.algebraic : poly;
     import std.math.constants : LOG2E;
@@ -1143,7 +1142,7 @@ private T expImpl(T)(T x) @safe pure nothrow @nogc
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.math.operations : NaN, feqrel, isClose;
     import std.math.constants : E;
     import std.math.traits : isIdentical;
@@ -1517,7 +1516,7 @@ L_largenegative:
 
 private T expm1Impl(T)(T x) @safe pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.math.rounding : floor;
     import std.math.algebraic : poly;
     import std.math.constants : LN2;
@@ -1909,8 +1908,7 @@ L_was_nan:
 
 private T exp2Impl(T)(T x) @nogc @safe pure nothrow
 {
-    import std.math : floatTraits, RealFormat;
-    import std.math.traits : isNaN;
+    import std.math.traits : floatTraits, RealFormat, isNaN;
     import std.math.rounding : floor;
     import std.math.algebraic : poly;
 
@@ -2098,8 +2096,7 @@ private T exp2Impl(T)(T x) @nogc @safe pure nothrow
 T frexp(T)(const T value, out int exp) @trusted pure nothrow @nogc
 if (isFloatingPoint!T)
 {
-    import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
-    import std.math.traits : isSubnormal;
+    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB, isSubnormal;
 
     if (__ctfe)
     {
@@ -2353,8 +2350,7 @@ if (isFloatingPoint!T)
 
 @safe unittest
 {
-    import std.math : floatTraits, RealFormat;
-    import std.math.traits : isIdentical;
+    import std.math.traits : floatTraits, RealFormat, isIdentical;
     import std.meta : AliasSeq;
     import std.typecons : tuple, Tuple;
 
@@ -2486,7 +2482,7 @@ if (isFloatingPoint!T)
 int ilogb(T)(const T x) @trusted pure nothrow @nogc
 if (isFloatingPoint!T)
 {
-    import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
 
     import core.bitop : bsr;
     alias F = floatTraits!T;
@@ -2681,7 +2677,7 @@ alias FP_ILOGBNAN = core.stdc.math.FP_ILOGBNAN;
 
 @safe nothrow @nogc unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.math.operations : nextUp;
     import std.meta : AliasSeq;
     import std.typecons : Tuple;
@@ -2778,7 +2774,7 @@ float ldexp(float n, int exp)   @safe pure nothrow @nogc { return core.math.ldex
 
 @safe pure nothrow @nogc unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
                floatTraits!(real).realFormat == RealFormat.ieeeExtended53 ||
@@ -2866,7 +2862,7 @@ private
     // Coefficients shared across log(), log2(), log10(), log1p().
     template LogCoeffs(T)
     {
-        import std.math : floatTraits, RealFormat;
+        import std.math.traits : floatTraits, RealFormat;
 
         static if (floatTraits!T.realFormat == RealFormat.ieeeQuadruple)
         {
@@ -3179,8 +3175,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc
 {
     import std.math.constants : SQRT1_2;
     import std.math.algebraic : poly;
-    import std.math.traits : isInfinity, isNaN, signbit;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : isInfinity, isNaN, signbit, floatTraits, RealFormat;
 
     alias coeffs = LogCoeffs!T;
     alias F = floatTraits!T;
@@ -3306,7 +3301,7 @@ private T logImpl(T, bool LOG1P = false)(T x) @safe pure nothrow @nogc
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.meta : AliasSeq;
 
     static void testLog(T)(T[2][] vals)
@@ -3452,8 +3447,7 @@ private T log10Impl(T)(T x) @safe pure nothrow @nogc
 {
     import std.math.constants : SQRT1_2;
     import std.math.algebraic : poly;
-    import std.math.traits : isNaN, isInfinity, signbit;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : isNaN, isInfinity, signbit, floatTraits, RealFormat;
 
     alias coeffs = LogCoeffs!T;
     alias F = floatTraits!T;
@@ -3558,7 +3552,7 @@ Ldone:
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.meta : AliasSeq;
 
     static void testLog10(T)(T[2][] vals)
@@ -3710,7 +3704,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc
     import std.math.traits : isNaN, isInfinity, signbit;
     import std.math.algebraic : poly;
     import std.math.constants : SQRT1_2, SQRT2;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     // Special cases.
     if (isNaN(x) || x == 0.0)
@@ -3746,7 +3740,7 @@ private T log1pImpl(T)(T x) @safe pure nothrow @nogc
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.meta : AliasSeq;
 
     static void testLog1p(T)(T[2][] vals)
@@ -3891,7 +3885,7 @@ private T log2Impl(T)(T x) @safe pure nothrow @nogc
     import std.math.traits : isNaN, isInfinity, signbit;
     import std.math.constants : SQRT1_2, LOG2E;
     import std.math.algebraic : poly;
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias coeffs = LogCoeffs!T;
     alias F = floatTraits!T;
@@ -3972,7 +3966,7 @@ Ldone:
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.meta : AliasSeq;
 
     static void testLog2(T)(T[2][] vals)
@@ -4172,7 +4166,7 @@ private T logbImpl(T)(T x) @trusted pure nothrow @nogc
 
 @safe @nogc nothrow unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.meta : AliasSeq;
 
     static void testLogb(T)(T[2][] vals)
diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d
index cb6cb87845c..c7c5d6ee1fc 100644
--- a/libphobos/src/std/math/hardware.d
+++ b/libphobos/src/std/math/hardware.d
@@ -210,14 +210,12 @@ private:
         }
         else version (RISCV_Any)
         {
-            mixin(`
             uint result = void;
             asm pure nothrow @nogc
             {
                 "frflags %0" : "=r" (result);
             }
             return result;
-            `);
         }
         else version (LoongArch_Any)
         {
@@ -307,13 +305,11 @@ private:
         }
         else version (RISCV_Any)
         {
-            mixin(`
             uint newValues = 0x0;
             asm pure nothrow @nogc
             {
                 "fsflags %0" : : "r" (newValues);
             }
-            `);
         }
         else version (LoongArch_Any)
         {
@@ -1039,14 +1035,12 @@ private:
         }
         else version (RISCV_Any)
         {
-            mixin(`
             ControlState cont;
             asm pure nothrow @nogc
             {
                 "frcsr %0" : "=r" (cont);
             }
             return cont;
-            `);
         }
         else version (LoongArch_Any)
         {
@@ -1163,12 +1157,10 @@ private:
         }
         else version (RISCV_Any)
         {
-            mixin(`
             asm pure nothrow @nogc
             {
                 "fscsr %0" : : "r" (newState);
             }
-            `);
         }
         else version (LoongArch_Any)
         {
diff --git a/libphobos/src/std/math/operations.d b/libphobos/src/std/math/operations.d
index 4bf19ee3da9..d456e29adb6 100644
--- a/libphobos/src/std/math/operations.d
+++ b/libphobos/src/std/math/operations.d
@@ -44,7 +44,7 @@ import std.traits : CommonType, isFloatingPoint, isIntegral, Unqual;
  */
 real NaN(ulong payload) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias F = floatTraits!(real);
     static if (F.realFormat == RealFormat.ieeeExtended ||
@@ -136,7 +136,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc
 
 @system pure nothrow @nogc unittest // not @safe because taking address of local.
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     static if (floatTraits!(real).realFormat == RealFormat.ieeeDouble)
     {
@@ -159,7 +159,7 @@ real NaN(ulong payload) @trusted pure nothrow @nogc
  */
 ulong getNaNPayload(real x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     //  assert(isNaN(x));
     alias F = floatTraits!(real);
@@ -283,7 +283,7 @@ debug(UnitTest)
  */
 real nextUp(real x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
 
     alias F = floatTraits!(real);
     static if (F.realFormat != RealFormat.ieeeDouble)
@@ -522,8 +522,7 @@ float nextDown(float x) @safe pure nothrow @nogc
 
 @safe pure nothrow @nogc unittest
 {
-    import std.math : floatTraits, RealFormat;
-    import std.math.traits : isIdentical;
+    import std.math.traits : floatTraits, RealFormat, isIdentical;
 
     static if (floatTraits!(real).realFormat == RealFormat.ieeeExtended ||
                floatTraits!(real).realFormat == RealFormat.ieeeDouble ||
@@ -865,7 +864,7 @@ real fma(real x, real y, real z) @safe pure nothrow @nogc { return (x * y) + z;
 int feqrel(X)(const X x, const X y) @trusted pure nothrow @nogc
 if (isFloatingPoint!(X))
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import core.math : fabs;
 
     /* Public Domain. Author: Don Clugston, 18 Aug 2005.
@@ -1495,7 +1494,7 @@ private template FloatingPointBaseType(T)
 int cmp(T)(const(T) x, const(T) y) @nogc @trusted pure nothrow
 if (isFloatingPoint!T)
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias F = floatTraits!T;
 
@@ -1723,7 +1722,7 @@ if (isFloatingPoint!T)
 FloatingPointBitpattern!T extractBitpattern(T)(const(T) value) @trusted
 if (isFloatingPoint!T)
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     T val = value;
     FloatingPointBitpattern!T ret;
@@ -1895,7 +1894,7 @@ if (isFloatingPoint!T)
 
 @safe pure unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias F = floatTraits!real;
     static if (F.realFormat == RealFormat.ieeeExtended)
@@ -1946,7 +1945,7 @@ if (isFloatingPoint!T)
 
 @safe pure unittest
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.math.exponential : log2;
 
     alias F = floatTraits!real;
diff --git a/libphobos/src/std/math/package.d b/libphobos/src/std/math/package.d
index 614f4d36fbb..0d1ecc35642 100644
--- a/libphobos/src/std/math/package.d
+++ b/libphobos/src/std/math/package.d
@@ -321,169 +321,3 @@ else
     static assert(real.mant_dig == 53 || real.mant_dig == 113,
     "Only 64-bit and 128-bit reals are supported for BigEndian CPUs.");
 }
-
-// Underlying format exposed through floatTraits
-enum RealFormat
-{
-    ieeeHalf,
-    ieeeSingle,
-    ieeeDouble,
-    ieeeExtended,   // x87 80-bit real
-    ieeeExtended53, // x87 real rounded to precision of double.
-    ibmExtended,    // IBM 128-bit extended
-    ieeeQuadruple,
-}
-
-// Constants used for extracting the components of the representation.
-// They supplement the built-in floating point properties.
-template floatTraits(T)
-{
-    import std.traits : Unqual;
-
-    // EXPMASK is a ushort mask to select the exponent portion (without sign)
-    // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
-    // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
-    // EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
-    // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
-    // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
-    enum Unqual!T RECIP_EPSILON = (1/T.epsilon);
-    static if (T.mant_dig == 24)
-    {
-        // Single precision float
-        enum ushort EXPMASK = 0x7F80;
-        enum ushort EXPSHIFT = 7;
-        enum ushort EXPBIAS = 0x3F00;
-        enum uint EXPMASK_INT = 0x7F80_0000;
-        enum uint MANTISSAMASK_INT = 0x007F_FFFF;
-        enum realFormat = RealFormat.ieeeSingle;
-        version (LittleEndian)
-        {
-            enum EXPPOS_SHORT = 1;
-            enum SIGNPOS_BYTE = 3;
-        }
-        else
-        {
-            enum EXPPOS_SHORT = 0;
-            enum SIGNPOS_BYTE = 0;
-        }
-    }
-    else static if (T.mant_dig == 53)
-    {
-        static if (T.sizeof == 8)
-        {
-            // Double precision float, or real == double
-            enum ushort EXPMASK = 0x7FF0;
-            enum ushort EXPSHIFT = 4;
-            enum ushort EXPBIAS = 0x3FE0;
-            enum uint EXPMASK_INT = 0x7FF0_0000;
-            enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
-            enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
-            enum realFormat = RealFormat.ieeeDouble;
-            version (LittleEndian)
-            {
-                enum EXPPOS_SHORT = 3;
-                enum SIGNPOS_BYTE = 7;
-            }
-            else
-            {
-                enum EXPPOS_SHORT = 0;
-                enum SIGNPOS_BYTE = 0;
-            }
-        }
-        else static if (T.sizeof == 12)
-        {
-            // Intel extended real80 rounded to double
-            enum ushort EXPMASK = 0x7FFF;
-            enum ushort EXPSHIFT = 0;
-            enum ushort EXPBIAS = 0x3FFE;
-            enum realFormat = RealFormat.ieeeExtended53;
-            version (LittleEndian)
-            {
-                enum EXPPOS_SHORT = 4;
-                enum SIGNPOS_BYTE = 9;
-            }
-            else
-            {
-                enum EXPPOS_SHORT = 0;
-                enum SIGNPOS_BYTE = 0;
-            }
-        }
-        else
-            static assert(false, "No traits support for " ~ T.stringof);
-    }
-    else static if (T.mant_dig == 64)
-    {
-        // Intel extended real80
-        enum ushort EXPMASK = 0x7FFF;
-        enum ushort EXPSHIFT = 0;
-        enum ushort EXPBIAS = 0x3FFE;
-        enum realFormat = RealFormat.ieeeExtended;
-        version (LittleEndian)
-        {
-            enum EXPPOS_SHORT = 4;
-            enum SIGNPOS_BYTE = 9;
-        }
-        else
-        {
-            enum EXPPOS_SHORT = 0;
-            enum SIGNPOS_BYTE = 0;
-        }
-    }
-    else static if (T.mant_dig == 113)
-    {
-        // Quadruple precision float
-        enum ushort EXPMASK = 0x7FFF;
-        enum ushort EXPSHIFT = 0;
-        enum ushort EXPBIAS = 0x3FFE;
-        enum realFormat = RealFormat.ieeeQuadruple;
-        version (LittleEndian)
-        {
-            enum EXPPOS_SHORT = 7;
-            enum SIGNPOS_BYTE = 15;
-        }
-        else
-        {
-            enum EXPPOS_SHORT = 0;
-            enum SIGNPOS_BYTE = 0;
-        }
-    }
-    else static if (T.mant_dig == 106)
-    {
-        // IBM Extended doubledouble
-        enum ushort EXPMASK = 0x7FF0;
-        enum ushort EXPSHIFT = 4;
-        enum realFormat = RealFormat.ibmExtended;
-
-        // For IBM doubledouble the larger magnitude double comes first.
-        // It's really a double[2] and arrays don't index differently
-        // between little and big-endian targets.
-        enum DOUBLEPAIR_MSB = 0;
-        enum DOUBLEPAIR_LSB = 1;
-
-        // The exponent/sign byte is for most significant part.
-        version (LittleEndian)
-        {
-            enum EXPPOS_SHORT = 3;
-            enum SIGNPOS_BYTE = 7;
-        }
-        else
-        {
-            enum EXPPOS_SHORT = 0;
-            enum SIGNPOS_BYTE = 0;
-        }
-    }
-    else
-        static assert(false, "No traits support for " ~ T.stringof);
-}
-
-// These apply to all floating-point types
-version (LittleEndian)
-{
-    enum MANTISSA_LSB = 0;
-    enum MANTISSA_MSB = 1;
-}
-else
-{
-    enum MANTISSA_LSB = 1;
-    enum MANTISSA_MSB = 0;
-}
diff --git a/libphobos/src/std/math/rounding.d b/libphobos/src/std/math/rounding.d
index 7dbe89b2dee..f6654fc115a 100644
--- a/libphobos/src/std/math/rounding.d
+++ b/libphobos/src/std/math/rounding.d
@@ -551,7 +551,7 @@ long lrint(real x) @trusted pure nothrow @nogc
     }
     else
     {
-        import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+        import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
 
         alias F = floatTraits!(real);
         static if (F.realFormat == RealFormat.ieeeDouble)
@@ -896,7 +896,7 @@ long rndtol(float x) @safe pure nothrow @nogc { return rndtol(cast(real) x); }
 // Helper for floor/ceil
 T floorImpl(T)(const T x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     alias F = floatTraits!(T);
     // Take care not to trigger library calls from the compiler,
diff --git a/libphobos/src/std/math/traits.d b/libphobos/src/std/math/traits.d
index 2841bad219f..81ab1b789db 100644
--- a/libphobos/src/std/math/traits.d
+++ b/libphobos/src/std/math/traits.d
@@ -137,7 +137,7 @@ if (isFloatingPoint!(X))
  */
 bool isFinite(X)(X x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     static if (__traits(isFloating, X))
         if (__ctfe)
@@ -202,7 +202,7 @@ bool isFinite(X)(X x) @trusted pure nothrow @nogc
  */
 bool isNormal(X)(X x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     static if (__traits(isFloating, X))
         if (__ctfe)
@@ -264,7 +264,7 @@ bool isNormal(X)(X x) @trusted pure nothrow @nogc
  */
 bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
 
     static if (__traits(isFloating, X))
         if (__ctfe)
@@ -344,7 +344,7 @@ bool isSubnormal(X)(X x) @trusted pure nothrow @nogc
 bool isInfinity(X)(X x) @nogc @trusted pure nothrow
 if (isFloatingPoint!(X))
 {
-    import std.math : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
+    import std.math.traits : floatTraits, RealFormat, MANTISSA_MSB, MANTISSA_LSB;
 
     alias F = floatTraits!(X);
     static if (F.realFormat == RealFormat.ieeeSingle)
@@ -466,7 +466,7 @@ if (isFloatingPoint!(X))
  */
 bool isIdentical(real x, real y) @trusted pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     // We're doing a bitwise comparison so the endianness is irrelevant.
     long*   pxs = cast(long *)&x;
@@ -510,7 +510,7 @@ bool isIdentical(real x, real y) @trusted pure nothrow @nogc
  */
 int signbit(X)(X x) @nogc @trusted pure nothrow
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     if (__ctfe)
     {
@@ -594,7 +594,7 @@ Returns:
 R copysign(R, X)(R to, X from) @trusted pure nothrow @nogc
 if (isFloatingPoint!(R) && isFloatingPoint!(X))
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
 
     if (__ctfe)
     {
@@ -851,3 +851,168 @@ if (isNumeric!X)
     }}
 }
 
+// Underlying format exposed through floatTraits
+enum RealFormat
+{
+    ieeeHalf,
+    ieeeSingle,
+    ieeeDouble,
+    ieeeExtended,   // x87 80-bit real
+    ieeeExtended53, // x87 real rounded to precision of double.
+    ibmExtended,    // IBM 128-bit extended
+    ieeeQuadruple,
+}
+
+// Constants used for extracting the components of the representation.
+// They supplement the built-in floating point properties.
+template floatTraits(T)
+{
+    import std.traits : Unqual;
+
+    // EXPMASK is a ushort mask to select the exponent portion (without sign)
+    // EXPSHIFT is the number of bits the exponent is left-shifted by in its ushort
+    // EXPBIAS is the exponent bias - 1 (exp == EXPBIAS yields ×2^-1).
+    // EXPPOS_SHORT is the index of the exponent when represented as a ushort array.
+    // SIGNPOS_BYTE is the index of the sign when represented as a ubyte array.
+    // RECIP_EPSILON is the value such that (smallest_subnormal) * RECIP_EPSILON == T.min_normal
+    enum Unqual!T RECIP_EPSILON = (1/T.epsilon);
+    static if (T.mant_dig == 24)
+    {
+        // Single precision float
+        enum ushort EXPMASK = 0x7F80;
+        enum ushort EXPSHIFT = 7;
+        enum ushort EXPBIAS = 0x3F00;
+        enum uint EXPMASK_INT = 0x7F80_0000;
+        enum uint MANTISSAMASK_INT = 0x007F_FFFF;
+        enum realFormat = RealFormat.ieeeSingle;
+        version (LittleEndian)
+        {
+            enum EXPPOS_SHORT = 1;
+            enum SIGNPOS_BYTE = 3;
+        }
+        else
+        {
+            enum EXPPOS_SHORT = 0;
+            enum SIGNPOS_BYTE = 0;
+        }
+    }
+    else static if (T.mant_dig == 53)
+    {
+        static if (T.sizeof == 8)
+        {
+            // Double precision float, or real == double
+            enum ushort EXPMASK = 0x7FF0;
+            enum ushort EXPSHIFT = 4;
+            enum ushort EXPBIAS = 0x3FE0;
+            enum uint EXPMASK_INT = 0x7FF0_0000;
+            enum uint MANTISSAMASK_INT = 0x000F_FFFF; // for the MSB only
+            enum ulong MANTISSAMASK_LONG = 0x000F_FFFF_FFFF_FFFF;
+            enum realFormat = RealFormat.ieeeDouble;
+            version (LittleEndian)
+            {
+                enum EXPPOS_SHORT = 3;
+                enum SIGNPOS_BYTE = 7;
+            }
+            else
+            {
+                enum EXPPOS_SHORT = 0;
+                enum SIGNPOS_BYTE = 0;
+            }
+        }
+        else static if (T.sizeof == 12)
+        {
+            // Intel extended real80 rounded to double
+            enum ushort EXPMASK = 0x7FFF;
+            enum ushort EXPSHIFT = 0;
+            enum ushort EXPBIAS = 0x3FFE;
+            enum realFormat = RealFormat.ieeeExtended53;
+            version (LittleEndian)
+            {
+                enum EXPPOS_SHORT = 4;
+                enum SIGNPOS_BYTE = 9;
+            }
+            else
+            {
+                enum EXPPOS_SHORT = 0;
+                enum SIGNPOS_BYTE = 0;
+            }
+        }
+        else
+            static assert(false, "No traits support for " ~ T.stringof);
+    }
+    else static if (T.mant_dig == 64)
+    {
+        // Intel extended real80
+        enum ushort EXPMASK = 0x7FFF;
+        enum ushort EXPSHIFT = 0;
+        enum ushort EXPBIAS = 0x3FFE;
+        enum realFormat = RealFormat.ieeeExtended;
+        version (LittleEndian)
+        {
+            enum EXPPOS_SHORT = 4;
+            enum SIGNPOS_BYTE = 9;
+        }
+        else
+        {
+            enum EXPPOS_SHORT = 0;
+            enum SIGNPOS_BYTE = 0;
+        }
+    }
+    else static if (T.mant_dig == 113)
+    {
+        // Quadruple precision float
+        enum ushort EXPMASK = 0x7FFF;
+        enum ushort EXPSHIFT = 0;
+        enum ushort EXPBIAS = 0x3FFE;
+        enum realFormat = RealFormat.ieeeQuadruple;
+        version (LittleEndian)
+        {
+            enum EXPPOS_SHORT = 7;
+            enum SIGNPOS_BYTE = 15;
+        }
+        else
+        {
+            enum EXPPOS_SHORT = 0;
+            enum SIGNPOS_BYTE = 0;
+        }
+    }
+    else static if (T.mant_dig == 106)
+    {
+        // IBM Extended doubledouble
+        enum ushort EXPMASK = 0x7FF0;
+        enum ushort EXPSHIFT = 4;
+        enum realFormat = RealFormat.ibmExtended;
+
+        // For IBM doubledouble the larger magnitude double comes first.
+        // It's really a double[2] and arrays don't index differently
+        // between little and big-endian targets.
+        enum DOUBLEPAIR_MSB = 0;
+        enum DOUBLEPAIR_LSB = 1;
+
+        // The exponent/sign byte is for most significant part.
+        version (LittleEndian)
+        {
+            enum EXPPOS_SHORT = 3;
+            enum SIGNPOS_BYTE = 7;
+        }
+        else
+        {
+            enum EXPPOS_SHORT = 0;
+            enum SIGNPOS_BYTE = 0;
+        }
+    }
+    else
+        static assert(false, "No traits support for " ~ T.stringof);
+}
+
+// These apply to all floating-point types
+version (LittleEndian)
+{
+    enum MANTISSA_LSB = 0;
+    enum MANTISSA_MSB = 1;
+}
+else
+{
+    enum MANTISSA_LSB = 1;
+    enum MANTISSA_MSB = 0;
+}
diff --git a/libphobos/src/std/math/trigonometry.d b/libphobos/src/std/math/trigonometry.d
index a3d04c60402..4f5f5c50e55 100644
--- a/libphobos/src/std/math/trigonometry.d
+++ b/libphobos/src/std/math/trigonometry.d
@@ -307,7 +307,7 @@ Lret:
 
 private T tanImpl(T)(T x) @safe pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
+    import std.math.traits : floatTraits, RealFormat;
     import std.math.constants : PI, PI_4;
     import std.math.rounding : floor;
     import std.math.algebraic : poly;
@@ -675,8 +675,7 @@ float atan(float x) @safe pure nothrow @nogc { return __ctfe ? cast(float) atan(
 
 private T atanImpl(T)(T x) @safe pure nothrow @nogc
 {
-    import std.math : floatTraits, RealFormat;
-    import std.math.traits : copysign, isInfinity, signbit;
+    import std.math.traits : floatTraits, RealFormat, copysign, isInfinity, signbit;
     import std.math.constants : PI_2, PI_4;
     import std.math.algebraic : poly;
 
diff --git a/libphobos/src/std/mmfile.d b/libphobos/src/std/mmfile.d
index f8f8a9088b6..b2cab3157d0 100644
--- a/libphobos/src/std/mmfile.d
+++ b/libphobos/src/std/mmfile.d
@@ -2,10 +2,22 @@
 
 /**
  * Read and write memory mapped files.
+ *
+ * Memory mapped files are a mechanism in operating systems that allows
+ * file access through virtual memory. After opening a file with `MmFile`,
+ * the contents can be read from or written to with standard slice / pointer operations.
+ * Changes to the memory are automatically reflected in the underlying file.
+ *
+ * Memory mapping can increase I/O performance of large files, compared to buffered
+ * read / write operations from `std.file` and `std.stdio`. However, I/O errors are
+ * not handled as safely: when for example the disk that the file is on gets removed,
+ * reading from it may result in a segfault.
+ *
  * Copyright: Copyright The D Language Foundation 2004 - 2009.
  * License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
  * Authors:   $(HTTP digitalmars.com, Walter Bright),
  *            Matthew Wilson
+ * References: $(LINK https://en.wikipedia.org/wiki/Memory-mapped_file)
  * Source:    $(PHOBOSSRC std/mmfile.d)
  *
  * $(SCRIPT inhibitQuickIndex = 1;)
@@ -612,23 +624,47 @@ private:
     {
         static assert(0);
     }
+}
+
+/// Read an existing file
+@system unittest
+{
+    import std.file;
+    std.file.write(deleteme, "hello"); // deleteme is a temporary filename
+    scope(exit) remove(deleteme);
+
+    // Use a scope class so the file will be closed at the end of this function
+    scope mmfile = new MmFile(deleteme);
+
+    assert(mmfile.length == "hello".length);
+
+    // Access file contents with the slice operator
+    // This is typed as `void[]`, so cast to `char[]` or `ubyte[]` to use it
+    const data = cast(const(char)[]) mmfile[];
+
+    // At this point, the file content may not have been read yet.
+    // In that case, the following memory access will intentionally
+    // trigger a page fault, causing the kernel to load the file contents
+    assert(data[0 .. 5] == "hello");
+}
+
+/// Write a new file
+@system unittest
+{
+    import std.file;
+    scope(exit) remove(deleteme);
+
+    scope mmfile = new MmFile(deleteme, MmFile.Mode.readWriteNew, 5, null);
+    assert(mmfile.length == 5);
+
+    auto data = cast(ubyte[]) mmfile[];
+
+    // This write to memory will be reflected in the file contents
+    data[] = '\n';
+
+    mmfile.flush();
 
-    // Report error, where errno gives the error number
-    // void errNo()
-    // {
-    //     version (Windows)
-    //     {
-    //         throw new FileException(filename, GetLastError());
-    //     }
-    //     else version (linux)
-    //     {
-    //         throw new FileException(filename, errno);
-    //     }
-    //     else
-    //     {
-    //         static assert(0);
-    //     }
-    // }
+    assert(std.file.read(deleteme) == "\n\n\n\n\n");
 }
 
 @system unittest
diff --git a/libphobos/src/std/regex/internal/backtracking.d b/libphobos/src/std/regex/internal/backtracking.d
index ac73f70f0f3..a488e0660d0 100644
--- a/libphobos/src/std/regex/internal/backtracking.d
+++ b/libphobos/src/std/regex/internal/backtracking.d
@@ -682,7 +682,7 @@ final:
                     while (prevStack()) {}
                     return re.ir[pc].data;
                 default:
-                    debug printBytecode(re.ir[0..$]);
+                    debug(std_regex_debug) printBytecode(re.ir[0..$]);
                     assert(0);
                 L_backtrack:
                     if (!popState())
diff --git a/libphobos/src/std/regex/internal/ir.d b/libphobos/src/std/regex/internal/ir.d
index 069d75f8822..04b902fc39d 100644
--- a/libphobos/src/std/regex/internal/ir.d
+++ b/libphobos/src/std/regex/internal/ir.d
@@ -403,7 +403,7 @@ struct Group(DataIndex)
 }
 
 //debugging tool, prints out instruction along with opcodes
-@trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[])
+debug(std_regex_parser) @trusted string disassemble(in Bytecode[] irb, uint pc, in NamedGroup[] dict=[])
 {
     import std.array : appender;
     import std.format.write : formattedWrite;
@@ -467,7 +467,7 @@ struct Group(DataIndex)
 }
 
 //disassemble the whole chunk
-@trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[])
+debug(std_regex_parser) @trusted void printBytecode()(in Bytecode[] slice, in NamedGroup[] dict=[])
 {
     import std.stdio : writeln;
     for (uint pc=0; pc<slice.length; pc += slice[pc].length)
diff --git a/libphobos/src/std/typecons.d b/libphobos/src/std/typecons.d
index 67a1ede8148..13ae2941296 100644
--- a/libphobos/src/std/typecons.d
+++ b/libphobos/src/std/typecons.d
@@ -3256,11 +3256,19 @@ struct Nullable(T)
      * Params:
      *     value = The value to initialize this `Nullable` with.
      */
-    this(inout T value) inout
-    {
-        _value.payload = value;
-        _isNull = false;
-    }
+    static if (isCopyable!T)
+        this(inout T value) inout
+        {
+            _value.payload = value;
+            _isNull = false;
+        }
+    else
+        this(T value) inout
+        {
+            import std.algorithm.mutation : move;
+            _value.payload = move(value);
+            _isNull = false;
+        }
 
     static if (hasElaborateDestructor!T)
     {
@@ -3273,6 +3281,9 @@ struct Nullable(T)
         }
     }
 
+    static if (!isCopyable!T)
+        @disable this(this);
+    else
     static if (__traits(hasPostblit, T))
     {
         this(this)
@@ -3511,22 +3522,18 @@ struct Nullable(T)
      * Params:
      *     value = A value of type `T` to assign to this `Nullable`.
      */
-    Nullable opAssign()(T value)
+    ref Nullable opAssign()(T value) return
     {
         import std.algorithm.mutation : moveEmplace, move;
 
-        // the lifetime of the value in copy shall be managed by
-        // this Nullable, so we must avoid calling its destructor.
-        auto copy = DontCallDestructorT(value);
-
         if (_isNull)
         {
             // trusted since payload is known to be uninitialized.
-            () @trusted { moveEmplace(copy.payload, _value.payload); }();
+            () @trusted { moveEmplace(value, _value.payload); }();
         }
         else
         {
-            move(copy.payload, _value.payload);
+            move(value, _value.payload);
         }
         _isNull = false;
         return this;
@@ -3604,12 +3611,14 @@ struct Nullable(T)
     alias back = front;
 
     /// ditto
+    static if (isCopyable!T)
     @property inout(typeof(this)) save() inout
     {
         return this;
     }
 
     /// ditto
+    static if (isCopyable!T)
     inout(typeof(this)) opIndex(size_t[2] dim) inout
     in (dim[0] <= length && dim[1] <= length && dim[1] >= dim[0])
     {
@@ -4088,16 +4097,12 @@ auto nullable(T)(T t)
 
     struct Test
     {
-        bool b;
-
-        nothrow invariant { assert(b == true); }
-
         SysTime _st;
 
         static bool destroyed;
 
         @disable this();
-        this(bool b) { this.b = b; }
+        this(int _dummy) {}
         ~this() @safe { destroyed = true; }
 
         // mustn't call opAssign on Test.init in Nullable!Test, because the invariant
@@ -4109,7 +4114,7 @@ auto nullable(T)(T t)
     {
         Nullable!Test nt;
 
-        nt = Test(true);
+        nt = Test(1);
 
         // destroy value
         Test.destroyed = false;
@@ -10676,6 +10681,21 @@ unittest
     assert(s2.get().b == 3);
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=24318
+@system unittest
+{
+    static struct S
+    {
+        @disable this(this);
+        int i;
+    }
+
+    Nullable!S s = S(1);
+    assert(s.get().i == 1);
+    s = S(2);
+    assert(s.get().i == 2);
+}
+
 /// The old version of $(LREF SafeRefCounted), before $(LREF borrow) existed.
 /// Old code may be relying on `@safe`ty of some of the member functions which
 /// cannot be safe in the new scheme, and
