diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 4ed8751079b..24ac456e23d 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -97,12 +97,15 @@ build_frontend_type (tree type)
 	{
 	  /* Check for char * first.  Needs to be done for chars/string.  */
 	  if (TYPE_MAIN_VARIANT (TREE_TYPE (type)) == char_type_node)
-	    return Type::tchar->addMod (dtype->mod)->pointerTo ()->addMod (mod);
+	    {
+	      dtype = addMod (Type::tchar, dtype->mod);
+	      return addMod (dtype->pointerTo (), mod);
+	    }
 
 	  if (dtype->ty == TY::Tfunction)
-	    return (TypePointer::create (dtype))->addMod (mod);
+	    return addMod (TypePointer::create (dtype), mod);
 
-	  return dtype->pointerTo ()->addMod (mod);
+	  return addMod (dtype->pointerTo (), mod);
 	}
       break;
 
@@ -113,7 +116,7 @@ build_frontend_type (tree type)
 	  /* Want to assign ctype directly so that the REFERENCE_TYPE code
 	     can be turned into as an `inout' argument.  Can't use pointerTo(),
 	     because the returned Type is shared.  */
-	  dtype = (TypePointer::create (dtype))->addMod (mod);
+	  dtype = addMod (TypePointer::create (dtype), mod);
 	  dtype->ctype = type;
 	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
 	  return dtype;
@@ -122,7 +125,7 @@ build_frontend_type (tree type)
 
     case BOOLEAN_TYPE:
       /* Should be no need for size checking.  */
-      return Type::tbool->addMod (mod);
+      return addMod (Type::tbool, mod);
 
     case INTEGER_TYPE:
     {
@@ -140,7 +143,7 @@ build_frontend_type (tree type)
 	      || size != dtype->size ())
 	    continue;
 
-	  return dtype->addMod (mod);
+	  return addMod (dtype, mod);
 	}
       break;
     }
@@ -157,7 +160,7 @@ build_frontend_type (tree type)
 	  if (dtype->size () != size)
 	    continue;
 
-	  return dtype->addMod (mod);
+	  return addMod (dtype, mod);
 	}
       break;
     }
@@ -174,13 +177,13 @@ build_frontend_type (tree type)
 	  if (dtype->size () != size)
 	    continue;
 
-	  return dtype->addMod (mod);
+	  return addMod (dtype, mod);
 	}
       break;
     }
 
     case VOID_TYPE:
-      return Type::tvoid->addMod (mod);
+      return addMod (Type::tvoid, mod);
 
     case ARRAY_TYPE:
       dtype = build_frontend_type (TREE_TYPE (type));
@@ -194,7 +197,7 @@ build_frontend_type (tree type)
 	  length = size_binop (PLUS_EXPR, size_one_node,
 			       convert (sizetype, length));
 
-	  dtype = dtype->sarrayOf (TREE_INT_CST_LOW (length))->addMod (mod);
+	  dtype = addMod (dtype->sarrayOf (TREE_INT_CST_LOW (length)), mod);
 	  builtin_converted_decls.safe_push (builtin_data (dtype, type));
 	  return dtype;
 	}
@@ -210,11 +213,11 @@ build_frontend_type (tree type)
       if (!dtype)
 	break;
 
-      dtype = dtype->sarrayOf (nunits)->addMod (mod);
+      dtype = addMod (dtype->sarrayOf (nunits), mod);
       if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
 	break;
 
-      dtype = (TypeVector::create (dtype))->addMod (mod);
+      dtype = addMod (TypeVector::create (dtype), mod);
       builtin_converted_decls.safe_push (builtin_data (dtype, type));
       return dtype;
     }
@@ -238,7 +241,7 @@ build_frontend_type (tree type)
       sdecl->alignsize = TYPE_ALIGN_UNIT (type);
       sdecl->alignment.setDefault ();
       sdecl->sizeok = Sizeok::done;
-      sdecl->type = (TypeStruct::create (sdecl))->addMod (mod);
+      sdecl->type = addMod (TypeStruct::create (sdecl), mod);
       sdecl->type->ctype = type;
       merge2 (sdecl->type);
 
@@ -331,7 +334,7 @@ build_frontend_type (tree type)
 	  if (args->length != 0 || varargs_p == VARARGnone)
 	    {
 	      dtype = TypeFunction::create (args, dtype, varargs_p, LINK::c);
-	      return dtype->addMod (mod);
+	      return addMod (dtype, mod);
 	    }
 	}
       break;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 57ac2dc69e7..74c194508f7 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-a6f10836997d0b5526c8c363d781b4029c77f09f
+11240a96635074b2f79d908b9348e9c0fbc3c7dc
 
 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/aggregate.d b/gcc/d/dmd/aggregate.d
index 2d320426c23..2c7622a9aa0 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -37,7 +37,7 @@ import dmd.identifier;
 import dmd.location;
 import dmd.mtype;
 import dmd.tokens;
-import dmd.typesem : defaultInit;
+import dmd.typesem : defaultInit, addMod;
 import dmd.visitor;
 
 /**
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index f466ba61740..6a864002e08 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -42,6 +42,7 @@ enum class Baseok : uint8_t
 };
 
 FuncDeclaration *search_toString(StructDeclaration *sd);
+void semanticTypeInfoMembers(StructDeclaration *sd);
 
 enum class ClassKind : uint8_t
 {
diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d
index f17907719a7..fd8387adb22 100644
--- a/gcc/d/dmd/astcodegen.d
+++ b/gcc/d/dmd/astcodegen.d
@@ -82,6 +82,7 @@ struct ASTCodegen
     alias Tcomplex64                = dmd.mtype.Tcomplex64;
     alias Tcomplex80                = dmd.mtype.Tcomplex80;
 
+    alias ModToStc                  = dmd.mtype.ModToStc;
     alias ParameterList             = dmd.mtype.ParameterList;
     alias VarArg                    = dmd.mtype.VarArg;
     alias STC                       = dmd.declaration.STC;
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 77940b80248..4fc15141c39 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -152,7 +152,7 @@ bool isRefReturnScope(const ulong stc)
 
 /* This is different from the one in declaration.d, make that fix a separate PR */
 static if (0)
-extern (C++) __gshared const(StorageClass) STCStorageClass =
+__gshared const(StorageClass) STCStorageClass =
     (STC.auto_ | STC.scope_ | STC.static_ | STC.extern_ | STC.const_ | STC.final_ |
      STC.abstract_ | STC.synchronized_ | STC.deprecated_ | STC.override_ | STC.lazy_ |
      STC.alias_ | STC.out_ | STC.in_ | STC.manifest | STC.immutable_ | STC.shared_ |
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 46470ee9e37..2e4833e8fdd 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -327,10 +327,19 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
         auto e2 = new BlitExp(loc, new VarExp(loc, swap), new ThisExp(loc));
         auto e3 = new BlitExp(loc, new ThisExp(loc), new IdentifierExp(loc, Id.p));
 
-        /* Instead of running the destructor on s, run it
-         * on swap. This avoids needing to copy swap back in to s.
-         */
-        auto e4 = new CallExp(loc, new DotVarExp(loc, new VarExp(loc, swap), sd.dtor, false));
+        Expression e4;
+        if (target.isCalleeDestroyingArgs(tf))
+        {   /* callee destroys s
+             * Instead of running the destructor on s, run it
+             * on swap.
+             */
+            e4 = new CallExp(loc, new DotVarExp(loc, new VarExp(loc, swap), sd.dtor, false));
+        }
+        else
+        {   /* caller destroys s, so copy contents of swap back into s
+             */
+            e4 = new BlitExp(loc, new IdentifierExp(loc, Id.p), new VarExp(loc, swap));
+        }
 
         e = Expression.combine(e1, e2, e3, e4);
     }
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index f5d2b60f45b..0686e1b0825 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -36,6 +36,7 @@ import dmd.root.utf;
 import dmd.sideeffect;
 import dmd.target;
 import dmd.tokens;
+import dmd.typesem : toDsymbol, equivalent;
 
 private enum LOG = false;
 
@@ -1038,7 +1039,6 @@ 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/dcast.d b/gcc/d/dmd/dcast.d
index 9ee8e8c4864..a49bd575f4b 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -235,7 +235,7 @@ Expression implicitCastTo(Expression e, Scope* sc, Type t)
  * Returns:
  *   The `MATCH` level between `e.type` and `t`.
  */
-extern(C++) MATCH implicitConvTo(Expression e, Type t)
+MATCH implicitConvTo(Expression e, Type t)
 {
     MATCH visit(Expression e)
     {
@@ -2848,7 +2848,7 @@ private bool isVoidArrayLiteral(Expression e, Type other)
  */
 Type typeMerge(Scope* sc, EXP op, ref Expression pe1, ref Expression pe2)
 {
-    //printf("typeMerge() %s op %s\n", e1.toChars(), e2.toChars());
+    //printf("typeMerge() %s op %s\n", pe1.toChars(), pe2.toChars());
 
     Expression e1 = pe1;
     Expression e2 = pe2;
@@ -3165,6 +3165,9 @@ Lagain:
         goto Lagain;
     }
 
+LmergeClassTypes:
+    /* Merge different type modifiers on classes
+     */
     if (t1.ty == Tclass && t2.ty == Tclass)
     {
         if (t1.mod != t2.mod)
@@ -3233,9 +3236,23 @@ Lagain:
 
             if (t1.ty == Tclass && t2.ty == Tclass)
             {
+                /* t1 cannot be converted to t2, and vice versa
+                 */
                 TypeClass tc1 = t1.isTypeClass();
                 TypeClass tc2 = t2.isTypeClass();
 
+                //if (tc1.sym.interfaces.length || tc2.sym.interfaces.length)
+                if (tc1.sym.isInterfaceDeclaration() ||
+                    tc2.sym.isInterfaceDeclaration())
+                {
+                    ClassDeclaration cd = findClassCommonRoot(tc1.sym, tc2.sym);
+                    if (!cd)
+                        return null;    // no common root
+                    t1 = cd.type.castMod(t1.mod);
+                    t2 = cd.type.castMod(t2.mod);
+                    goto LmergeClassTypes;   // deal with mod differences
+                }
+
                 /* Pick 'tightest' type
                  */
                 ClassDeclaration cd1 = tc1.sym.baseClass;
@@ -3251,6 +3268,7 @@ Lagain:
                     t2 = cd2.type;
                 else
                     return null;
+                goto LmergeClassTypes;
             }
             else if (t1.ty == Tstruct && t1.isTypeStruct().sym.aliasthis)
             {
@@ -3582,6 +3600,71 @@ LmodCompare:
     return null;
 }
 
+/**********************************
+ * Find common root that both cd1 and cd2 can be implicitly converted to.
+ * Params:
+ *      cd1 = first class
+ *      cd2 = second class
+ * Returns:
+ *      common base that both can implicitly convert to, null if none or
+ *      multiple matches
+ */
+private
+ClassDeclaration findClassCommonRoot(ClassDeclaration cd1, ClassDeclaration cd2)
+{
+    enum log = false;
+    if (log) printf("findClassCommonRoot(%s, %s)\n", cd1.toChars(), cd2.toChars());
+    /* accumulate results in this */
+    static struct Root
+    {
+        ClassDeclaration cd;
+        bool error;
+
+        /* merge cd into results */
+        void accumulate(ClassDeclaration cd)
+        {
+            if (log) printf(" accumulate(r.cd: %s r.error: %d cd: %s)\n", this.cd ? this.cd.toChars() : "null", error, cd ? cd.toChars() : null);
+            if (this.cd is cd)
+            {
+            }
+            else if (!this.cd)
+                this.cd = cd;
+            else
+                error = true;
+        }
+    }
+
+    /* Find common root of cd1 and cd2. Accumulate results in r. depth is nesting level */
+    void findCommonRoot(ClassDeclaration cd1, ClassDeclaration cd2, ref Root r)
+    {
+        if (log) printf("findCommonRoot(cd1: %s cd2: %s)\n", cd1.toChars(), cd2.toChars());
+        /* Warning: quadratic time function
+         */
+        if (cd1 is cd2)
+        {
+            r.accumulate(cd1);
+            return;
+        }
+
+        foreach (b1; (*cd1.baseclasses)[])
+        {
+            if (b1.sym != r.cd)
+                findCommonRoot(cd2, b1.sym, r);
+        }
+        foreach (b2; (*cd2.baseclasses)[])
+        {
+            if (b2.sym != r.cd)
+                findCommonRoot(cd1, b2.sym, r);
+        }
+    }
+
+    Root r;
+    findCommonRoot(cd1, cd2, r);
+    if (!r.cd || r.error)
+        return null;        // no common root
+    return r.cd;
+}
+
 /************************************
  * Bring leaves to common type.
  * Returns:
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 93ef63f7aa3..3f9769d7155 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -213,7 +213,7 @@ bool modifyFieldVar(Loc loc, Scope* sc, VarDeclaration var, Expression e1)
 
 /******************************************
  */
-extern (C++) void ObjectNotFound(Identifier id)
+void ObjectNotFound(Identifier id)
 {
     error(Loc.initial, "`%s` not found. object.d may be incorrectly installed or corrupt.", id.toChars());
     fatal();
@@ -1380,7 +1380,7 @@ extern (C++) class VarDeclaration : Declaration
      */
     final bool needsScopeDtor()
     {
-        //printf("VarDeclaration::needsScopeDtor() %s\n", toChars());
+        //printf("VarDeclaration::needsScopeDtor() %s %d\n", toChars(), edtor && !(storage_class & STC.nodtor));
         return edtor && !(storage_class & STC.nodtor);
     }
 
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index afbb9975cc9..a393da80c09 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -107,8 +107,6 @@ bool functionSemantic3(FuncDeclaration* fd);
 #define STC_TYPECTOR    (STCconst | STCimmutable | STCshared | STCwild)
 #define STC_FUNCATTR    (STCref | STCnothrow | STCnogc | STCpure | STCproperty | STCsafe | STCtrusted | STCsystem)
 
-void ObjectNotFound(Identifier *id);
-
 /**************************************************************/
 
 class Declaration : public Dsymbol
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index b0785424f3c..c3395a584e2 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -50,7 +50,7 @@ import dmd.rootobject;
 import dmd.root.utf;
 import dmd.statement;
 import dmd.tokens;
-import dmd.typesem : mutableOf;
+import dmd.typesem : mutableOf, equivalent;
 import dmd.utils : arrayCastBigEndian;
 import dmd.visitor;
 
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index e463d3d9005..db236275570 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -427,7 +427,5 @@ public:
 
 void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
 Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
-bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc);
 void setScope(Dsymbol *d, Scope *sc);
 void importAll(Dsymbol *d, Scope *sc);
-void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 33a397a87b0..4a4d82ff5c0 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -6907,7 +6907,7 @@ extern(C++) class ImportAllVisitor : Visitor
     override void visit(StaticForeachDeclaration _) {}
 }
 
-extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
 {
     scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);
     d.accept(v);
diff --git a/gcc/d/dmd/errors.h b/gcc/d/dmd/errors.h
index 308e81e30ba..a47b5aada56 100644
--- a/gcc/d/dmd/errors.h
+++ b/gcc/d/dmd/errors.h
@@ -24,8 +24,6 @@ enum class ErrorKind
     message = 4,
 };
 
-bool isConsoleColorSupported();
-
 #if defined(__GNUC__)
 #define D_ATTRIBUTE_FORMAT(m, n) __attribute__((format(printf, m, n))) __attribute__((nonnull (m)))
 #else
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index f713d25a739..8dbb4a63c7e 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -46,15 +46,15 @@ typedef union tree_node Symbol;
 struct Symbol;          // back end symbol
 #endif
 
+// in expressionsem.d
+Expression *expressionSemantic(Expression *e, Scope *sc);
+// in typesem.d
+Expression *defaultInit(Type *mt, const Loc &loc, const bool isCfile = false);
+
 // Entry point for CTFE.
 // A compile-time result is required. Give an error if not possible
 Expression *ctfeInterpret(Expression *e);
 void expandTuples(Expressions *exps, Identifiers *names = nullptr);
-StringExp *toUTF8(StringExp *se, Scope *sc);
-Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc);
-MATCH implicitConvTo(Expression *e, Type *t);
-Expression *toLvalue(Expression *_this, Scope *sc, const char* action);
-Expression *modifiableLvalue(Expression* exp, Scope *sc);
 Expression *optimize(Expression *exp, int result, bool keepLvalue = false);
 
 typedef unsigned char OwnedBy;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index d7377dbdea8..9028ba1b191 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -2523,7 +2523,7 @@ private bool checkRightThis(Expression e, Scope* sc)
     return false;
 }
 
-extern (C++) Expression resolveProperties(Scope* sc, Expression e)
+Expression resolveProperties(Scope* sc, Expression e)
 {
     //printf("resolveProperties(%s)\n", e.toChars());
     e = resolvePropertiesX(sc, e);
@@ -3464,12 +3464,12 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
             eprefix = ae.expressionSemantic(sc);
         }
 
-        for (ptrdiff_t i = 0; i != nargs; i++)
+        foreach (ptrdiff_t i; 0 .. nargs)
         {
             Expression arg = (*arguments)[i];
             //printf("arg[%d]: %s\n", cast(int)i, arg.toChars());
 
-            Parameter parameter = (i >= nparams ? null : tf.parameterList[i]);
+            Parameter parameter = i < nparams ? tf.parameterList[i] : null;
             const bool isRef = parameter && parameter.isReference();
             const bool isLazy = parameter && parameter.isLazy();
 
@@ -3485,7 +3485,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
              * 'eprefix' will therefore finally contain all args up to and including 'lastPrefix',
              * excluding all lazy parameters.
              */
-            if (needsPrefix && (lastPrefix - i) >= 0)
+            if (needsPrefix && i <= lastPrefix)
             {
                 const bool needsDtor = !isRef && arg.type.needsDestruction() &&
                                        // Problem 3: last throwing arg doesn't require dtor patching
@@ -3494,9 +3494,9 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                 /* Declare temporary 'auto __pfx = arg' (needsDtor) or 'auto __pfy = arg' (!needsDtor)
                  */
                 auto tmp = copyToTemp(
-                    (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.scope_),
+                    (parameter ? parameter.storageClass : tf.parameterList.stc) & (STC.return_ | STC.scope_),
                     needsDtor ? "__pfx" : "__pfy",
-                    !isRef ? arg : arg.addressOf());
+                    isRef ? arg.addressOf() : arg);
                 tmp.dsymbolSemantic(sc);
 
                 if (callerDestroysArgs)
@@ -3511,15 +3511,7 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                     /* Problem 2: Modify the destructor so it only runs if gate==false,
                      * i.e., only if there was a throw while constructing the args
                      */
-                    if (!needsDtor)
-                    {
-                        if (tmp.edtor)
-                        {
-                            assert(i == lastPrefix);
-                            tmp.edtor = null;
-                        }
-                    }
-                    else
+                    if (needsDtor)
                     {
                         // edtor => (__gate || edtor)
                         assert(tmp.edtor);
@@ -3528,6 +3520,14 @@ private bool functionParameters(const ref Loc loc, Scope* sc,
                         tmp.edtor = e.expressionSemantic(sc);
                         //printf("edtor: %s\n", tmp.edtor.toChars());
                     }
+                    else
+                    {
+                        if (tmp.edtor)
+                        {
+                            assert(i == lastPrefix);
+                            tmp.edtor = null;
+                        }
+                    }
                 }
 
                 // eprefix => (eprefix, auto __pfx/y = arg)
@@ -15534,7 +15534,7 @@ Expression addDtorHook(Expression e, Scope* sc)
  *     action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
  * Returns: converted expression, or `ErrorExp` on error
 */
-extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
+Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
 {
     return toLvalueImpl(_this, sc, action, _this);
 }
@@ -15955,7 +15955,7 @@ Modifiable checkModifiable(Expression exp, Scope* sc, ModifyFlags flag = ModifyF
  *     sc = scope
  * Returns: `_this` converted to an lvalue, or an `ErrorExp`
  */
-extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc)
+Expression modifiableLvalue(Expression _this, Scope* sc)
 {
     return modifiableLvalueImpl(_this, sc, _this);
 }
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index ddf21a2079f..4881ad6c020 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -60,6 +60,7 @@ import dmd.statement;
 import dmd.statementsem;
 import dmd.templatesem;
 import dmd.tokens;
+import dmd.typesem;
 import dmd.visitor;
 
 version (IN_GCC) {}
@@ -518,7 +519,6 @@ extern (C++) class FuncDeclaration : Declaration
         int result = 0;
         if (fd.ident == ident)
         {
-            import dmd.typesem : covariant;
             const cov = type.covariant(fd.type);
             if (cov != Covariant.distinct)
             {
@@ -625,7 +625,6 @@ extern (C++) class FuncDeclaration : Declaration
              */
             if (t.ty == Tfunction)
             {
-                import dmd.typesem : covariant;
                 auto tf = cast(TypeFunction)f.type;
                 if (tf.covariant(t) == Covariant.yes &&
                     tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
@@ -840,7 +839,6 @@ extern (C++) class FuncDeclaration : Declaration
             args.push(e);
         }
 
-        import dmd.typesem : callMatch;
         MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
         if (m > MATCH.nomatch)
         {
@@ -1151,7 +1149,6 @@ extern (C++) class FuncDeclaration : Declaration
     {
         //printf("FuncDeclaration::isPure() '%s'\n", toChars());
 
-        import dmd.typesem : purityLevel;
 
         TypeFunction tf = type.toTypeFunction();
         if (purityInprocess)
@@ -1464,7 +1461,6 @@ 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);
@@ -1546,7 +1542,6 @@ 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)
                         {
@@ -2411,7 +2406,6 @@ 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
@@ -3325,7 +3319,6 @@ 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();
@@ -3372,7 +3365,6 @@ 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();
@@ -3409,7 +3401,6 @@ 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/hdrgen.h b/gcc/d/dmd/hdrgen.h
index e38ca569354..e0a20461d45 100644
--- a/gcc/d/dmd/hdrgen.h
+++ b/gcc/d/dmd/hdrgen.h
@@ -13,9 +13,17 @@
 #include "globals.h"
 #include "mtype.h"
 
+class Expression;
+class Initializer;
 class Module;
+class Statement;
 
 void genhdrfile(Module *m, bool doFuncBodies, OutBuffer &buf);
 void genCppHdrFiles(Modules &ms);
 void moduleToBuffer(OutBuffer& buf, bool vcg_ast, Module *m);
 const char *parametersTypeToChars(ParameterList pl);
+
+const char* toChars(const Expression* const e);
+const char* toChars(const Initializer* const i);
+const char* toChars(const Statement* const s);
+const char* toChars(const Type* const t);
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
index b4e15e3fa98..cccd3c97f2c 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -125,3 +125,4 @@ public:
 };
 
 Expression *initializerToExpression(Initializer *init, Type *t = NULL, const bool isCfile = false);
+Initializer *initializerSemantic(Initializer *init, Scope *sc, Type *&tx, NeedInterpret needInterpret);
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index c46f5600c80..4f8ed7594c7 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -444,11 +444,6 @@ extern (C++) abstract class Type : ASTNode
         return false;
     }
 
-    final bool equivalent(Type t)
-    {
-        return immutableOf(this).equals(t.immutableOf());
-    }
-
     // kludge for template.isType()
     override final DYNCAST dyncast() const
     {
@@ -1191,111 +1186,6 @@ extern (C++) abstract class Type : ASTNode
         return t;
     }
 
-    /************************************
-     * Add MODxxxx bits to existing type.
-     * We're adding, not replacing, so adding const to
-     * a shared type => "shared const"
-     */
-    final Type addMod(MOD mod)
-    {
-        /* Add anything to immutable, and it remains immutable
-         */
-        Type t = this;
-        if (!t.isImmutable())
-        {
-            //printf("addMod(%x) %s\n", mod, toChars());
-            switch (mod)
-            {
-            case 0:
-                break;
-
-            case MODFlags.const_:
-                if (isShared())
-                {
-                    if (isWild())
-                        t = this.sharedWildConstOf();
-                    else
-                        t = this.sharedConstOf();
-                }
-                else
-                {
-                    if (this.isWild())
-                        t = this.wildConstOf();
-                    else
-                        t = t.constOf();
-                }
-                break;
-
-            case MODFlags.wild:
-                if (isShared())
-                {
-                    if (isConst())
-                        t = this.sharedWildConstOf();
-                    else
-                        t = this.sharedWildOf();
-                }
-                else
-                {
-                    if (isConst())
-                        t = this.wildConstOf();
-                    else
-                        t = this.wildOf();
-                }
-                break;
-
-            case MODFlags.wildconst:
-                if (isShared())
-                    t = this.sharedWildConstOf();
-                else
-                    t = this.wildConstOf();
-                break;
-
-            case MODFlags.shared_:
-                if (isWild())
-                {
-                    if (isConst())
-                        t = this.sharedWildConstOf();
-                    else
-                        t = this.sharedWildOf();
-                }
-                else
-                {
-                    if (isConst())
-                        t = this.sharedConstOf();
-                    else
-                        t = this.sharedOf();
-                }
-                break;
-
-            case MODFlags.shared_ | MODFlags.const_:
-                if (isWild())
-                    t = this.sharedWildConstOf();
-                else
-                    t = this.sharedConstOf();
-                break;
-
-            case MODFlags.shared_ | MODFlags.wild:
-                if (isConst())
-                    t = this.sharedWildConstOf();
-                else
-                    t = this.sharedWildOf();
-                break;
-
-            case MODFlags.shared_ | MODFlags.wildconst:
-                t = this.sharedWildConstOf();
-                break;
-
-            case MODFlags.immutable_:
-                t = this.immutableOf();
-                break;
-
-            default:
-                assert(0);
-            }
-        }
-        return t;
-    }
-
     /************************************
      * Add storage class modifiers to type.
      */
@@ -1315,7 +1205,7 @@ extern (C++) abstract class Type : ASTNode
             if (stc & STC.shared_)
                 mod |= MODFlags.shared_;
         }
-        return addMod(mod);
+        return this.addMod(mod);
     }
 
     final Type pointerTo()
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index a7a41c64042..df8cc4dd6b6 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -39,7 +39,6 @@ typedef union tree_node type;
 typedef struct TYPE type;
 #endif
 
-extern const char* toChars(const Type* const t);
 Type *typeSemantic(Type *t, const Loc &loc, Scope *sc);
 Type *merge(Type *type);
 
@@ -218,7 +217,6 @@ public:
     Type *copy() const;
     virtual Type *syntaxCopy();
     bool equals(const RootObject * const o) const override;
-    bool equivalent(Type *t);
     // kludge for template.isType()
     DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
     size_t getUniqueID() const;
@@ -253,7 +251,6 @@ public:
     bool isSharedWild() const  { return (mod & (MODshared | MODwild)) == (MODshared | MODwild); }
     bool isNaked() const       { return mod == 0; }
     Type *nullAttributes() const;
-    Type *addMod(MOD mod);
     virtual Type *addStorageClass(StorageClass stc);
     Type *pointerTo();
     Type *referenceTo();
@@ -889,10 +886,10 @@ AggregateDeclaration *isAggregate(Type *t);
 bool hasPointers(Type *t);
 // return the symbol to which type t resolves
 Dsymbol *toDsymbol(Type *t, Scope *sc);
+bool equivalent(Type *src, Type *t);
 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);
 Type *merge2(Type *type);
 Type *constOf(Type *type);
 Type *immutableOf(Type *type);
@@ -905,3 +902,4 @@ Type *wildConstOf(Type *type);
 Type *sharedWildOf(Type *type);
 Type *sharedWildConstOf(Type *type);
 Type *castMod(Type *type, MOD mod);
+Type *addMod(Type *type, MOD mod);
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 0dc54ffe762..2d2e6fde323 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -8730,7 +8730,7 @@ class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 else
                 {
                     AST.Type t = parseType(); // cast( type )
-                    t = t.addMod(m); // cast( const type )
+                    t = t.addSTC(AST.ModToStc(m)); // cast( const type )
                     check(TOK.rightParenthesis);
                     e = parseUnaryExp();
                     e = new AST.CastExp(loc, e, t);
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index ee03d49eb4a..8a6bf3d0d1c 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -701,7 +701,12 @@ public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
+// in statementsem.d
+Statement* statementSemantic(Statement *s, Scope *sc);
+// in iasm.d
 Statement* asmSemantic(AsmStatement *s, Scope *sc);
+// in iasmgcc.d
+Statement *gccAsmSemantic(GccAsmStatement *s, Scope *sc);
 
 class AsmStatement : public Statement
 {
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 153eb4eb68b..c80f28bf807 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -317,6 +317,9 @@ public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
+// in templateparamsem.d
+bool tpsemantic(TemplateParameter *tp, Scope *sc, TemplateParameters *parameters);
+
 Expression *isExpression(RootObject *o);
 Dsymbol *isDsymbol(RootObject *o);
 Type *isType(RootObject *o);
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index b1ca92da4cb..19c6912eeaf 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -520,7 +520,7 @@ int mutabilityOfType(bool isref, Type t)
  * Set 'purity' field of 'typeFunction'.
  * Do this lazily, as the parameter types might be forward referenced.
  */
-extern(C++) void purityLevel(TypeFunction typeFunction)
+void purityLevel(TypeFunction typeFunction)
 {
     TypeFunction tf = typeFunction;
     if (tf.purity != PURE.fwdref)
@@ -6106,6 +6106,11 @@ extern(C++) bool isBaseOf(Type tthis, Type t, int* poffset)
     return false;
 }
 
+extern(C++) bool equivalent(Type src, Type t)
+{
+    return immutableOf(src).equals(t.immutableOf());
+}
+
 /********************************
  * Convert to 'const'.
  */
@@ -6405,6 +6410,111 @@ extern(C++) Type castMod(Type type, MOD mod)
     return t;
 }
 
+/************************************
+ * Add MODxxxx bits to existing type.
+ * We're adding, not replacing, so adding const to
+ * a shared type => "shared const"
+ */
+extern(C++) Type addMod(Type type, MOD mod)
+{
+    /* Add anything to immutable, and it remains immutable
+     */
+    Type t = type;
+    if (!t.isImmutable())
+    {
+        //printf("addMod(%x) %s\n", mod, toChars());
+        switch (mod)
+        {
+        case 0:
+            break;
+
+        case MODFlags.const_:
+            if (type.isShared())
+            {
+                if (type.isWild())
+                    t = type.sharedWildConstOf();
+                else
+                    t = type.sharedConstOf();
+            }
+            else
+            {
+                if (type.isWild())
+                    t = type.wildConstOf();
+                else
+                    t = t.constOf();
+            }
+            break;
+
+        case MODFlags.wild:
+            if (type.isShared())
+            {
+                if (type.isConst())
+                    t = type.sharedWildConstOf();
+                else
+                    t = type.sharedWildOf();
+            }
+            else
+            {
+                if (type.isConst())
+                    t = type.wildConstOf();
+                else
+                    t = type.wildOf();
+            }
+            break;
+
+        case MODFlags.wildconst:
+            if (type.isShared())
+                t = type.sharedWildConstOf();
+            else
+                t = type.wildConstOf();
+            break;
+
+        case MODFlags.shared_:
+            if (type.isWild())
+            {
+                if (type.isConst())
+                    t = type.sharedWildConstOf();
+                else
+                    t = type.sharedWildOf();
+            }
+            else
+            {
+                if (type.isConst())
+                    t = type.sharedConstOf();
+                else
+                    t = type.sharedOf();
+            }
+            break;
+
+        case MODFlags.shared_ | MODFlags.const_:
+            if (type.isWild())
+                t = type.sharedWildConstOf();
+            else
+                t = type.sharedConstOf();
+            break;
+
+        case MODFlags.shared_ | MODFlags.wild:
+            if (type.isConst())
+                t = type.sharedWildConstOf();
+            else
+                t = type.sharedWildOf();
+            break;
+
+        case MODFlags.shared_ | MODFlags.wildconst:
+            t = type.sharedWildConstOf();
+            break;
+
+        case MODFlags.immutable_:
+            t = type.immutableOf();
+            break;
+
+        default:
+            assert(0);
+        }
+    }
+    return t;
+}
+
 /******************************* Private *****************************************/
 
 private:
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 4e14b158bea..af9aad8a412 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -144,7 +144,7 @@ same_type_p (Type *t1, Type *t2)
     return true;
 
   /* Types are mutably the same type.  */
-  if (tb1->ty == tb2->ty && tb1->equivalent (tb2))
+  if (tb1->ty == tb2->ty && equivalent (tb1, tb2))
     return true;
 
   return false;
diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d
index a980ace2177..c12506f2939 100644
--- a/gcc/testsuite/gdc.test/compilable/commontype.d
+++ b/gcc/testsuite/gdc.test/compilable/commontype.d
@@ -413,12 +413,12 @@ static assert(is( X!( C, immutable(B) ) == const(B) ));
 static assert(is( X!( C, immutable(D) ) == const(B) ));
 static assert(is( X!( C, immutable(K) ) == const(Object) ));
 
-static assert(Error!( C, immutable(SC) )); // should work
-static assert(Error!( C, immutable(SI) )); // should work
-static assert(Error!( immutable(SI), C )); // should work
-static assert(Error!( C, immutable(SB) )); // should work
-static assert(Error!( C, immutable(SD) )); // should work
-static assert(Error!( C, immutable(SK) )); // should work
+static assert(is( X!( C, immutable(SC)) == const(B) ));
+static assert(is( X!( C, immutable(SI) ) == const(I) ));
+static assert(is( X!( immutable(SI), C ) == const(I) ));
+static assert(is( X!( C, immutable(SB) ) == const(Object) ));
+static assert(is( X!( C, immutable(SD) ) == const(B) ));
+static assert(is( X!( C, immutable(SK) ) == const(Object) ));
 
 static assert(is( X!( const(C), C ) == const(C) ));
 static assert(is( X!( const(C), I ) == const(I) ));
@@ -427,11 +427,11 @@ static assert(is( X!( const(C), D ) == const(B) ));
 static assert(is( X!( const(C), K ) == const(Object) ));
 
 static assert(is( X!( const(C), SC ) == const(C)));
-static assert(Error!( const(C), SI )); // should work
-static assert(is( X!( const(SI), const(C) ) == const(I) )); // should work
-static assert(is( X!( const(C), SB ) == const(B)));
+static assert(is( X!( const(C), SI ) == const(I)));
+static assert(is( X!( const(SI), const(C) ) == const(I) ));
+static assert(is( X!( const(C), SB ) == const(Object)));
 static assert(is( X!( const(C), SD ) == const(B)));
-static assert(is( X!( const(C), SK ) == Object)); // `const`
+static assert(is( X!( const(C), SK ) == const(Object)));
 
 static assert(is( X!( SiC, SC ) == const(C) ));
 
diff --git a/gcc/testsuite/gdc.test/compilable/test3543.d b/gcc/testsuite/gdc.test/compilable/test3543.d
new file mode 100644
index 00000000000..9a72ca9dda5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test3543.d
@@ -0,0 +1,80 @@
+
+// https://issues.dlang.org/show_bug.cgi?id=3543
+
+// merge with commontype.d?
+
+void testi(bool bla)
+{
+    interface Root { }
+    interface A : Root { }
+    interface B : Root { }
+    A a;
+    B b;
+    Root r = bla ? a : b;
+    static assert(is(typeof(r) == Root));
+    Root[] t = [a, b];
+    static assert(is(typeof(t[0]) == Root));
+}
+
+void testc(bool bla)
+{
+    class Root { }
+    class A : Root { }
+    class B : Root { }
+    A a;
+    B b;
+    Root r = bla ? a : b;
+    static assert(is(typeof(r) == Root));
+    Root[] t = [a, b];
+    static assert(is(typeof(t[0]) == Root));
+}
+
+void teste(bool bla)
+{
+    interface Root { }
+    interface Othe { }
+    interface A : Root, Othe { }
+    interface B : Root, Othe { }
+    A a;
+    B b;
+    static assert(!__traits(compiles, bla ? a : b));
+}
+
+void testf(bool bla)
+{
+    interface Othe { }
+    interface Root : Othe { }
+    interface A : Root { }
+    interface B : Othe { }
+    A a;
+    B b;
+    Othe r = bla ? a : b;
+}
+
+void testg()
+{
+    interface A{}
+    interface B{}
+
+    interface C:A{}
+    interface D:B,C{}
+
+    interface E:B{}
+    interface F:A,E{}
+
+    D d;
+    F f;
+    static assert(!__traits(compiles, true ? d : f));
+    static assert(!__traits(compiles, true ? f : d));
+}
+
+void testh()
+{
+    interface I {}
+    class B {}
+    class C : B, I {}
+    class D : B {}
+    C c;
+    D d;
+    auto b = true ? c : d;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/mangle.d b/gcc/testsuite/gdc.test/runnable/mangle.d
index 6e8f2b28987..53d76480997 100644
--- a/gcc/testsuite/gdc.test/runnable/mangle.d
+++ b/gcc/testsuite/gdc.test/runnable/mangle.d
@@ -1,6 +1,7 @@
 // PERMUTE_ARGS:
 // EXTRA_SOURCES: imports/mangle10077.d
 // EXTRA_FILES: imports/testmangle.d
+// UNICODE_NAMES:
 /*
 TEST_OUTPUT:
 ---
diff --git a/gcc/testsuite/gdc.test/runnable/testmodule.d b/gcc/testsuite/gdc.test/runnable/testmodule.d
index 45da7d1659d..4e1068c8938 100644
--- a/gcc/testsuite/gdc.test/runnable/testmodule.d
+++ b/gcc/testsuite/gdc.test/runnable/testmodule.d
@@ -1,4 +1,5 @@
 // PERMUTE_ARGS:
+// UNICODE_NAMES:
 
 // $HeadURL$
 // $Date$
@@ -11,6 +12,7 @@
 
 module run.unicode_06_哪里;
 
+//UTF-8 chars
 int 哪里(int ö){
         return ö+2;
 }
diff --git a/gcc/testsuite/gdc.test/runnable/ufcs.d b/gcc/testsuite/gdc.test/runnable/ufcs.d
index 8fd7bb2fba2..6328a5b380c 100644
--- a/gcc/testsuite/gdc.test/runnable/ufcs.d
+++ b/gcc/testsuite/gdc.test/runnable/ufcs.d
@@ -1,4 +1,5 @@
 // EXTRA_SOURCES: imports/ufcs5a.d imports/ufcs5b.d imports/ufcs5c.d imports/ufcs5d.d imports/ufcs5e.d
+// UNICODE_NAMES:
 
 module ufcs;
 
@@ -677,6 +678,7 @@ void test8453()
 /*******************************************/
 // https://issues.dlang.org/show_bug.cgi?id=8503
 
+//UTF-8 chars
 void α8503(int i) {}
 
 void test8503()
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 57ac2dc69e7..74c194508f7 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-a6f10836997d0b5526c8c363d781b4029c77f09f
+11240a96635074b2f79d908b9348e9c0fbc3c7dc
 
 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/demangle.d b/libphobos/libdruntime/core/demangle.d
index 5a6ad6f5cf5..272ee1e1ba4 100644
--- a/libphobos/libdruntime/core/demangle.d
+++ b/libphobos/libdruntime/core/demangle.d
@@ -79,17 +79,6 @@ pure @safe:
     AddType         addType = AddType.yes;
     bool            mute    = false;
     Hooks           hooks;
-    bool hasErrors = false;
-
-    /// Called when encountering an error / unrecognized mangle.
-    ///
-    /// Currently, errors simply make `demangle` return
-    /// the input string, but the `msg` string can be used for debugging.
-    /// As a future enhancement, error handlers can be supplied through `Hooks`
-    void error(string msg = "error")
-    {
-        hasErrors = true;
-    }
 
     //////////////////////////////////////////////////////////////////////////
     // Type Testing and Conversion
@@ -733,7 +722,7 @@ pure @safe:
     TypeTuple:
         B Number Arguments
     */
-    BufSlice parseType() return scope nothrow
+    BufSlice parseType(out bool errStatus) return scope nothrow
     {
         static immutable string[23] primitives = [
             "char", // a
@@ -763,8 +752,8 @@ pure @safe:
 
         static if (__traits(hasMember, Hooks, "parseType"))
         {
-            auto n = hooks.parseType(this, null);
-            if (this.hasErrors)
+            auto n = hooks.parseType(errStatus, this, null);
+            if (errStatus)
                 return dst.bslice_empty;
             else
                 if (n !is null)
@@ -776,11 +765,11 @@ pure @safe:
         auto beg = dst.length;
         auto t = front;
 
-        BufSlice parseBackrefType(scope BufSlice delegate() pure @safe nothrow parseDg) pure @safe nothrow
+        BufSlice parseBackrefType(out string errStatus, scope BufSlice delegate(bool err_flag) pure @safe nothrow parseDg) pure @safe nothrow
         {
             if (pos == brp)
             {
-                this.error("recursive back reference");
+                errStatus = "recursive back reference";
                 return dst.bslice_empty;
             }
 
@@ -789,7 +778,7 @@ pure @safe:
             auto n = decodeBackref();
             if (n == 0 || n > pos)
             {
-                this.error("invalid back reference");
+                errStatus = "invalid back reference";
                 return dst.bslice_empty;
             }
 
@@ -801,31 +790,44 @@ pure @safe:
             pos = refPos - n;
             brp = refPos;
 
-            auto ret = parseDg();
+            bool err_flag;
+            auto ret = parseDg(err_flag);
+            if (err_flag)
+            {
+                errStatus = "parseDg error";
+                return dst.bslice_empty;
+            }
+
             return ret;
         }
 
+        // call parseType() and return error if occured
+        enum parseTypeOrF = "parseType(errStatus); if (errStatus) return dst.bslice_empty;";
+
         switch ( t )
         {
         case 'Q': // Type back reference
-            auto r = parseBackrefType(() => parseType());
+            string errMsg;
+            auto r = parseBackrefType(errMsg, (e_flag) => parseType(e_flag));
+            if (errMsg !is null)
+                return dst.bslice_empty;
             return r;
         case 'O': // Shared (O Type)
             popFront();
             put( "shared(" );
-            parseType();
+            mixin(parseTypeOrF);
             put( ')' );
             return dst[beg .. $];
         case 'x': // Const (x Type)
             popFront();
             put( "const(" );
-            parseType();
+            mixin(parseTypeOrF);
             put( ')' );
             return dst[beg .. $];
         case 'y': // Immutable (y Type)
             popFront();
             put( "immutable(" );
-            parseType();
+            mixin(parseTypeOrF);
             put( ')' );
             return dst[beg .. $];
         case 'N':
@@ -840,28 +842,28 @@ pure @safe:
                 popFront();
                 // TODO: Anything needed here?
                 put( "inout(" );
-                parseType();
+                mixin(parseTypeOrF);
                 put( ')' );
                 return dst[beg .. $];
             case 'h': // TypeVector (Nh Type)
                 popFront();
                 put( "__vector(" );
-                parseType();
+                mixin(parseTypeOrF);
                 put( ')' );
                 return dst[beg .. $];
             default:
-                error();
+                errStatus = true;
                 return dst.bslice_empty;
             }
         case 'A': // TypeArray (A Type)
             popFront();
-            parseType();
+            mixin(parseTypeOrF);
             put( "[]" );
             return dst[beg .. $];
         case 'G': // TypeStaticArray (G Number Type)
             popFront();
             auto num = sliceNumber();
-            parseType();
+            mixin(parseTypeOrF);
             put( '[' );
             put( num );
             put( ']' );
@@ -869,34 +871,29 @@ pure @safe:
         case 'H': // TypeAssocArray (H Type Type)
             popFront();
             // skip t1
-            auto tx = parseType();
-            if (this.hasErrors)
+            auto tx = parseType(errStatus);
+            if (errStatus)
                 return dst.bslice_empty;
-            parseType();
+            mixin(parseTypeOrF);
             put( '[' );
             shift(tx);
             put( ']' );
             return dst[beg .. $];
         case 'P': // TypePointer (P Type)
             popFront();
-            parseType();
+            mixin(parseTypeOrF);
             put( '*' );
             return dst[beg .. $];
         case 'F': case 'U': case 'W': case 'V': case 'R': // TypeFunction
-            bool errStatus;
             auto r = parseTypeFunction(errStatus);
             if (errStatus)
-            {
-                error();
                 return dst.bslice_empty;
-            }
             return r;
         case 'C': // TypeClass (C LName)
         case 'S': // TypeStruct (S LName)
         case 'E': // TypeEnum (E LName)
         case 'T': // TypeTypedef (T LName)
             popFront();
-            bool errStatus;
             parseQualifiedName(errStatus);
             if (errStatus)
                 return dst.bslice_empty;
@@ -906,20 +903,16 @@ pure @safe:
             auto modifiers = parseModifier();
             if ( front == 'Q' )
             {
-                bool errStatus;
-                auto r = parseBackrefType(() => parseTypeFunction(errStatus, IsDelegate.yes));
-                if (errStatus)
-                {
-                    error();
+                string errMsg;
+                auto r = parseBackrefType(errMsg, (e_flag) => parseTypeFunction(e_flag, IsDelegate.yes));
+                if (errMsg !is null)
                     return dst.bslice_empty;
-                }
                 return r;
             }
             else
             {
-                bool errStatus;
                 parseTypeFunction(errStatus, IsDelegate.yes);
-                if (this.hasErrors || errStatus)
+                if (errStatus)
                     return dst.bslice_empty;
             }
 
@@ -972,11 +965,11 @@ pure @safe:
                     put( "ucent" );
                     return dst[beg .. $];
                 default:
-                    error("unknown type");
+                    errStatus = true;
                     return dst.bslice_empty;
                 }
             }
-            error("unknown type");
+            errStatus = true;
             return dst.bslice_empty;
         }
     }
@@ -1289,6 +1282,9 @@ pure @safe:
                     pos--;
             }
 
+            // call parseType() and return error if occured
+            enum parseTypeOrF = "parseType(errStatus); if (errStatus) return;";
+
             switch ( front )
             {
             case 'I': // in  (I Type)
@@ -1296,25 +1292,25 @@ pure @safe:
                 put("in ");
                 if (front == 'K')
                     goto case;
-                parseType();
+                mixin(parseTypeOrF);
                 continue;
             case 'K': // ref (K Type)
                 popFront();
                 put( "ref " );
-                parseType();
+                mixin(parseTypeOrF);
                 continue;
             case 'J': // out (J Type)
                 popFront();
                 put( "out " );
-                parseType();
+                mixin(parseTypeOrF);
                 continue;
             case 'L': // lazy (L Type)
                 popFront();
                 put( "lazy " );
-                parseType();
+                mixin(parseTypeOrF);
                 continue;
             default:
-                parseType();
+                mixin(parseTypeOrF);
             }
         }
     }
@@ -1361,8 +1357,8 @@ pure @safe:
         // e.g. `delegate(int) @safedouble ' => 'double delegate(int) @safe'
         {
             auto retbeg = dst.length;
-            parseType();
-            if (this.hasErrors)
+            parseType(errStatus);
+            if (errStatus)
                 return dst.bslice_empty;
             put(' ');
             shift(dst[argbeg .. retbeg]);
@@ -1576,9 +1572,7 @@ pure @safe:
             // f MangledName
             // A function literal symbol
             popFront();
-            parseMangledName(false, 1);
-            if (this.hasErrors)
-                errStatus = true;
+            parseMangledName(errStatus, false, 1);
             return;
         default:
             errStatus = true;
@@ -1716,12 +1710,9 @@ pure @safe:
             case 'T':
                 popFront();
                 putComma(n);
-                parseType();
-                if (this.hasErrors)
-                {
-                    errStatus = true;
+                parseType(errStatus);
+                if (errStatus)
                     return;
-                }
                 continue;
             case 'V':
                 popFront();
@@ -1742,7 +1733,7 @@ pure @safe:
                     }
                 }
                 BufSlice name = dst.bslice_empty;
-                silent( errStatus, delegate void(out bool e_flg) nothrow { name = parseType(); } );
+                silent( errStatus, delegate void(out bool e_flg) nothrow { name = parseType(e_flg); } );
                 if (errStatus)
                     return;
                 parseValue( errStatus, name, t );
@@ -1857,20 +1848,20 @@ pure @safe:
         debug(trace) printf( "parseMangledNameArg+\n" );
         debug(trace) scope(success) printf( "parseMangledNameArg-\n" );
 
+        bool errStatus;
+
         size_t n = 0;
         if ( isDigit( front ) )
         {
-            bool errStatus;
             n = decodeNumber(errStatus);
+
             if (errStatus)
-            {
-                error();
                 return false;
-            }
         }
 
-        parseMangledName(false, n);
-        return !this.hasErrors;
+        parseMangledName(errStatus, false, n );
+
+        return !errStatus;
     }
 
     /*
@@ -2091,7 +2082,7 @@ pure @safe:
         _D QualifiedName Type
         _D QualifiedName M Type
     */
-    void parseMangledName(bool displayType, size_t n = 0 ) scope nothrow
+    void parseMangledName( out bool errStatus, bool displayType, size_t n = 0 ) scope nothrow
     {
         debug(trace) printf( "parseMangledName+\n" );
         debug(trace) scope(success) printf( "parseMangledName-\n" );
@@ -2100,8 +2091,9 @@ pure @safe:
         auto end = pos + n;
 
         eat( '_' );
-        if (!match('D'))
-            return error();
+        errStatus = !match( 'D' );
+        if (errStatus)
+            return;
 
         do
         {
@@ -2117,17 +2109,16 @@ pure @safe:
                 if (beg != dst.length)
                     put( '.' );
 
-                bool errStatus;
                 parseSymbolName(errStatus);
                 if (errStatus)
-                    return error();
+                    return;
 
                 nameEnd = dst.length;
                 attr = parseFunctionTypeNoReturn( displayType );
 
                 is_sym_name_front = isSymbolNameFront(errStatus);
                 if (errStatus)
-                    return error();
+                    return;
             } while (is_sym_name_front);
 
             if ( displayType )
@@ -2142,8 +2133,8 @@ pure @safe:
                 popFront(); // has 'this' pointer
 
             auto lastlen = dst.length;
-            auto type = parseType();
-            if (this.hasErrors)
+            auto type = parseType(errStatus);
+            if (errStatus)
                 return;
 
             if ( displayType )
@@ -2176,9 +2167,9 @@ pure @safe:
         } while ( true );
     }
 
-    void parseMangledName() nothrow
+    void parseMangledName(out bool errStatus) nothrow
     {
-        parseMangledName(AddType.yes == addType);
+        parseMangledName(errStatus, AddType.yes == addType);
     }
 
     char[] doDemangle(alias FUNC)() return scope nothrow
@@ -2187,8 +2178,9 @@ pure @safe:
         {
             debug(info) printf( "demangle(%.*s)\n", cast(int) buf.length, buf.ptr );
 
-            FUNC();
-            if (!this.hasErrors)
+            bool errStatus;
+            FUNC(errStatus);
+            if (!errStatus)
             {
                 return dst[0 .. $].getSlice;
             }
@@ -2387,9 +2379,8 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
             return true;
         }
 
-        char[] parseType(ref Remangle d, char[] name) return scope nothrow
+        char[] parseType( out bool errStatus, ref Remangle d, char[] name ) return scope nothrow
         {
-            bool errStatus;
             if (d.front != 'Q')
                 return null;
 
@@ -2400,7 +2391,8 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
             auto n = d.decodeBackref();
             if (n == 0 || n > refPos)
             {
-                d.error("invalid back reference");
+                // invalid back reference
+                errStatus = true;
                 return null;
             }
 
@@ -2436,7 +2428,7 @@ char[] reencodeMangled(return scope const(char)[] mangled) nothrow pure @safe
 
     bool errStatus;
     d.parseMangledName(errStatus);
-    if (d.hasErrors)
+    if (errStatus)
     {
         // error cannot occur
         return mangled.dup;
diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d
index 03d1c017c07..6242d76ba30 100644
--- a/libphobos/libdruntime/core/internal/atomic.d
+++ b/libphobos/libdruntime/core/internal/atomic.d
@@ -609,7 +609,7 @@ else version (GNU)
     import gcc.builtins;
     import gcc.config;
 
-    enum IsAtomicLockFree(T) = __atomic_is_lock_free(T.sizeof, null);
+    enum IsAtomicLockFree(T) = __traits(compiles, { enum E = __atomic_is_lock_free(T.sizeof, null); });
 
     inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
         if (CanCAS!T)
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index 73fe087861a..56433b49302 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -4941,6 +4941,7 @@ unittest
 // improve predictability of coverage of code that is eventually not hit by other tests
 debug (SENTINEL) {} else // cannot extend with SENTINEL
 debug (MARK_PRINTF) {} else // takes forever
+version (OnlyLowMemUnittests) {} else
 unittest
 {
     import core.memory;
@@ -4988,24 +4989,34 @@ 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(true));
-        if (os_physical_mem(true) > sz)
+        size_t phys_mem = os_physical_mem(true);
+        if (phys_mem > sz)
         {
             import core.memory;
+            import core.exception;
             GC.collect();
             GC.minimize();
-            auto stats = GC.stats();
-            auto ptr = GC.malloc(sz, BlkAttr.NO_SCAN);
-            auto info = GC.query(ptr);
-            //printf("info.size = %lld", info.size);
-            assert(info.size >= sz);
-            GC.free(ptr);
-            GC.minimize();
-            auto nstats = GC.stats();
-            assert(nstats.usedSize == stats.usedSize);
-            assert(nstats.freeSize == stats.freeSize);
-            assert(nstats.allocatedInCurrentThread - sz == stats.allocatedInCurrentThread);
+            try
+            {
+                auto stats = GC.stats();
+                auto ptr = GC.malloc(sz, BlkAttr.NO_SCAN);
+                auto info = GC.query(ptr);
+                //printf("info.size = %lld", info.size);
+                assert(info.size >= sz);
+                GC.free(ptr);
+                GC.minimize();
+                auto nstats = GC.stats();
+                assert(nstats.usedSize == stats.usedSize);
+                assert(nstats.freeSize == stats.freeSize);
+                assert(nstats.allocatedInCurrentThread - sz == stats.allocatedInCurrentThread);
+            }
+            catch (OutOfMemoryError)
+            {
+                // ignore if the system still doesn't have enough virtual memory
+                import core.stdc.stdio;
+                printf("%s(%d): out-of-memory execption ignored, phys_mem = %zd",
+                       __FILE__.ptr, __LINE__, phys_mem);
+            }
         }
     }
 }
diff --git a/libphobos/libdruntime/core/internal/qsort.d b/libphobos/libdruntime/core/internal/qsort.d
index ad8307a2523..ada914c9ef4 100644
--- a/libphobos/libdruntime/core/internal/qsort.d
+++ b/libphobos/libdruntime/core/internal/qsort.d
@@ -132,6 +132,7 @@ else
 
 unittest
 {
+    debug(qsort) import core.stdc.stdio;
     debug(qsort) printf("array.sort.unittest()\n");
 
     int[] a = new int[10];
@@ -151,8 +152,8 @@ unittest
 
     for (int i = 0; i < a.length - 1; i++)
     {
-        //printf("i = %d", i);
-        //printf(" %d %d\n", a[i], a[i + 1]);
+        debug(qsort) printf("i = %d", i);
+        debug(qsort) printf(" %d %d\n", a[i], a[i + 1]);
         assert(a[i] <= a[i + 1]);
     }
 }
diff --git a/libphobos/libdruntime/core/memory.d b/libphobos/libdruntime/core/memory.d
index f2a48f9a3ae..239d23ff01d 100644
--- a/libphobos/libdruntime/core/memory.d
+++ b/libphobos/libdruntime/core/memory.d
@@ -575,6 +575,7 @@ extern(C):
 
     // https://issues.dlang.org/show_bug.cgi?id=13111
     ///
+    version (OnlyLowMemUnittests) {} else // Test needs a lot of RAM
     unittest
     {
         enum size1 = 1 << 11 + 1; // page in large object pool
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 93902439fbf..295ca52e350 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -2103,6 +2103,8 @@ private extern (D) void resume(ThreadBase _t) nothrow @nogc
             t.m_curr.tstack = t.m_curr.bstack;
         }
     }
+    else
+        static assert(false, "Platform not supported.");
 }
 
 
diff --git a/libphobos/libdruntime/core/time.d b/libphobos/libdruntime/core/time.d
index be941e2abcd..c3192fc39f9 100644
--- a/libphobos/libdruntime/core/time.d
+++ b/libphobos/libdruntime/core/time.d
@@ -2584,6 +2584,8 @@ extern(C) void _d_initMonoTime() @nogc nothrow
             }
         }
     }
+    else
+        static assert(0, "Unsupported platform");
 }
 
 
@@ -2883,6 +2885,8 @@ deprecated:
             else
                 ticksPerSec = 1_000_000;
         }
+        else
+            static assert(0, "Unsupported platform");
 
         if (ticksPerSec != 0)
             appOrigin = TickDuration.currSystemTick;
diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d
index 36f25554db3..5903d9cd754 100644
--- a/libphobos/libdruntime/rt/aaA.d
+++ b/libphobos/libdruntime/rt/aaA.d
@@ -437,6 +437,7 @@ unittest
         string[412] names;
         ubyte[1024] moredata;
     }
+    version (OnlyLowMemUnittests) {} else
     test!(Large, Large);
 }
 
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 8ce2d564bd6..4a071f3d81b 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -2247,6 +2247,7 @@ unittest
         assert(GC.getAttr(p) == BlkAttr.NO_SCAN);
     }
     test(16);
+    version (OnlyLowMemUnittests) {} else
     test(1024 * 1024);
 }
 
