diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 233342aab015a985908ce2be4bec79875a00316f..a0545d66c1c420e2fb17136611eac6238a247d2f 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -140,7 +140,7 @@ build_frontend_type (tree type)
 
 	  /* Search for type matching size and signedness.  */
 	  if (unsignedp != dtype->isunsigned ()
-	      || size != dtype->size ())
+	      || size != dmd::size (dtype))
 	    continue;
 
 	  return dmd::addMod (dtype, mod);
@@ -157,7 +157,7 @@ build_frontend_type (tree type)
 	  dtype = Type::basic[i];
 
 	  /* Search for type matching size.  */
-	  if (dtype->size () != size)
+	  if (dmd::size (dtype) != size)
 	    continue;
 
 	  return dmd::addMod (dtype, mod);
@@ -174,7 +174,7 @@ build_frontend_type (tree type)
 	  dtype = Type::basic[i];
 
 	  /* Search for type matching size.  */
-	  if (dtype->size () != size)
+	  if (dmd::size (dtype) != size)
 	    continue;
 
 	  return dmd::addMod (dtype, mod);
@@ -215,7 +215,7 @@ build_frontend_type (tree type)
 	break;
 
       dtype = dmd::addMod (dmd::sarrayOf (dtype, nunits), mod);
-      if (target.isVectorTypeSupported (dtype->size (), dtype->nextOf ()))
+      if (target.isVectorTypeSupported (dmd::size (dtype), dtype->nextOf ()))
 	break;
 
       dtype = dmd::addMod (TypeVector::create (dtype), mod);
@@ -712,11 +712,11 @@ matches_builtin_type (Type *t1, Type *t2)
 
   if (((tb1->isTypePointer () && tb2->isTypePointer ())
        || (tb1->isTypeVector () && tb2->isTypeVector ()))
-      && tb1->implicitConvTo (tb2) != MATCH::nomatch)
+      && dmd::implicitConvTo (tb1, tb2) != MATCH::nomatch)
     return true;
 
   if (tb1->isintegral () == tb2->isintegral ()
-      && tb1->size () == tb2->size ())
+      && dmd::size (tb1) == dmd::size (tb2))
     return true;
 
   return false;
diff --git a/gcc/d/d-codegen.cc b/gcc/d/d-codegen.cc
index 2ccd8f90a92c9d7226d14bb0713ebcbe6b962b87..5c9d01d8f018119e25a7be8223d86ea11cc13194 100644
--- a/gcc/d/d-codegen.cc
+++ b/gcc/d/d-codegen.cc
@@ -904,7 +904,7 @@ identity_compare_p (StructDeclaration *sd)
 	  if (offset != vd->offset)
 	    return false;
 
-	  offset += vd->type->size ();
+	  offset += dmd::size (vd->type);
 	}
     }
 
@@ -2128,7 +2128,7 @@ call_side_effect_free_p (FuncDeclaration *func, Type *type)
 	return false;
 
       /* Only consider it as `pure' if it can't modify its arguments.  */
-      if (func->isPure () == PURE::const_)
+      if (dmd::isPure (func) == PURE::const_)
 	return true;
     }
 
diff --git a/gcc/d/d-convert.cc b/gcc/d/d-convert.cc
index 1e15c037916ba94ee9edfb3cc4e7f66772a24c36..e996c91d344e568d4b6dda389840f9a7fd11e5cb 100644
--- a/gcc/d/d-convert.cc
+++ b/gcc/d/d-convert.cc
@@ -384,7 +384,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
     case TY::Tstruct:
       if (tbtype->ty == TY::Tstruct)
 	{
-	  if (totype->size () == etype->size ())
+	  if (dmd::size (totype) == dmd::size (etype))
 	    {
 	      /* Allowed to cast to structs with same type size.  */
 	      result = build_vconvert (build_ctype (totype), exp);
@@ -467,8 +467,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
       else if (tbtype->ty == TY::Tarray)
 	{
 	  dinteger_t dim = ebtype->isTypeSArray ()->dim->toInteger ();
-	  dinteger_t esize = ebtype->nextOf ()->size ();
-	  dinteger_t tsize = tbtype->nextOf ()->size ();
+	  dinteger_t esize = dmd::size (ebtype->nextOf ());
+	  dinteger_t tsize = dmd::size (tbtype->nextOf ());
 
 	  tree ptrtype = build_ctype (dmd::pointerTo (tbtype->nextOf ()));
 
@@ -498,10 +498,11 @@ convert_expr (tree exp, Type *etype, Type *totype)
 	{
 	  /* And allows casting a static array to any struct type too.
 	     Type sizes should have already been checked by the frontend.  */
-	  gcc_assert (totype->size () == etype->size ());
+	  gcc_assert (dmd::size (totype) == dmd::size (etype));
 	  result = build_vconvert (build_ctype (totype), exp);
 	}
-      else if (tbtype->ty == TY::Tvector && tbtype->size () == ebtype->size ())
+      else if (tbtype->ty == TY::Tvector
+	       && dmd::size (tbtype) == dmd::size (ebtype))
 	{
 	  /* Allow casting from array to vector as if its an unaligned load.  */
 	  tree type = build_ctype (totype);
@@ -526,8 +527,8 @@ convert_expr (tree exp, Type *etype, Type *totype)
       else if (tbtype->ty == TY::Tarray)
 	{
 	  /* Assume tvoid->size() == 1.  */
-	  dinteger_t fsize = ebtype->nextOf ()->toBasetype ()->size ();
-	  dinteger_t tsize = tbtype->nextOf ()->toBasetype ()->size ();
+	  dinteger_t fsize = dmd::size (ebtype->nextOf ()->toBasetype ());
+	  dinteger_t tsize = dmd::size (tbtype->nextOf ()->toBasetype ());
 
 	  if (fsize != tsize)
 	    {
@@ -594,7 +595,7 @@ convert_expr (tree exp, Type *etype, Type *totype)
     case TY::Tvector:
       if (tbtype->ty == TY::Tsarray)
 	{
-	  if (tbtype->size () == ebtype->size ())
+	  if (dmd::size (tbtype) == dmd::size (ebtype))
 	    return build_vconvert (build_ctype (totype), exp);
 	}
       break;
@@ -740,7 +741,7 @@ check_valist_conversion (Expression *expr, Type *totype, bool in_assignment)
 	      && valist_array_p (decl->type));
 
   /* OK if conversion between types is allowed.  */
-  if (type->implicitConvTo (totype) != MATCH::nomatch)
+  if (dmd::implicitConvTo (type, totype) != MATCH::nomatch)
     return;
 
   if (in_assignment)
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index f642248055813be57024a3a9a8d3aa558a42e183..b6724c3afbcf364c704be9012b14de9204a3b850 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -1709,8 +1709,8 @@ d_types_compatible_p (tree x, tree y)
 	return true;
 
       /* Type system allows implicit conversion between.  */
-      if (tx->implicitConvTo (ty) != MATCH::nomatch
-	  || ty->implicitConvTo (tx) != MATCH::nomatch)
+      if (dmd::implicitConvTo (tx, ty) != MATCH::nomatch
+	  || dmd::implicitConvTo (ty, tx) != MATCH::nomatch)
 	return true;
     }
 
diff --git a/gcc/d/d-target.cc b/gcc/d/d-target.cc
index 83775347d36c7ffa6f139b6807465282d38ede79..07131f4095feb048b428d83318ccc18610a6ae0d 100644
--- a/gcc/d/d-target.cc
+++ b/gcc/d/d-target.cc
@@ -280,7 +280,7 @@ Target::isVectorTypeSupported (int sz, Type *type)
   /* In [simd/vector extensions], which vector types are supported depends on
      the target.  The implementation is expected to only support the vector
      types that are implemented in the target's hardware.  */
-  unsigned HOST_WIDE_INT nunits = sz / type->size ();
+  unsigned HOST_WIDE_INT nunits = sz / dmd::size (type);
   tree ctype = build_vector_type (build_ctype (type), nunits);
 
   if (!targetm.vector_mode_supported_p (TYPE_MODE (ctype)))
@@ -453,7 +453,7 @@ Target::isReturnOnStack (TypeFunction *tf, bool)
     return false;
 
   Type *tn = tf->next->toBasetype ();
-  if (tn->size () == SIZE_INVALID)
+  if (dmd::size (tn) == SIZE_INVALID)
     return false;
 
   return (tn->ty == TY::Tstruct || tn->ty == TY::Tsarray);
@@ -583,7 +583,7 @@ Target::preferPassByRef (Type *param_type)
 {
   /* See note in Target::isReturnOnStack.  */
   Type *tb = param_type->toBasetype ();
-  if (tb->size () == SIZE_INVALID)
+  if (dmd::size (tb) == SIZE_INVALID)
     return false;
 
   return (tb->ty == TY::Tstruct || tb->ty == TY::Tsarray);
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index fa9c429a7ce10c9fa1780c81443fe061b6d4d9ed..6f1be64ba042756b0371d4ead37dcfc04469b968 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -803,7 +803,7 @@ public:
 	  return;
 
 	/* How big a symbol can be should depend on back-end.  */
-	tree size = build_integer_cst (d->type->size (d->loc),
+	tree size = build_integer_cst (dmd::size (d->type, d->loc),
 				       build_ctype (Type::tsize_t));
 	if (!valid_constant_size_p (size))
 	  {
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 77e8562abcc346f344c4d264393c1bce0f9dd798..d458bea5e1a593bfcd3455a9fe99cdc29f4c5b09 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@
-07bc5b9b3c81cc0d4314e0040de981124b363ea5
+66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/README.md b/gcc/d/dmd/README.md
index baac0d79b30d975385373a7d18fac21ed81f2946..078759431515ad79f2e4b2d3a2157f62a912a9f7 100644
--- a/gcc/d/dmd/README.md
+++ b/gcc/d/dmd/README.md
@@ -251,6 +251,8 @@ Note that these groups have no strict meaning, the category assignments are a bi
 | [hdrgen.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/hdrgen.d) | Convert an AST into D source code for `.di` header generation, as well as `-vcg-ast` and error messages |
 | [json.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/json.d)     | Describe the module in a `.json` file for the `-X` flag                                                 |
 | [dtoh.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/dtoh.d)     | C++ header generation from D source files                                                               |
+| [disasm86.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/disasm86.d)       | x86-64 dissassembly generation
+| [disasmarm.d](https://github.com/dlang/dmd/blob/master/compiler/src/dmd/backend/arm/disasmarm.d) | AArch64 disassembly generation
 
 ### Utility
 
diff --git a/gcc/d/dmd/VERSION b/gcc/d/dmd/VERSION
index 3d80c3d19134c2b48cc52e74a31a7ab6602293d8..ffc1c3e86dfacfcd9c22c09e361b073286358f7e 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@
-v2.109.0
+v2.109.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 2c7622a9aa016c0ec389022621856ffdc47ce49d..78cb87f2fe7d9b772bc950c9aa0d0da733e9063a 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, addMod;
+import dmd.typesem : defaultInit, addMod, size;
 import dmd.visitor;
 
 /**
diff --git a/gcc/d/dmd/arrayop.d b/gcc/d/dmd/arrayop.d
index d0ec5ebcdbe91db144c3be6ff795b1013444f3ef..e30160d72b92e04bc3c8fd37831009e993fe2b3c 100644
--- a/gcc/d/dmd/arrayop.d
+++ b/gcc/d/dmd/arrayop.d
@@ -16,6 +16,7 @@ module dmd.arrayop;
 import core.stdc.stdio;
 import dmd.arraytypes;
 import dmd.astenums;
+import dmd.dcast : implicitConvTo;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/chkformat.d b/gcc/d/dmd/chkformat.d
index 5024f9bb210038245eca36bd416a63e8f5fe2cd9..bbc7b867c5531087972a039199e9f83c879c5036 100644
--- a/gcc/d/dmd/chkformat.d
+++ b/gcc/d/dmd/chkformat.d
@@ -21,6 +21,7 @@ import dmd.globals;
 import dmd.identifier;
 import dmd.location;
 import dmd.mtype;
+import dmd.typesem;
 import dmd.target;
 
 
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2e4833e8fdd7477faf0623d4e922a5b4b0a11f49..17b33d839df82abf7d94a4c1a892752bd6dd1425 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -57,7 +57,7 @@ StorageClass mergeFuncAttrs(StorageClass s1, const FuncDeclaration f) pure
         return s1;
     StorageClass s2 = (f.storage_class & STC.disable);
 
-    TypeFunction tf = cast(TypeFunction)f.type;
+    auto tf = cast(TypeFunction)f.type;
     if (tf.trust == TRUST.safe)
         s2 |= STC.safe;
     else if (tf.trust == TRUST.system)
@@ -177,7 +177,7 @@ private bool needOpAssign(StructDeclaration sd)
         Type tv = v.type.baseElemOf();
         if (tv.ty == Tstruct)
         {
-            TypeStruct ts = cast(TypeStruct)tv;
+            auto ts = cast(TypeStruct)tv;
             if (ts.sym.isUnionDeclaration())
                 continue;
             if (needOpAssign(ts.sym))
@@ -314,7 +314,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc)
     else if (sd.dtor)
     {
         //printf("\tswap copy\n");
-        TypeFunction tdtor = cast(TypeFunction)sd.dtor.type;
+        auto tdtor = cast(TypeFunction)sd.dtor.type;
         assert(tdtor.ty == Tfunction);
 
         auto idswap = Identifier.generateId("__swap");
@@ -435,7 +435,7 @@ bool needOpEquals(StructDeclaration sd)
         auto tvbase = tv.baseElemOf();
         if (tvbase.ty == Tstruct)
         {
-            TypeStruct ts = cast(TypeStruct)tvbase;
+            auto ts = cast(TypeStruct)tvbase;
             if (ts.sym.isUnionDeclaration() && ts.sym.fields.length != 1)
                 continue;
             if (needOpEquals(ts.sym))
@@ -762,7 +762,7 @@ private bool needToHash(StructDeclaration sd)
         auto tvbase = tv.baseElemOf();
         if (tvbase.ty == Tstruct)
         {
-            TypeStruct ts = cast(TypeStruct)tvbase;
+            auto ts = cast(TypeStruct)tvbase;
             if (ts.sym.isUnionDeclaration())
                 continue;
             if (needToHash(ts.sym))
diff --git a/gcc/d/dmd/compiler.d b/gcc/d/dmd/compiler.d
index 65330cf5d11fe75e0565e259fc5b65c1b0489165..3b00194ba8a6372923ce7b2f8865411338e415a0 100644
--- a/gcc/d/dmd/compiler.d
+++ b/gcc/d/dmd/compiler.d
@@ -16,6 +16,7 @@ import dmd.ctfeexpr;
 import dmd.dmodule;
 import dmd.expression;
 import dmd.mtype;
+import dmd.typesem;
 import dmd.root.array;
 
 extern (C++) __gshared
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index e194664383e9a91dccfa9be33c18ad64fddd2597..02dde1b4c0f6fc4b794f5ca6875401b1f77675b9 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -659,9 +659,9 @@ extern (C++) final class VersionCondition : DVCondition
             case "AVR":
             case "BigEndian":
             case "BSD":
-            case "CppRuntime_Clang":
+            case "CppRuntime_LLVM":
             case "CppRuntime_DigitalMars":
-            case "CppRuntime_Gcc":
+            case "CppRuntime_GNU":
             case "CppRuntime_Microsoft":
             case "CppRuntime_Sun":
             case "CRuntime_Bionic":
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 6ec31d5f9bb446a091da61ab9f4105c42f9f258d..54d50cf4a34b1cdc4c344a1778c98668ef68bcc0 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -36,7 +36,7 @@ import dmd.root.utf;
 import dmd.sideeffect;
 import dmd.target;
 import dmd.tokens;
-import dmd.typesem : toDsymbol, equivalent, sarrayOf;
+import dmd.typesem : toDsymbol, equivalent, sarrayOf, size;
 
 private enum LOG = false;
 
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 7fbcd6d9bc1f581898cf9659d3b426ebce9a4635..a4e3c7ecc0350627516b81b8a4dfa88eb26a6789 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -27,6 +27,7 @@ import dmd.root.array;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
 import dmd.tokens;
+import dmd.typesem : size;
 
 /***********************************************************
  */
@@ -1872,22 +1873,30 @@ final class CParser(AST) : Parser!AST
              * init-declarator:
              *    declarator simple-asm-expr (opt) gnu-attributes (opt)
              *    declarator simple-asm-expr (opt) gnu-attributes (opt) = initializer
+             *
+             * Clang also allows simple-asm-expr after gnu-attributes.
              */
+            while (1)
+            {
+                if (token.value == TOK.asm_)
+                {
+                    asmName = cparseGnuAsmLabel();
+                    /* This is a data definition, there cannot now be a
+                     * function definition.
+                     */
+                    first = false;
+                }
+                else if (token.value == TOK.__attribute__)
+                    cparseGnuAttributes(specifier);
+                else
+                    break;
+            }
+
             switch (token.value)
             {
                 case TOK.assign:
                 case TOK.comma:
                 case TOK.semicolon:
-                case TOK.asm_:
-                case TOK.__attribute__:
-                    if (token.value == TOK.asm_)
-                        asmName = cparseGnuAsmLabel();
-                    if (token.value == TOK.__attribute__)
-                    {
-                        cparseGnuAttributes(specifier);
-                        if (token.value == TOK.leftCurly)
-                            break;              // function definition
-                    }
                     /* This is a data definition, there cannot now be a
                      * function definition.
                      */
@@ -3626,6 +3635,12 @@ final class CParser(AST) : Parser!AST
                  * type on the target machine. It's the opposite of __attribute__((packed))
                  */
             }
+            else if (token.ident == Id.packed)
+            {
+                specifier.packalign.set(1);
+                specifier.packalign.setPack(true);
+                nextToken();
+            }
             else if (token.ident == Id.always_inline) // https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html
             {
                 specifier.scw |= SCW.xinline;
@@ -3974,7 +3989,7 @@ final class CParser(AST) : Parser!AST
             members = new AST.Dsymbols();          // so `members` will be non-null even with 0 members
             while (token.value != TOK.rightCurly)
             {
-                cparseStructDeclaration(members);
+                cparseStructDeclaration(members, packalign);
 
                 if (token.value == TOK.endOfFile)
                     break;
@@ -3988,6 +4003,24 @@ final class CParser(AST) : Parser!AST
                  *    struct-declarator (opt)
                  */
             }
+
+            /* GNU Extensions
+             * Parse the postfix gnu-attributes (opt)
+             */
+            Specifier specifier;
+            if (token.value == TOK.__attribute__)
+                cparseGnuAttributes(specifier);
+            if (!specifier.packalign.isUnknown)
+            {
+                packalign.set(specifier.packalign.get());
+                packalign.setPack(specifier.packalign.isPack());
+                foreach (ref d; (*members)[])
+                {
+                    auto decls = new AST.Dsymbols(1);
+                    (*decls)[0] = d;
+                    d = new AST.AlignDeclaration(d.loc, specifier.packalign, decls);
+                }
+            }
         }
         else if (!tag)
             error("missing tag `identifier` after `%s`", Token.toChars(structOrUnion));
@@ -4019,8 +4052,9 @@ final class CParser(AST) : Parser!AST
      *    declarator (opt) : constant-expression
      * Params:
      *    members = where to put the fields (members)
+     *    packalign = alignment to use for struct members
      */
-    void cparseStructDeclaration(AST.Dsymbols* members)
+    void cparseStructDeclaration(AST.Dsymbols* members, structalign_t packalign)
     {
         //printf("cparseStructDeclaration()\n");
         if (token.value == TOK._Static_assert)
@@ -4031,7 +4065,7 @@ final class CParser(AST) : Parser!AST
         }
 
         Specifier specifier;
-        specifier.packalign = this.packalign;
+        specifier.packalign = packalign.isUnknown ? this.packalign : packalign;
         auto tspec = cparseSpecifierQualifierList(LVL.member, specifier);
         if (!tspec)
         {
diff --git a/gcc/d/dmd/cppmangle.d b/gcc/d/dmd/cppmangle.d
index 334088b381cd6d979aa61b74c60b24e1cd25f870..0609778e4c774428d880285dbe812adf53ea46ba 100644
--- a/gcc/d/dmd/cppmangle.d
+++ b/gcc/d/dmd/cppmangle.d
@@ -2197,7 +2197,7 @@ private extern(C++) final class ComponentVisitor : Visitor
     /// Set to the result of the comparison
     private bool result;
 
-    public this(RootObject base) @safe
+    public this(RootObject base) @trusted
     {
         switch (base.dyncast())
         {
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index d2fcf5f796080da6203d27afaccef5bb23a6629e..8ed70c6639e0a0e93444579e185b097dd9d1b70f 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -17,6 +17,7 @@ import dmd.arraytypes;
 import dmd.astenums;
 import dmd.constfold;
 import dmd.compiler;
+import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dinterpret;
diff --git a/gcc/d/dmd/cxxfrontend.d b/gcc/d/dmd/cxxfrontend.d
index 403588b35e772a1606da5e0f00a15da55325e6f6..0b3096d1f5c7fbf9f30ef8067ed018ea600dce20 100644
--- a/gcc/d/dmd/cxxfrontend.d
+++ b/gcc/d/dmd/cxxfrontend.d
@@ -265,10 +265,16 @@ bool functionSemantic3(FuncDeclaration fd)
     return dmd.funcsem.functionSemantic3(fd);
 }
 
-MATCH leastAsSpecialized(FuncDeclaration f, FuncDeclaration g, Identifiers* names)
+MATCH leastAsSpecialized(FuncDeclaration fd, FuncDeclaration g, Identifiers* names)
 {
     import dmd.funcsem;
-    return dmd.funcsem.leastAsSpecialized(f, g, names);
+    return dmd.funcsem.leastAsSpecialized(fd, g, names);
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+    import dmd.funcsem;
+    return dmd.funcsem.isPure(fd);
 }
 
 /***********************************************************
@@ -627,6 +633,24 @@ Type referenceTo(Type type)
     return dmd.typesem.referenceTo(type);
 }
 
+uinteger_t size(Type type)
+{
+    import dmd.typesem;
+    return dmd.typesem.size(type);
+}
+
+uinteger_t size(Type type, const ref Loc loc)
+{
+    import dmd.typesem;
+    return dmd.typesem.size(type, loc);
+}
+
+MATCH implicitConvTo(Type from, Type to)
+{
+    import dmd.dcast;
+    return dmd.dcast.implicitConvTo(from, to);
+}
+
 /***********************************************************
  * typinf.d
  */
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index 78781f4ced7c3b3dd47224c47a04e3ba90e19b03..29059678fc2512ac6db401a77c9a94d47f687910 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -20,6 +20,7 @@ import dmd.arraytypes;
 import dmd.astenums;
 import dmd.dclass;
 import dmd.declaration;
+import dmd.denum;
 import dmd.dinterpret;
 import dmd.dscope;
 import dmd.dstruct;
@@ -1468,6 +1469,463 @@ MATCH implicitConvTo(Expression e, Type t)
     }
 }
 
+/********************************
+ * Determine if 'from' can be implicitly converted
+ * to type 'to'.
+ * Returns:
+ *      MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
+ */
+MATCH implicitConvTo(Type from, Type to)
+{
+    MATCH visitType(Type from)
+    {
+        //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
+        //printf("from: %s\n", from.toChars());
+        //printf("to  : %s\n", to.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+        return MATCH.nomatch;
+
+    }
+
+    MATCH visitBasic(TypeBasic from)
+    {
+        //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+        if (from == to)
+            return MATCH.exact;
+
+        if (from.ty == to.ty)
+        {
+            if (from.mod == to.mod)
+                return MATCH.exact;
+            else if (MODimplicitConv(from.mod, to.mod))
+                return MATCH.constant;
+            else if (!((from.mod ^ to.mod) & MODFlags.shared_)) // for wild matching
+                return MATCH.constant;
+            else
+                return MATCH.convert;
+        }
+
+        if (from.ty == Tvoid || to.ty == Tvoid)
+            return MATCH.nomatch;
+        if (to.ty == Tbool)
+            return MATCH.nomatch;
+
+        TypeBasic tob;
+        if (to.ty == Tvector && to.deco)
+        {
+            TypeVector tv = cast(TypeVector)to;
+            tob = tv.elementType();
+        }
+        else if (auto te = to.isTypeEnum())
+        {
+            EnumDeclaration ed = te.sym;
+            if (ed.isSpecial())
+            {
+                /* Special enums that allow implicit conversions to them
+                 * with a MATCH.convert
+                 */
+                tob = to.toBasetype().isTypeBasic();
+            }
+            else
+                return MATCH.nomatch;
+        }
+        else
+            tob = to.isTypeBasic();
+        if (!tob)
+            return MATCH.nomatch;
+
+        if (from.flags & TFlags.integral)
+        {
+            // Disallow implicit conversion of integers to imaginary or complex
+            if (tob.flags & (TFlags.imaginary | TFlags.complex))
+                return MATCH.nomatch;
+
+            // If converting from integral to integral
+            if (tob.flags & TFlags.integral)
+            {
+                const sz = size(from, Loc.initial);
+                const tosz = tob.size(Loc.initial);
+
+                /* Can't convert to smaller size
+                 */
+                if (sz > tosz)
+                    return MATCH.nomatch;
+                /* Can't change sign if same size
+                 */
+                //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
+                //    return MATCH.nomatch;
+            }
+        }
+        else if (from.flags & TFlags.floating)
+        {
+            // Disallow implicit conversion of floating point to integer
+            if (tob.flags & TFlags.integral)
+                return MATCH.nomatch;
+
+            assert(tob.flags & TFlags.floating || to.ty == Tvector);
+
+            // Disallow implicit conversion from complex to non-complex
+            if (from.flags & TFlags.complex && !(tob.flags & TFlags.complex))
+                return MATCH.nomatch;
+
+            // Disallow implicit conversion of real or imaginary to complex
+            if (from.flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
+                return MATCH.nomatch;
+
+            // Disallow implicit conversion to-from real and imaginary
+            if ((from.flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
+                return MATCH.nomatch;
+        }
+        return MATCH.convert;
+
+    }
+
+    MATCH visitVector(TypeVector from)
+    {
+        //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), from.toChars());
+        if (from == to)
+            return MATCH.exact;
+        if (to.ty != Tvector)
+            return MATCH.nomatch;
+
+        TypeVector tv = cast(TypeVector)to;
+        assert(from.basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
+
+        // Can't convert to a vector which has different size.
+        if (from.basetype.size() != tv.basetype.size())
+            return MATCH.nomatch;
+
+        // Allow conversion to void[]
+        if (tv.basetype.nextOf().ty == Tvoid)
+            return MATCH.convert;
+
+        // Otherwise implicitly convertible only if basetypes are.
+        return from.basetype.implicitConvTo(tv.basetype);
+    }
+
+    MATCH visitSArray(TypeSArray from)
+    {
+        //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+        if (auto ta = to.isTypeDArray())
+        {
+            if (!MODimplicitConv(from.next.mod, ta.next.mod))
+                return MATCH.nomatch;
+
+            /* Allow conversion to void[]
+             */
+            if (ta.next.ty == Tvoid)
+            {
+                return MATCH.convert;
+            }
+
+            MATCH m = from.next.constConv(ta.next);
+            if (m > MATCH.nomatch)
+            {
+                return MATCH.convert;
+            }
+            return MATCH.nomatch;
+        }
+        if (auto tsa = to.isTypeSArray())
+        {
+            if (from == to)
+                return MATCH.exact;
+
+            if (from.dim.equals(tsa.dim))
+            {
+                MATCH m = from.next.implicitConvTo(tsa.next);
+
+                /* Allow conversion to non-interface base class.
+                 */
+                if (m == MATCH.convert &&
+                    from.next.ty == Tclass)
+                {
+                    if (auto toc = tsa.next.isTypeClass)
+                    {
+                        if (!toc.sym.isInterfaceDeclaration)
+                            return MATCH.convert;
+                    }
+                }
+
+                /* Since static arrays are value types, allow
+                 * conversions from const elements to non-const
+                 * ones, just like we allow conversion from const int
+                 * to int.
+                 */
+                if (m >= MATCH.constant)
+                {
+                    if (from.mod != to.mod)
+                        m = MATCH.constant;
+                    return m;
+                }
+            }
+        }
+        return MATCH.nomatch;
+    }
+
+    MATCH visitDArray(TypeDArray from)
+    {
+        //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        if (auto ta = to.isTypeDArray())
+        {
+            if (!MODimplicitConv(from.next.mod, ta.next.mod))
+                return MATCH.nomatch; // not const-compatible
+
+            /* Allow conversion to void[]
+             */
+            if (from.next.ty != Tvoid && ta.next.ty == Tvoid)
+            {
+                return MATCH.convert;
+            }
+
+            MATCH m = from.next.constConv(ta.next);
+            if (m > MATCH.nomatch)
+            {
+                if (m == MATCH.exact && from.mod != to.mod)
+                    m = MATCH.constant;
+                return m;
+            }
+        }
+
+        return visitType(from);
+    }
+
+    MATCH visitAArray(TypeAArray from)
+    {
+        //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), from.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        if (auto ta = to.isTypeAArray())
+        {
+            if (!MODimplicitConv(from.next.mod, ta.next.mod))
+                return MATCH.nomatch; // not const-compatible
+
+            if (!MODimplicitConv(from.index.mod, ta.index.mod))
+                return MATCH.nomatch; // not const-compatible
+
+            MATCH m = from.next.constConv(ta.next);
+            MATCH mi = from.index.constConv(ta.index);
+            if (m > MATCH.nomatch && mi > MATCH.nomatch)
+            {
+                return MODimplicitConv(from.mod, to.mod) ? MATCH.constant : MATCH.nomatch;
+            }
+        }
+        return visitType(from);
+    }
+
+    /+
+     + Checks whether this function type is convertible to ` to`
+     + when used in a function pointer / delegate.
+     +
+     + Params:
+     +   to = target type
+     +
+     + Returns:
+     +   MATCH.nomatch: `to` is not a covaraint function
+     +   MATCH.convert: `to` is a covaraint function
+     +   MATCH.exact:   `to` is identical to this function
+     +/
+    MATCH implicitPointerConv(TypeFunction tf, Type to)
+    {
+        assert(to);
+
+        if (tf.equals(to))
+            return MATCH.constant;
+
+        if (tf.covariant(to) == Covariant.yes)
+        {
+            Type tret = tf.nextOf();
+            Type toret = to.nextOf();
+            if (tret.ty == Tclass && toret.ty == Tclass)
+            {
+                /* https://issues.dlang.org/show_bug.cgi?id=10219
+                 * Check covariant interface return with offset tweaking.
+                 * interface I {}
+                 * class C : Object, I {}
+                 * I function() dg = function C() {}    // should be error
+                 */
+                int offset = 0;
+                if (toret.isBaseOf(tret, &offset) && offset != 0)
+                    return MATCH.nomatch;
+            }
+            return MATCH.convert;
+        }
+
+        return MATCH.nomatch;
+    }
+
+    MATCH visitPointer(TypePointer from)
+    {
+        //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), from.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        // Only convert between pointers
+        auto tp = to.isTypePointer();
+        if (!tp)
+            return MATCH.nomatch;
+
+        assert(from.next);
+        assert(tp.next);
+
+        // Conversion to void*
+        if (tp.next.ty == Tvoid)
+        {
+            // Function pointer conversion doesn't check constness?
+            if (from.next.ty == Tfunction)
+                return MATCH.convert;
+
+            if (!MODimplicitConv(from.next.mod, tp.next.mod))
+                return MATCH.nomatch; // not const-compatible
+
+            return from.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
+        }
+
+        // Conversion between function pointers
+        if (auto thisTf = from.next.isTypeFunction())
+            return implicitPointerConv(thisTf, tp.next);
+
+        // Default, no implicit conversion between the pointer targets
+        MATCH m = from.next.constConv(tp.next);
+
+        if (m == MATCH.exact && from.mod != to.mod)
+            m = MATCH.constant;
+        return m;
+    }
+
+    MATCH visitDelegate(TypeDelegate from)
+    {
+        //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", from, to);
+        //printf("from: %s\n", from.toChars());
+        //printf("to  : %s\n", to.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        if (auto toDg = to.isTypeDelegate())
+        {
+            MATCH m = implicitPointerConv(from.next.isTypeFunction(), toDg.next);
+
+            // Retain the old behaviour for this refactoring
+            // Should probably be changed to constant to match function pointers
+            if (m > MATCH.convert)
+                m = MATCH.convert;
+
+            return m;
+        }
+
+        return MATCH.nomatch;
+    }
+
+    MATCH visitStruct(TypeStruct from)
+    {
+        //printf("TypeStruct::implicitConvTo(%s => %s)\n", from.toChars(), to.toChars());
+        MATCH m = from.implicitConvToWithoutAliasThis(to);
+        return m == MATCH.nomatch ? from.implicitConvToThroughAliasThis(to) : m;
+    }
+
+    MATCH visitEnum(TypeEnum from)
+    {
+        import dmd.enumsem : getMemtype;
+
+        MATCH m;
+        //printf("TypeEnum::implicitConvTo() %s to %s\n", from.toChars(), to.toChars());
+        if (from.ty == to.ty && from.sym == (cast(TypeEnum)to).sym)
+            m = (from.mod == to.mod) ? MATCH.exact : MATCH.constant;
+        else if (from.sym.getMemtype(Loc.initial).implicitConvTo(to))
+            m = MATCH.convert; // match with conversions
+        else
+            m = MATCH.nomatch; // no match
+        return m;
+    }
+
+    MATCH visitClass(TypeClass from)
+    {
+        //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), from.toChars());
+        MATCH m = from.implicitConvToWithoutAliasThis(to);
+        return m ? m : from.implicitConvToThroughAliasThis(to);
+    }
+
+    MATCH visitTuple(TypeTuple from)
+    {
+        if (from == to)
+            return MATCH.exact;
+        if (auto tt = to.isTypeTuple())
+        {
+            if (from.arguments.length == tt.arguments.length)
+            {
+                MATCH m = MATCH.exact;
+                for (size_t i = 0; i < tt.arguments.length; i++)
+                {
+                    Parameter arg1 = (*from.arguments)[i];
+                    Parameter arg2 = (*tt.arguments)[i];
+                    MATCH mi = arg1.type.implicitConvTo(arg2.type);
+                    if (mi < m)
+                        m = mi;
+                }
+                return m;
+            }
+        }
+        return MATCH.nomatch;
+    }
+
+    MATCH visitNull(TypeNull from)
+    {
+        //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", from, to);
+        //printf("from: %s\n", from.toChars());
+        //printf("to  : %s\n", to.toChars());
+        MATCH m = visitType(cast(Type)from);
+        if (m != MATCH.nomatch)
+            return m;
+
+        //NULL implicitly converts to any pointer type or dynamic array
+        //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
+        {
+            Type tb = to.toBasetype();
+            if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
+                return MATCH.constant;
+        }
+
+        return MATCH.nomatch;
+    }
+
+    MATCH visitNoreturn(TypeNoreturn from)
+    {
+        //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", from, to);
+        //printf("from: %s\n", from.toChars());
+        //printf("to  : %s\n", to.toChars());
+        if (from.equals(to))
+            return MATCH.exact;
+
+        // Different qualifiers?
+        if (to.ty == Tnoreturn)
+            return MATCH.constant;
+
+        // Implicitly convertible to any type
+        return MATCH.convert;
+    }
+
+    switch(from.ty)
+    {
+        default:             return from.isTypeBasic() ? visitBasic(from.isTypeBasic()) : visitType(from);
+        case Tvector:        return visitVector(from.isTypeVector());
+        case Tsarray:        return visitSArray(from.isTypeSArray());
+        case Tarray:         return visitDArray(from.isTypeDArray());
+        case Taarray:        return visitAArray(from.isTypeAArray());
+        case Tpointer:       return visitPointer(from.isTypePointer());
+        case Tdelegate:      return visitDelegate(from.isTypeDelegate());
+        case Tstruct:        return visitStruct(from.isTypeStruct());
+        case Tenum:          return visitEnum(from.isTypeEnum());
+        case Tclass:         return visitClass(from.isTypeClass());
+        case Ttuple:         return visitTuple(from.isTypeTuple());
+        case Tnull:          return visitNull(from.isTypeNull());
+        case Tnoreturn:      return visitNoreturn(from.isTypeNoreturn());
+    }
+}
+
 /**
  * Same as implicitConvTo(); except follow C11 rules, which are quite a bit
  * more permissive than D.
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index fdfe8a86a48b83cff626b5b8515f40384a2c95df..8f706fba33277c5391421f93741d03ff36f5fb44 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -35,6 +35,7 @@ namespace dmd
     bool functionSemantic(FuncDeclaration* fd);
     bool functionSemantic3(FuncDeclaration* fd);
     MATCH leastAsSpecialized(FuncDeclaration *f, FuncDeclaration *g, Identifiers *names);
+    PURE isPure(FuncDeclaration *f);
 }
 
 //enum STC : ulong from astenums.d:
@@ -719,7 +720,6 @@ public:
     bool isCodeseg() const override final;
     bool isOverloadable() const override final;
     bool isAbstract() override final;
-    PURE isPure();
     bool isSafe();
     bool isTrusted();
     bool isNogc();
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 2efdd31bbba011766bd9c107edb628b4cfe442d8..4c4c063cbf2731fd72897a9e9873482b9c8b7380 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -165,11 +165,10 @@ extern (C++) final class Import : Dsymbol
          * https://issues.dlang.org/show_bug.cgi?id=5412
          */
         assert(ident && ident == s.ident);
-        Import imp;
-        if (!aliasId && (imp = s.isImport()) !is null && !imp.aliasId)
-            return true;
-        else
+        if (aliasId)
             return false;
+        const imp = s.isImport();
+        return imp && !imp.aliasId;
     }
 
     override inout(Import) isImport() inout
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index 5493fc188812bf1c1892dfec8877d23c848a304c..52520be01df6059aea6c8eb17cf8d2adbb4f64af 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, equivalent, pointerTo, sarrayOf, arrayOf;
+import dmd.typesem : mutableOf, equivalent, pointerTo, sarrayOf, arrayOf, size;
 import dmd.utils : arrayCastBigEndian;
 import dmd.visitor;
 
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index a8b43da625b3b1fc520ccfe3a9e6e7952c8c93c6..84048af033796ab9a561732f2e830f6c1a15a301 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -2587,7 +2587,7 @@ TypeFunction isTypeFunction(Dsymbol s) @safe
     {
         Type t = f.originalType ? f.originalType : f.type;
         if (t.ty == Tfunction)
-            return cast(TypeFunction)t;
+            return (() @trusted => cast(TypeFunction)t)();
     }
     return null;
 }
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 416bd57f24bb4e5aa55c3445e8f3efd8ba6aea57..64f19d932ebfe8f374817e03fc708e9e6a35244d 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -456,7 +456,7 @@ extern (C++) class StructDeclaration : AggregateDeclaration
             Type tv = v.type.baseElemOf();
             if (tv.ty == Tstruct)
             {
-                TypeStruct ts = cast(TypeStruct)tv;
+                auto ts = cast(TypeStruct)tv;
                 StructDeclaration sd = ts.sym;
                 if (!sd.isPOD())
                 {
@@ -608,7 +608,7 @@ bool _isZeroInit(Expression exp)
 
         case EXP.string_:
         {
-            StringExp se = cast(StringExp)exp;
+            auto se = cast(StringExp)exp;
 
             if (se.type.toBasetype().ty == Tarray) // if initializing a dynamic array
                 return se.len == 0;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 4a21b14734235c58dc18e089e21ca32eb05a5adc..e32f5fa221c72ba1f8010815e6cba0d098923fea 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -7270,7 +7270,7 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             // If the bit-field spans more units of alignment than its type,
             // start a new field at the next alignment boundary.
             if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
-                fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
+                fieldState.bitOffset + bfd.fieldWidth > memsize * 8)
             {
                 if (log) printf("more units of alignment than its type\n");
                 startNewField();        // the bit field is full
@@ -7278,10 +7278,10 @@ private extern(C++) class SetFieldOffsetVisitor : Visitor
             else
             {
                 // if alignment boundary is crossed
-                uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+                uint start = (fieldState.fieldOffset * 8 + fieldState.bitOffset) % (memalignsize * 8);
                 uint end   = start + bfd.fieldWidth;
                 //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
-                if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+                if (start / (memsize * 8) != (end - 1) / (memsize * 8))
                 {
                     if (log) printf("alignment is crossed\n");
                     startNewField();
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 33ec6b1849f653012b686f9bdb878fece82493eb..8fcbbad2f76953e5e0ee1848fa72568c0cf94bed 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -89,7 +89,7 @@ private enum LOG = false;
 
 enum IDX_NOTFOUND = 0x12345678;
 
-pure nothrow @nogc @safe
+pure nothrow @nogc @trusted
 {
 
 /********************************************
@@ -143,6 +143,11 @@ inout(TemplateParameter) isTemplateParameter(inout RootObject o)
     return cast(inout(TemplateParameter))o;
 }
 
+} // end @trusted casts
+
+pure nothrow @nogc @safe
+{
+
 /**************************************
  * Is this Object an error?
  */
@@ -282,6 +287,18 @@ private bool match(RootObject o1, RootObject o2)
             o1, o1.toChars(), o1.dyncast(), o2, o2.toChars(), o2.dyncast());
     }
 
+    bool yes()
+    {
+        static if (log)
+            printf("\t. match\n");
+        return true;
+    }
+    bool no()
+    {
+        static if (log)
+            printf("\t. nomatch\n");
+        return false;
+    }
     /* A proper implementation of the various equals() overrides
      * should make it possible to just do o1.equals(o2), but
      * we'll do that another day.
@@ -294,7 +311,7 @@ private bool match(RootObject o1, RootObject o2)
     {
         auto t2 = isType(o2);
         if (!t2)
-            goto Lnomatch;
+            return no();
 
         static if (log)
         {
@@ -302,15 +319,15 @@ private bool match(RootObject o1, RootObject o2)
             printf("\tt2 = %s\n", t2.toChars());
         }
         if (!t1.equals(t2))
-            goto Lnomatch;
+            return no();
 
-        goto Lmatch;
+        return yes();
     }
     if (auto e1 = getExpression(o1))
     {
         auto e2 = getExpression(o2);
         if (!e2)
-            goto Lnomatch;
+            return no();
 
         static if (log)
         {
@@ -323,15 +340,15 @@ private bool match(RootObject o1, RootObject o2)
         // as well as expression equality to ensure templates are properly
         // matched.
         if (!(e1.type && e2.type && e1.type.equals(e2.type)) || !e1.equals(e2))
-            goto Lnomatch;
+            return no();
 
-        goto Lmatch;
+        return yes();
     }
     if (auto s1 = isDsymbol(o1))
     {
         auto s2 = isDsymbol(o2);
         if (!s2)
-            goto Lnomatch;
+            return no();
 
         static if (log)
         {
@@ -339,17 +356,17 @@ private bool match(RootObject o1, RootObject o2)
             printf("\ts2 = %s \n", s2.kind(), s2.toChars());
         }
         if (!s1.equals(s2))
-            goto Lnomatch;
+            return no();
         if (s1.parent != s2.parent && !s1.isFuncDeclaration() && !s2.isFuncDeclaration())
-            goto Lnomatch;
+            return no();
 
-        goto Lmatch;
+        return yes();
     }
     if (auto u1 = isTuple(o1))
     {
         auto u2 = isTuple(o2);
         if (!u2)
-            goto Lnomatch;
+            return no();
 
         static if (log)
         {
@@ -357,19 +374,11 @@ private bool match(RootObject o1, RootObject o2)
             printf("\tu2 = %s\n", u2.toChars());
         }
         if (!arrayObjectMatch(u1.objects, u2.objects))
-            goto Lnomatch;
+            return no();
 
-        goto Lmatch;
+        return yes();
     }
-Lmatch:
-    static if (log)
-        printf("\t. match\n");
-    return true;
-
-Lnomatch:
-    static if (log)
-        printf("\t. nomatch\n");
-    return false;
+    return yes();
 }
 
 /************************************
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index a26f3ab83b998c5ed8852d411821b0f7d7a9e8b3..b5fb0e2b9b32dbc84825aa51952beb3785a8b1c8 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -21,6 +21,7 @@ import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dimport;
@@ -426,7 +427,7 @@ extern (C++) abstract class Expression : ASTNode
      * is returned via e0.
      * Otherwise 'e' is directly returned and e0 is set to NULL.
      */
-    extern (D) static Expression extractLast(Expression e, out Expression e0) @safe
+    extern (D) static Expression extractLast(Expression e, out Expression e0) @trusted
     {
         if (e.op != EXP.comma)
         {
@@ -709,7 +710,7 @@ extern (C++) abstract class Expression : ASTNode
         return true;
     }
 
-    final pure inout nothrow @nogc @safe
+    final pure inout nothrow @nogc @trusted
     {
         inout(IntegerExp)   isIntegerExp() { return op == EXP.int64 ? cast(typeof(return))this : null; }
         inout(ErrorExp)     isErrorExp() { return op == EXP.error ? cast(typeof(return))this : null; }
@@ -3868,7 +3869,7 @@ extern (C++) final class VectorExp : UnaExp
     uint dim = ~0;      // number of elements in the vector
     OwnedBy ownedByCtfe = OwnedBy.code;
 
-    extern (D) this(const ref Loc loc, Expression e, Type t) @safe
+    extern (D) this(const ref Loc loc, Expression e, Type t) @trusted
     {
         super(loc, EXP.vector, e);
         assert(t.ty == Tvector);
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 481806d392bd0bbb66005e29d2780eddb70c2e77..a69b64d6b784f068e56c54a985b1dac7a8cc216e 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -7752,6 +7752,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             if (auto fmResult = global.fileManager.getFileContents(fileName))
             {
                 se = new StringExp(e.loc, fmResult);
+                se.hexString = true;
             }
             else
             {
@@ -9251,13 +9252,27 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         // Check for unsafe casts
-        if (!isSafeCast(ex, t1b, tob))
+        string msg;
+        if (!isSafeCast(ex, t1b, tob, msg))
         {
-            if (sc.setUnsafe(false, exp.loc, "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
+            if (sc.setUnsafe(false, exp.loc,
+                "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to))
             {
+                if (msg.length)
+                    errorSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
                 return setError();
             }
         }
+        else if (msg.length) // deprecated unsafe
+        {
+            const err = sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+                "cast from `%s` to `%s` not allowed in safe code", exp.e1.type, exp.to);
+            // if message was printed
+            if (sc.func && sc.func.isSafeBypassingInference() && !sc.isDeprecated())
+                deprecationSupplemental(exp.loc, "%s", (msg ~ '\0').ptr);
+            if (err)
+                return setError();
+        }
 
         // `object.__ArrayCast` is a rewrite of an old runtime hook `_d_arraycast`. `_d_arraycast` was not built
         // to handle certain casts.  Those casts which `object.__ArrayCast` does not support are filtered out.
@@ -11413,11 +11428,6 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 else
                     e2x = e2x.implicitCastTo(sc, exp.e1.type);
             }
-            if (t1n.toBasetype.ty == Tvoid && t2n.toBasetype.ty == Tvoid)
-            {
-                if (sc.setUnsafe(false, exp.loc, "cannot copy `void[]` to `void[]` in `@safe` code"))
-                    return setError();
-            }
         }
         else
         {
@@ -11449,6 +11459,33 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
             }
         }
+
+        if (exp.e1.op == EXP.slice &&
+            (t1.ty == Tarray || t1.ty == Tsarray) &&
+            t1.nextOf().toBasetype().ty == Tvoid)
+        {
+            if (t2.nextOf().implicitConvTo(t1.nextOf()))
+            {
+                if (sc.setUnsafe(false, exp.loc, "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+                    return setError();
+            }
+            else
+            {
+                // copying from non-void to void was overlooked, deprecate
+                if (sc.setUnsafePreview(FeatureState.default_, false, exp.loc,
+                    "cannot copy `%s` to `%s` in `@safe` code", t2, t1))
+                    return setError();
+            }
+            if (global.params.fixImmutableConv && !t2.implicitConvTo(t1))
+            {
+                error(exp.loc, "cannot copy `%s` to `%s`",
+                    t2.toChars(), t1.toChars());
+                errorSupplemental(exp.loc,
+                    "Source data has incompatible type qualifier(s)");
+                errorSupplemental(exp.loc, "Use `cast(%s)` to force copy", t1.toChars());
+                return setError();
+            }
+        }
         if (e2x.op == EXP.error)
         {
             result = e2x;
@@ -11837,6 +11874,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             (tb2.ty == Tarray || tb2.ty == Tsarray) &&
             (exp.e2.implicitConvTo(exp.e1.type) ||
              (tb2.nextOf().implicitConvTo(tb1next) &&
+             // Do not strip const(void)[]
+             (!global.params.fixImmutableConv || tb1next.ty != Tvoid) &&
               (tb2.nextOf().size(Loc.initial) == tb1next.size(Loc.initial)))))
         {
             // EXP.concatenateAssign
@@ -12586,7 +12625,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp.type = tb.nextOf().arrayOf();
         if (exp.type.ty == Tarray && tb1next && tb2next && tb1next.mod != tb2next.mod)
         {
-            exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
+            // Do not strip const(void)[]
+            if (!global.params.fixImmutableConv || tb.nextOf().ty != Tvoid)
+                exp.type = exp.type.nextOf().toHeadMutable().arrayOf();
         }
         if (Type tbn = tb.nextOf())
         {
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index cb19b14dfb411d1d6d3bb8dfff4287d66f2a1596..54ff82670aebbf87193dbe3e3097a108575fe34a 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -731,72 +731,6 @@ extern (C++) class FuncDeclaration : Declaration
         inferScope = true;
     }
 
-    final PURE isPure()
-    {
-        //printf("FuncDeclaration::isPure() '%s'\n", toChars());
-
-
-        TypeFunction tf = type.toTypeFunction();
-        if (purityInprocess)
-            setImpure();
-        if (tf.purity == PURE.fwdref)
-            tf.purityLevel();
-        PURE purity = tf.purity;
-        if (purity > PURE.weak && isNested())
-            purity = PURE.weak;
-        if (purity > PURE.weak && needThis())
-        {
-            // The attribute of the 'this' reference affects purity strength
-            if (type.mod & MODFlags.immutable_)
-            {
-            }
-            else if (type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
-                purity = PURE.const_;
-            else
-                purity = PURE.weak;
-        }
-        tf.purity = purity;
-        // ^ This rely on the current situation that every FuncDeclaration has a
-        //   unique TypeFunction.
-        return purity;
-    }
-
-    extern (D) final PURE isPureBypassingInference()
-    {
-        if (purityInprocess)
-            return PURE.fwdref;
-        else
-            return isPure();
-    }
-
-    /**************************************
-     * The function is doing something impure, so mark it as impure.
-     *
-     * Params:
-     *     loc = location of impure action
-     *     fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
-     *     arg0 = (optional) argument to format string
-     *
-     * Returns: `true` if there's a purity error
-     */
-    extern (D) final bool setImpure(Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
-    {
-        if (purityInprocess)
-        {
-            purityInprocess = false;
-            if (fmt)
-                pureViolation = new AttributeViolation(loc, fmt, this, arg0); // impure action
-            else if (arg0)
-                pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
-
-            if (fes)
-                fes.func.setImpure(loc, fmt, arg0);
-        }
-        else if (isPure())
-            return true;
-        return false;
-    }
-
     extern (D) final uint flags()
     {
         return bitFields;
@@ -977,187 +911,6 @@ extern (C++) class FuncDeclaration : Declaration
         }
     }
 
-    /********************************************
-     * See if pointers from function parameters, mutable globals, or uplevel functions
-     * could leak into return value.
-     * Returns:
-     *   true if the function return value is isolated from
-     *   any inputs to the function
-     */
-    extern (D) final bool isReturnIsolated()
-    {
-        //printf("isReturnIsolated(this: %s)\n", this.toChars);
-        TypeFunction tf = type.toTypeFunction();
-        assert(tf.next);
-
-        Type treti = tf.next;
-        if (tf.isref)
-            return isTypeIsolatedIndirect(treti);              // check influence from parameters
-
-        return isTypeIsolated(treti);
-    }
-
-    /********************
-     * See if pointers from function parameters, mutable globals, or uplevel functions
-     * could leak into type `t`.
-     * Params:
-     *   t = type to check if it is isolated
-     * Returns:
-     *   true if `t` is isolated from
-     *   any inputs to the function
-     */
-    extern (D) final bool isTypeIsolated(Type t)
-    {
-        StringTable!Type parentTypes;
-        const uniqueTypeID = t.getUniqueID();
-        if (uniqueTypeID)
-        {
-            const cacheResultPtr = uniqueTypeID in isTypeIsolatedCache;
-            if (cacheResultPtr !is null)
-                return *cacheResultPtr;
-
-            parentTypes._init();
-            const isIsolated = isTypeIsolated(t, parentTypes);
-            isTypeIsolatedCache[uniqueTypeID] = isIsolated;
-            return isIsolated;
-        }
-        else
-        {
-            parentTypes._init();
-            return isTypeIsolated(t, parentTypes);
-        }
-    }
-
-    ///ditto
-    extern (D) final bool isTypeIsolated(Type t, ref StringTable!Type parentTypes)
-    {
-        //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
-
-        t = t.baseElemOf();
-        switch (t.ty)
-        {
-            case Tarray:
-            case Tpointer:
-                return isTypeIsolatedIndirect(t.nextOf()); // go down one level
-
-            case Taarray:
-            case Tclass:
-                return isTypeIsolatedIndirect(t);
-
-            case Tstruct:
-                /* Drill down and check the struct's fields
-                 */
-                auto sym = t.toDsymbol(null).isStructDeclaration();
-                const tName = t.toChars.toDString;
-                const entry = parentTypes.insert(tName, t);
-                if (entry == null)
-                {
-                    //we've already seen this type in a parent, not isolated
-                    return false;
-                }
-                foreach (v; sym.fields)
-                {
-                    Type tmi = v.type.addMod(t.mod);
-                    //printf("\tt = %s, v: %s, vtype: %s,  tmi = %s\n",
-                    //       t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
-                    if (!isTypeIsolated(tmi, parentTypes))
-                        return false;
-                }
-                return true;
-
-            default:
-                return true;
-        }
-    }
-
-    /********************************************
-     * Params:
-     *    t = type of object to test one level of indirection down
-     * Returns:
-     *    true if an object typed `t` has no indirections
-     *    which could have come from the function's parameters, mutable
-     *    globals, or uplevel functions.
-     */
-    private bool isTypeIsolatedIndirect(Type t)
-    {
-        //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
-        assert(t);
-
-        /* Since `t` is one level down from an indirection, it could pick
-         * up a reference to a mutable global or an outer function, so
-         * return false.
-         */
-        if (!isPureBypassingInference() || isNested())
-            return false;
-
-        TypeFunction tf = type.toTypeFunction();
-
-        //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
-
-        foreach (i, fparam; tf.parameterList)
-        {
-            Type tp = fparam.type;
-            if (!tp)
-                continue;
-
-            if (fparam.isLazy() || fparam.isReference())
-            {
-                if (!traverseIndirections(tp, t))
-                    return false;
-                continue;
-            }
-
-            /* Goes down one level of indirection, then calls traverseIndirection() on
-             * the result.
-             * Returns:
-             *  true if t is isolated from tp
-             */
-            static bool traverse(Type tp, Type t)
-            {
-                tp = tp.baseElemOf();
-                switch (tp.ty)
-                {
-                    case Tarray:
-                    case Tpointer:
-                        return traverseIndirections(tp.nextOf(), t);
-
-                    case Taarray:
-                    case Tclass:
-                        return traverseIndirections(tp, t);
-
-                    case Tstruct:
-                        /* Drill down and check the struct's fields
-                         */
-                        auto sym = tp.toDsymbol(null).isStructDeclaration();
-                        foreach (v; sym.fields)
-                        {
-                            Type tprmi = v.type.addMod(tp.mod);
-                            //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
-                            if (!traverse(tprmi, t))
-                                return false;
-                        }
-                        return true;
-
-                    default:
-                        return true;
-                }
-            }
-
-            if (!traverse(tp, t))
-                return false;
-        }
-        // The 'this' reference is a parameter, too
-        if (AggregateDeclaration ad = isCtorDeclaration() ? null : isThis())
-        {
-            Type tthis = ad.getType().addMod(tf.mod);
-            //printf("\ttthis = %s\n", tthis.toChars());
-            if (!traverseIndirections(tthis, t))
-                return false;
-        }
-
-        return true;
-    }
-
     /****************************************
      * Determine if function needs a static frame pointer.
      * Returns:
@@ -1766,116 +1519,6 @@ unittest
     assert(mismatches.isMutable);
 }
 
-/**************************************
- * Performs type-based alias analysis between a newly created value and a pre-
- * existing memory reference:
- *
- * Assuming that a reference A to a value of type `ta` was available to the code
- * that created a reference B to a value of type `tb`, it returns whether B
- * might alias memory reachable from A based on the types involved (either
- * directly or via any number of indirections in either A or B).
- *
- * This relation is not symmetric in the two arguments. For example, a
- * a `const(int)` reference can point to a pre-existing `int`, but not the other
- * way round.
- *
- * Examples:
- *
- *      ta,           tb,               result
- *      `const(int)`, `int`,            `false`
- *      `int`,        `const(int)`,     `true`
- *      `int`,        `immutable(int)`, `false`
- *      const(immutable(int)*), immutable(int)*, false   // BUG: returns true
- *
- * Params:
- *      ta = value type being referred to
- *      tb = referred to value type that could be constructed from ta
- *
- * Returns:
- *      true if reference to `tb` is isolated from reference to `ta`
- */
-private bool traverseIndirections(Type ta, Type tb)
-{
-    //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
-
-    static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
-    {
-        //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
-        ta = ta.baseElemOf();
-        tb = tb.baseElemOf();
-
-        // First, check if the pointed-to types are convertible to each other such
-        // that they might alias directly.
-        static bool mayAliasDirect(Type source, Type target)
-        {
-            return
-                // if source is the same as target or can be const-converted to target
-                source.constConv(target) != MATCH.nomatch ||
-                // if target is void and source can be const-converted to target
-                (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
-        }
-
-        if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
-        {
-            //printf(" true  mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
-            return false;
-        }
-        if (ta.nextOf() && ta.nextOf() == tb.nextOf())
-        {
-             //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
-             return true;
-        }
-
-        if (tb.ty == Tclass || tb.ty == Tstruct)
-        {
-            /* Traverse the type of each field of the aggregate
-             */
-            bool* found = table.getLvalue(tb.deco);
-            if (*found == true)
-                return true; // We have already seen this symbol, break the cycle
-            else
-                *found = true;
-
-            AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
-            foreach (v; sym.fields)
-            {
-                Type tprmi = v.type.addMod(tb.mod);
-                //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
-                if (!traverse(ta, tprmi, table, reversePass))
-                    return false;
-            }
-        }
-        else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
-        {
-            Type tind = tb.nextOf();
-            if (!traverse(ta, tind, table, reversePass))
-                return false;
-        }
-        else if (tb.hasPointers())
-        {
-            // BUG: consider the context pointer of delegate types
-            return false;
-        }
-
-        // Still no match, so try breaking up ta if we have not done so yet.
-        if (!reversePass)
-        {
-            scope newTable = AssocArray!(const(char)*, bool)();
-            return traverse(tb, ta, newTable, true);
-        }
-
-        return true;
-    }
-
-    // To handle arbitrary levels of indirections in both parameters, we
-    // recursively descend into aggregate members/levels of indirection in both
-    // `ta` and `tb` while avoiding cycles. Start with the original types.
-    scope table = AssocArray!(const(char)*, bool)();
-    const result = traverse(ta, tb, table, false);
-    //printf("  returns %d\n", result);
-    return result;
-}
-
 /* For all functions between outerFunc and f, mark them as needing
  * a closure.
  */
diff --git a/gcc/d/dmd/funcsem.d b/gcc/d/dmd/funcsem.d
index ee36a165d62ced4476ae9cad43c24dadfdc4019a..594e481e4694fce896b69b8cef2021f4e7e684f8 100644
--- a/gcc/d/dmd/funcsem.d
+++ b/gcc/d/dmd/funcsem.d
@@ -2539,7 +2539,7 @@ void buildEnsureRequire(FuncDeclaration thisfd)
     /* Rewrite contracts as nested functions, then call them. Doing it as nested
      * functions means that overriding functions can call them.
      */
-    TypeFunction f = cast(TypeFunction) thisfd.type;
+    auto f = cast(TypeFunction) thisfd.type;
     /* Make a copy of the parameters and make them all ref */
     static Parameters* toRefCopy(ParameterList parameterList)
     {
@@ -3062,3 +3062,362 @@ extern (D) bool checkNRVO(FuncDeclaration fd)
     }
     return true;
 }
+
+/**************************************
+ * The function is doing something impure, so mark it as impure.
+ *
+ * Params:
+ *     fd = function declaration to mark
+ *     loc = location of impure action
+ *     fmt = format string for error message. Must include "%s `%s`" for the function kind and name.
+ *     arg0 = (optional) argument to format string
+ *
+ * Returns: `true` if there's a purity error
+ */
+extern (D) bool setImpure(FuncDeclaration fd, Loc loc = Loc.init, const(char)* fmt = null, RootObject arg0 = null)
+{
+    if (fd.purityInprocess)
+    {
+        fd.purityInprocess = false;
+        if (fmt)
+            fd.pureViolation = new AttributeViolation(loc, fmt, fd, arg0); // impure action
+        else if (arg0)
+            fd.pureViolation = new AttributeViolation(loc, fmt, arg0); // call to impure function
+
+        if (fd.fes)
+            fd.fes.func.setImpure(loc, fmt, arg0);
+    }
+    else if (fd.isPure())
+        return true;
+    return false;
+}
+
+PURE isPure(FuncDeclaration fd)
+{
+    //printf("FuncDeclaration::isPure() '%s'\n", toChars());
+
+
+    TypeFunction tf = fd.type.toTypeFunction();
+    if (fd.purityInprocess)
+        fd.setImpure();
+    if (tf.purity == PURE.fwdref)
+        tf.purityLevel();
+    PURE purity = tf.purity;
+    if (purity > PURE.weak && fd.isNested())
+        purity = PURE.weak;
+    if (purity > PURE.weak && fd.needThis())
+    {
+        // The attribute of the 'this' reference affects purity strength
+        if (fd.type.mod & MODFlags.immutable_)
+        {
+        }
+        else if (fd.type.mod & (MODFlags.const_ | MODFlags.wild) && purity >= PURE.const_)
+            purity = PURE.const_;
+        else
+            purity = PURE.weak;
+    }
+    tf.purity = purity;
+    // ^ This rely on the current situation that every FuncDeclaration has a
+    //   unique TypeFunction.
+    return purity;
+}
+
+extern (D) PURE isPureBypassingInference(FuncDeclaration fd)
+{
+    if (fd.purityInprocess)
+        return PURE.fwdref;
+    else
+        return fd.isPure();
+}
+
+/**************************************
+ * Performs type-based alias analysis between a newly created value and a pre-
+ * existing memory reference:
+ *
+ * Assuming that a reference A to a value of type `ta` was available to the code
+ * that created a reference B to a value of type `tb`, it returns whether B
+ * might alias memory reachable from A based on the types involved (either
+ * directly or via any number of indirections in either A or B).
+ *
+ * This relation is not symmetric in the two arguments. For example, a
+ * a `const(int)` reference can point to a pre-existing `int`, but not the other
+ * way round.
+ *
+ * Examples:
+ *
+ *      ta,           tb,               result
+ *      `const(int)`, `int`,            `false`
+ *      `int`,        `const(int)`,     `true`
+ *      `int`,        `immutable(int)`, `false`
+ *      const(immutable(int)*), immutable(int)*, false   // BUG: returns true
+ *
+ * Params:
+ *      ta = value type being referred to
+ *      tb = referred to value type that could be constructed from ta
+ *
+ * Returns:
+ *      true if reference to `tb` is isolated from reference to `ta`
+ */
+bool traverseIndirections(Type ta, Type tb)
+{
+    //printf("traverseIndirections(%s, %s)\n", ta.toChars(), tb.toChars());
+
+    static bool traverse(Type ta, Type tb, ref scope AssocArray!(const(char)*, bool) table, bool reversePass)
+    {
+        //printf("traverse(%s, %s)\n", ta.toChars(), tb.toChars());
+        ta = ta.baseElemOf();
+        tb = tb.baseElemOf();
+
+        // First, check if the pointed-to types are convertible to each other such
+        // that they might alias directly.
+        static bool mayAliasDirect(Type source, Type target)
+        {
+            return
+                // if source is the same as target or can be const-converted to target
+                source.constConv(target) != MATCH.nomatch ||
+                // if target is void and source can be const-converted to target
+                (target.ty == Tvoid && MODimplicitConv(source.mod, target.mod));
+        }
+
+        if (mayAliasDirect(reversePass ? tb : ta, reversePass ? ta : tb))
+        {
+            //printf(" true  mayalias %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+            return false;
+        }
+        if (ta.nextOf() && ta.nextOf() == tb.nextOf())
+        {
+             //printf(" next==next %s %s %d\n", ta.toChars(), tb.toChars(), reversePass);
+             return true;
+        }
+
+        if (tb.ty == Tclass || tb.ty == Tstruct)
+        {
+            /* Traverse the type of each field of the aggregate
+             */
+            bool* found = table.getLvalue(tb.deco);
+            if (*found == true)
+                return true; // We have already seen this symbol, break the cycle
+            else
+                *found = true;
+
+            AggregateDeclaration sym = tb.toDsymbol(null).isAggregateDeclaration();
+            foreach (v; sym.fields)
+            {
+                Type tprmi = v.type.addMod(tb.mod);
+                //printf("\ttb = %s, tprmi = %s\n", tb.toChars(), tprmi.toChars());
+                if (!traverse(ta, tprmi, table, reversePass))
+                    return false;
+            }
+        }
+        else if (tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tpointer)
+        {
+            Type tind = tb.nextOf();
+            if (!traverse(ta, tind, table, reversePass))
+                return false;
+        }
+        else if (tb.hasPointers())
+        {
+            // BUG: consider the context pointer of delegate types
+            return false;
+        }
+
+        // Still no match, so try breaking up ta if we have not done so yet.
+        if (!reversePass)
+        {
+            scope newTable = AssocArray!(const(char)*, bool)();
+            return traverse(tb, ta, newTable, true);
+        }
+
+        return true;
+    }
+
+    // To handle arbitrary levels of indirections in both parameters, we
+    // recursively descend into aggregate members/levels of indirection in both
+    // `ta` and `tb` while avoiding cycles. Start with the original types.
+    scope table = AssocArray!(const(char)*, bool)();
+    const result = traverse(ta, tb, table, false);
+    //printf("  returns %d\n", result);
+    return result;
+}
+
+/********************************************
+ * Params:
+ *     fd = function declaration to check
+ *    t = type of object to test one level of indirection down
+ * Returns:
+ *    true if an object typed `t` has no indirections
+ *    which could have come from the function's parameters, mutable
+ *    globals, or uplevel functions.
+ */
+bool isTypeIsolatedIndirect(FuncDeclaration fd, Type t)
+{
+    //printf("isTypeIsolatedIndirect(t: %s)\n", t.toChars());
+    assert(t);
+
+    /* Since `t` is one level down from an indirection, it could pick
+     * up a reference to a mutable global or an outer function, so
+     * return false.
+     */
+    if (!fd.isPureBypassingInference() || fd.isNested())
+        return false;
+
+    TypeFunction tf = fd.type.toTypeFunction();
+
+    //printf("isTypeIsolatedIndirect(%s) t = %s\n", tf.toChars(), t.toChars());
+
+    foreach (i, fparam; tf.parameterList)
+    {
+        Type tp = fparam.type;
+        if (!tp)
+            continue;
+
+        if (fparam.isLazy() || fparam.isReference())
+        {
+            if (!traverseIndirections(tp, t))
+                return false;
+            continue;
+        }
+
+        /* Goes down one level of indirection, then calls traverseIndirection() on
+         * the result.
+         * Returns:
+         *  true if t is isolated from tp
+         */
+        static bool traverse(Type tp, Type t)
+        {
+            tp = tp.baseElemOf();
+            switch (tp.ty)
+            {
+                case Tarray:
+                case Tpointer:
+                    return traverseIndirections(tp.nextOf(), t);
+
+                case Taarray:
+                case Tclass:
+                    return traverseIndirections(tp, t);
+
+                case Tstruct:
+                    /* Drill down and check the struct's fields
+                     */
+                    auto sym = tp.toDsymbol(null).isStructDeclaration();
+                    foreach (v; sym.fields)
+                    {
+                        Type tprmi = v.type.addMod(tp.mod);
+                        //printf("\ttp = %s, tprmi = %s\n", tp.toChars(), tprmi.toChars());
+                        if (!traverse(tprmi, t))
+                            return false;
+                    }
+                    return true;
+
+                default:
+                    return true;
+            }
+        }
+
+        if (!traverse(tp, t))
+            return false;
+    }
+    // The 'this' reference is a parameter, too
+    if (AggregateDeclaration ad = fd.isCtorDeclaration() ? null : fd.isThis())
+    {
+        Type tthis = ad.getType().addMod(tf.mod);
+        //printf("\ttthis = %s\n", tthis.toChars());
+        if (!traverseIndirections(tthis, t))
+            return false;
+    }
+
+    return true;
+}
+
+/********************************************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into return value.
+ * Returns:
+ *   true if the function return value is isolated from
+ *   any inputs to the function
+ */
+extern (D) bool isReturnIsolated(FuncDeclaration fd)
+{
+    //printf("isReturnIsolated(this: %s)\n", this.toChars);
+    TypeFunction tf = fd.type.toTypeFunction();
+    assert(tf.next);
+
+    Type treti = tf.next;
+    if (tf.isref)
+        return fd.isTypeIsolatedIndirect(treti);              // check influence from parameters
+
+    return fd.isTypeIsolated(treti);
+}
+
+/********************
+ * See if pointers from function parameters, mutable globals, or uplevel functions
+ * could leak into type `t`.
+ * Params:
+ *   t = type to check if it is isolated
+ * Returns:
+ *   true if `t` is isolated from
+ *   any inputs to the function
+ */
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t)
+{
+    StringTable!Type parentTypes;
+    const uniqueTypeID = t.getUniqueID();
+    if (uniqueTypeID)
+    {
+        const cacheResultPtr = uniqueTypeID in fd.isTypeIsolatedCache;
+        if (cacheResultPtr !is null)
+            return *cacheResultPtr;
+
+        parentTypes._init();
+        const isIsolated = fd.isTypeIsolated(t, parentTypes);
+        fd.isTypeIsolatedCache[uniqueTypeID] = isIsolated;
+        return isIsolated;
+    }
+    else
+    {
+        parentTypes._init();
+        return fd.isTypeIsolated(t, parentTypes);
+    }
+}
+
+///ditto
+extern (D) bool isTypeIsolated(FuncDeclaration fd, Type t, ref StringTable!Type parentTypes)
+{
+    //printf("this: %s, isTypeIsolated(t: %s)\n", this.toChars(), t.toChars());
+
+    t = t.baseElemOf();
+    switch (t.ty)
+    {
+        case Tarray:
+        case Tpointer:
+            return fd.isTypeIsolatedIndirect(t.nextOf()); // go down one level
+
+        case Taarray:
+        case Tclass:
+            return fd.isTypeIsolatedIndirect(t);
+
+        case Tstruct:
+            /* Drill down and check the struct's fields
+             */
+            auto sym = t.toDsymbol(null).isStructDeclaration();
+            const tName = t.toChars.toDString;
+            const entry = parentTypes.insert(tName, t);
+            if (entry == null)
+            {
+                //we've already seen this type in a parent, not isolated
+                return false;
+            }
+            foreach (v; sym.fields)
+            {
+                Type tmi = v.type.addMod(t.mod);
+                //printf("\tt = %s, v: %s, vtype: %s,  tmi = %s\n",
+                //       t.toChars(), v.toChars(), v.type.toChars(), tmi.toChars());
+                if (!fd.isTypeIsolated(tmi, parentTypes))
+                    return false;
+            }
+            return true;
+
+        default:
+            return true;
+    }
+}
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 1e72cf709c664583663ec7335bd6cae3e0003f89..a44fb2877a95b14003f4656f3d9f07fa169e4af4 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -3933,9 +3933,9 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
         buf.writeByte(' ');
     }
 
-    void ignoreReturn(string str)
+    void dg(string str)
     {
-        if (str != "return")
+        if (str != "return" && str != "scope")
         {
             // don't write 'ref' for ctors
             if ((ident == Id.ctor) && str == "ref")
@@ -3944,7 +3944,7 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
             buf.writeByte(' ');
         }
     }
-    t.attributesApply(&ignoreReturn);
+    t.attributesApply(&dg);
 
     if (t.linkage > LINK.d && hgs.ddoc != 1 && !hgs.hdrgen)
     {
@@ -3977,7 +3977,15 @@ private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
         buf.writeByte(')');
     }
     parametersToBuffer(t.parameterList, buf, hgs);
-    if (t.isreturn)
+    if (t.isreturnscope && !t.isreturninferred)
+    {
+        buf.writestring(" return scope");
+    }
+    else if (t.isScopeQual && !t.isscopeinferred)
+    {
+        buf.writestring(" scope");
+    }
+    if (t.isreturn && !t.isreturnscope && !t.isreturninferred)
     {
         buf.writestring(" return");
     }
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index dfaf8f5200b346a470826831138cd973823b1173..f676361d958bba49dda83dfa6df59cefa7219a52 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -574,6 +574,7 @@ immutable Msgtable[] msgtable =
     { "define" },
     { "undef" },
     { "ident" },
+    { "packed" },
 ];
 
 
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index a91a0a4ef630ded0e1ae7e1d688dcd19664939fa..6a2d349f15b5e6b2f581920024237b94f7bb1f2f 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -21,6 +21,7 @@ import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
+import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.denum;
@@ -30,7 +31,6 @@ import dmd.dtemplate;
 import dmd.enumsem;
 import dmd.errors;
 import dmd.expression;
-import dmd.funcsem;
 import dmd.globals;
 import dmd.hdrgen;
 import dmd.id;
@@ -618,20 +618,9 @@ extern (C++) abstract class Type : ASTNode
         stringtable = stringtable.init;
     }
 
-    final uinteger_t size()
-    {
-        return size(Loc.initial);
-    }
-
-    uinteger_t size(const ref Loc loc)
-    {
-        error(loc, "no size for type `%s`", toChars());
-        return SIZE_INVALID;
-    }
-
     uint alignsize()
     {
-        return cast(uint)size(Loc.initial);
+        return cast(uint)size(this, Loc.initial);
     }
 
     /*********************************
@@ -1293,22 +1282,6 @@ extern (C++) abstract class Type : ASTNode
         return ((te = isTypeEnum()) !is null) ? te.toBasetype2() : this;
     }
 
-    /********************************
-     * Determine if 'this' can be implicitly converted
-     * to type 'to'.
-     * Returns:
-     *      MATCH.nomatch, MATCH.convert, MATCH.constant, MATCH.exact
-     */
-    MATCH implicitConvTo(Type to)
-    {
-        //printf("Type::implicitConvTo(this=%p, to=%p)\n", this, to);
-        //printf("from: %s\n", toChars());
-        //printf("to  : %s\n", to.toChars());
-        if (this.equals(to))
-            return MATCH.exact;
-        return MATCH.nomatch;
-    }
-
     /*******************************
      * Determine if converting 'this' to 'to' is an identity operation,
      * a conversion to const operation, or the types aren't the same.
@@ -1582,7 +1555,7 @@ extern (C++) abstract class Type : ASTNode
         }
     }
 
-    final pure inout nothrow @nogc @safe
+    final pure inout nothrow @nogc @trusted
     {
         inout(TypeError)      isTypeError()      { return ty == Terror     ? cast(typeof(return))this : null; }
         inout(TypeVector)     isTypeVector()     { return ty == Tvector    ? cast(typeof(return))this : null; }
@@ -1656,11 +1629,6 @@ extern (C++) final class TypeError : Type
         return this;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return SIZE_INVALID;
-    }
-
     override Expression defaultInitLiteral(const ref Loc loc)
     {
         return ErrorExp.get();
@@ -2116,83 +2084,6 @@ extern (C++) final class TypeBasic : Type
         return this;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        uint size;
-        //printf("TypeBasic::size()\n");
-        switch (ty)
-        {
-        case Tint8:
-        case Tuns8:
-            size = 1;
-            break;
-
-        case Tint16:
-        case Tuns16:
-            size = 2;
-            break;
-
-        case Tint32:
-        case Tuns32:
-        case Tfloat32:
-        case Timaginary32:
-            size = 4;
-            break;
-
-        case Tint64:
-        case Tuns64:
-        case Tfloat64:
-        case Timaginary64:
-            size = 8;
-            break;
-
-        case Tfloat80:
-        case Timaginary80:
-            size = target.realsize;
-            break;
-
-        case Tcomplex32:
-            size = 8;
-            break;
-
-        case Tcomplex64:
-        case Tint128:
-        case Tuns128:
-            size = 16;
-            break;
-
-        case Tcomplex80:
-            size = target.realsize * 2;
-            break;
-
-        case Tvoid:
-            //size = Type::size();      // error message
-            size = 1;
-            break;
-
-        case Tbool:
-            size = 1;
-            break;
-
-        case Tchar:
-            size = 1;
-            break;
-
-        case Twchar:
-            size = 2;
-            break;
-
-        case Tdchar:
-            size = 4;
-            break;
-
-        default:
-            assert(0);
-        }
-        //printf("TypeBasic::size() = %d\n", size);
-        return size;
-    }
-
     override uint alignsize()
     {
         return target.alignsize(this);
@@ -2234,98 +2125,6 @@ extern (C++) final class TypeBasic : Type
         return (flags & TFlags.unsigned) != 0;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeBasic::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
-        if (this == to)
-            return MATCH.exact;
-
-        if (ty == to.ty)
-        {
-            if (mod == to.mod)
-                return MATCH.exact;
-            else if (MODimplicitConv(mod, to.mod))
-                return MATCH.constant;
-            else if (!((mod ^ to.mod) & MODFlags.shared_)) // for wild matching
-                return MATCH.constant;
-            else
-                return MATCH.convert;
-        }
-
-        if (ty == Tvoid || to.ty == Tvoid)
-            return MATCH.nomatch;
-        if (to.ty == Tbool)
-            return MATCH.nomatch;
-
-        TypeBasic tob;
-        if (to.ty == Tvector && to.deco)
-        {
-            TypeVector tv = cast(TypeVector)to;
-            tob = tv.elementType();
-        }
-        else if (auto te = to.isTypeEnum())
-        {
-            EnumDeclaration ed = te.sym;
-            if (ed.isSpecial())
-            {
-                /* Special enums that allow implicit conversions to them
-                 * with a MATCH.convert
-                 */
-                tob = to.toBasetype().isTypeBasic();
-            }
-            else
-                return MATCH.nomatch;
-        }
-        else
-            tob = to.isTypeBasic();
-        if (!tob)
-            return MATCH.nomatch;
-
-        if (flags & TFlags.integral)
-        {
-            // Disallow implicit conversion of integers to imaginary or complex
-            if (tob.flags & (TFlags.imaginary | TFlags.complex))
-                return MATCH.nomatch;
-
-            // If converting from integral to integral
-            if (tob.flags & TFlags.integral)
-            {
-                const sz = size(Loc.initial);
-                const tosz = tob.size(Loc.initial);
-
-                /* Can't convert to smaller size
-                 */
-                if (sz > tosz)
-                    return MATCH.nomatch;
-                /* Can't change sign if same size
-                 */
-                //if (sz == tosz && (flags ^ tob.flags) & TFlags.unsigned)
-                //    return MATCH.nomatch;
-            }
-        }
-        else if (flags & TFlags.floating)
-        {
-            // Disallow implicit conversion of floating point to integer
-            if (tob.flags & TFlags.integral)
-                return MATCH.nomatch;
-
-            assert(tob.flags & TFlags.floating || to.ty == Tvector);
-
-            // Disallow implicit conversion from complex to non-complex
-            if (flags & TFlags.complex && !(tob.flags & TFlags.complex))
-                return MATCH.nomatch;
-
-            // Disallow implicit conversion of real or imaginary to complex
-            if (flags & (TFlags.real_ | TFlags.imaginary) && tob.flags & TFlags.complex)
-                return MATCH.nomatch;
-
-            // Disallow implicit conversion to-from real and imaginary
-            if ((flags & (TFlags.real_ | TFlags.imaginary)) != (tob.flags & (TFlags.real_ | TFlags.imaginary)))
-                return MATCH.nomatch;
-        }
-        return MATCH.convert;
-    }
-
     override bool isZeroInit(const ref Loc loc)
     {
         switch (ty)
@@ -2396,11 +2195,6 @@ extern (C++) final class TypeVector : Type
         return new TypeVector(basetype.syntaxCopy());
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return basetype.size();
-    }
-
     override uint alignsize()
     {
         return cast(uint)basetype.size();
@@ -2432,29 +2226,6 @@ extern (C++) final class TypeVector : Type
         return false;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeVector::implicitConvTo(%s) from %s\n", to.toChars(), toChars());
-        if (this == to)
-            return MATCH.exact;
-        if (to.ty != Tvector)
-            return MATCH.nomatch;
-
-        TypeVector tv = cast(TypeVector)to;
-        assert(basetype.ty == Tsarray && tv.basetype.ty == Tsarray);
-
-        // Can't convert to a vector which has different size.
-        if (basetype.size() != tv.basetype.size())
-            return MATCH.nomatch;
-
-        // Allow conversion to void[]
-        if (tv.basetype.nextOf().ty == Tvoid)
-            return MATCH.convert;
-
-        // Otherwise implicitly convertible only if basetypes are.
-        return basetype.implicitConvTo(tv.basetype);
-    }
-
     override Expression defaultInitLiteral(const ref Loc loc)
     {
         //printf("TypeVector::defaultInitLiteral()\n");
@@ -2545,22 +2316,6 @@ extern (C++) final class TypeSArray : TypeArray
         return dim.isIntegerExp() && dim.isIntegerExp().getInteger() == 0;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        //printf("TypeSArray::size()\n");
-        const n = numberOfElems(loc);
-        const elemsize = baseElemOf().size(loc);
-        bool overflow = false;
-        const sz = mulu(n, elemsize, overflow);
-        if (overflow || sz >= uint.max)
-        {
-            if (elemsize != SIZE_INVALID && n != uint.max)
-                error(loc, "static array `%s` size overflowed to %lld", toChars(), cast(long)sz);
-            return SIZE_INVALID;
-        }
-        return sz;
-    }
-
     override uint alignsize()
     {
         return next.alignsize();
@@ -2592,65 +2347,6 @@ extern (C++) final class TypeSArray : TypeArray
         return TypeNext.constConv(to);
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeSArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
-        if (auto ta = to.isTypeDArray())
-        {
-            if (!MODimplicitConv(next.mod, ta.next.mod))
-                return MATCH.nomatch;
-
-            /* Allow conversion to void[]
-             */
-            if (ta.next.ty == Tvoid)
-            {
-                return MATCH.convert;
-            }
-
-            MATCH m = next.constConv(ta.next);
-            if (m > MATCH.nomatch)
-            {
-                return MATCH.convert;
-            }
-            return MATCH.nomatch;
-        }
-        if (auto tsa = to.isTypeSArray())
-        {
-            if (this == to)
-                return MATCH.exact;
-
-            if (dim.equals(tsa.dim))
-            {
-                MATCH m = next.implicitConvTo(tsa.next);
-
-                /* Allow conversion to non-interface base class.
-                 */
-                if (m == MATCH.convert &&
-                    next.ty == Tclass)
-                {
-                    if (auto toc = tsa.next.isTypeClass)
-                    {
-                        if (!toc.sym.isInterfaceDeclaration)
-                            return MATCH.convert;
-                    }
-                }
-
-                /* Since static arrays are value types, allow
-                 * conversions from const elements to non-const
-                 * ones, just like we allow conversion from const int
-                 * to int.
-                 */
-                if (m >= MATCH.constant)
-                {
-                    if (mod != to.mod)
-                        m = MATCH.constant;
-                    return m;
-                }
-            }
-        }
-        return MATCH.nomatch;
-    }
-
     override Expression defaultInitLiteral(const ref Loc loc)
     {
         static if (LOGDEFAULTINIT)
@@ -2736,12 +2432,6 @@ extern (C++) final class TypeDArray : TypeArray
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        //printf("TypeDArray::size()\n");
-        return target.ptrsize * 2;
-    }
-
     override uint alignsize()
     {
         // A DArray consists of two ptr-sized values, so align it on pointer size
@@ -2765,35 +2455,6 @@ extern (C++) final class TypeDArray : TypeArray
         return true;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeDArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
-        if (equals(to))
-            return MATCH.exact;
-
-        if (auto ta = to.isTypeDArray())
-        {
-            if (!MODimplicitConv(next.mod, ta.next.mod))
-                return MATCH.nomatch; // not const-compatible
-
-            /* Allow conversion to void[]
-             */
-            if (next.ty != Tvoid && ta.next.ty == Tvoid)
-            {
-                return MATCH.convert;
-            }
-
-            MATCH m = next.constConv(ta.next);
-            if (m > MATCH.nomatch)
-            {
-                if (m == MATCH.exact && mod != to.mod)
-                    m = MATCH.constant;
-                return m;
-            }
-        }
-        return Type.implicitConvTo(to);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2835,11 +2496,6 @@ extern (C++) final class TypeAArray : TypeArray
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return target.ptrsize;
-    }
-
     override bool isZeroInit(const ref Loc loc)
     {
         return true;
@@ -2850,30 +2506,6 @@ extern (C++) final class TypeAArray : TypeArray
         return true;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeAArray::implicitConvTo(to = %s) this = %s\n", to.toChars(), toChars());
-        if (equals(to))
-            return MATCH.exact;
-
-        if (auto ta = to.isTypeAArray())
-        {
-            if (!MODimplicitConv(next.mod, ta.next.mod))
-                return MATCH.nomatch; // not const-compatible
-
-            if (!MODimplicitConv(index.mod, ta.index.mod))
-                return MATCH.nomatch; // not const-compatible
-
-            MATCH m = next.constConv(ta.next);
-            MATCH mi = index.constConv(ta.index);
-            if (m > MATCH.nomatch && mi > MATCH.nomatch)
-            {
-                return MODimplicitConv(mod, to.mod) ? MATCH.constant : MATCH.nomatch;
-            }
-        }
-        return Type.implicitConvTo(to);
-    }
-
     override MATCH constConv(Type to)
     {
         if (auto taa = to.isTypeAArray())
@@ -2922,50 +2554,6 @@ extern (C++) final class TypePointer : TypeNext
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return target.ptrsize;
-    }
-
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypePointer::implicitConvTo(to = %s) %s\n", to.toChars(), toChars());
-        if (equals(to))
-            return MATCH.exact;
-
-        // Only convert between pointers
-        auto tp = to.isTypePointer();
-        if (!tp)
-            return MATCH.nomatch;
-
-        assert(this.next);
-        assert(tp.next);
-
-        // Conversion to void*
-        if (tp.next.ty == Tvoid)
-        {
-            // Function pointer conversion doesn't check constness?
-            if (this.next.ty == Tfunction)
-                return MATCH.convert;
-
-            if (!MODimplicitConv(next.mod, tp.next.mod))
-                return MATCH.nomatch; // not const-compatible
-
-            return this.next.ty == Tvoid ? MATCH.constant : MATCH.convert;
-        }
-
-        // Conversion between function pointers
-        if (auto thisTf = this.next.isTypeFunction())
-            return thisTf.implicitPointerConv(tp.next);
-
-        // Default, no implicit conversion between the pointer targets
-        MATCH m = next.constConv(tp.next);
-
-        if (m == MATCH.exact && mod != to.mod)
-            m = MATCH.constant;
-        return m;
-    }
-
     override MATCH constConv(Type to)
     {
         if (next.ty == Tfunction)
@@ -3020,11 +2608,6 @@ extern (C++) final class TypeReference : TypeNext
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return target.ptrsize;
-    }
-
     override bool isZeroInit(const ref Loc loc)
     {
         return true;
@@ -3285,47 +2868,6 @@ extern (C++) final class TypeFunction : TypeNext
         return newArgs;
     }
 
-    /+
-     + Checks whether this function type is convertible to ` to`
-     + when used in a function pointer / delegate.
-     +
-     + Params:
-     +   to = target type
-     +
-     + Returns:
-     +   MATCH.nomatch: `to` is not a covaraint function
-     +   MATCH.convert: `to` is a covaraint function
-     +   MATCH.exact:   `to` is identical to this function
-     +/
-    private MATCH implicitPointerConv(Type to)
-    {
-        assert(to);
-
-        if (this.equals(to))
-            return MATCH.constant;
-
-        if (this.covariant(to) == Covariant.yes)
-        {
-            Type tret = this.nextOf();
-            Type toret = to.nextOf();
-            if (tret.ty == Tclass && toret.ty == Tclass)
-            {
-                /* https://issues.dlang.org/show_bug.cgi?id=10219
-                 * Check covariant interface return with offset tweaking.
-                 * interface I {}
-                 * class C : Object, I {}
-                 * I function() dg = function C() {}    // should be error
-                 */
-                int offset = 0;
-                if (toret.isBaseOf(tret, &offset) && offset != 0)
-                    return MATCH.nomatch;
-            }
-            return MATCH.convert;
-        }
-
-        return MATCH.nomatch;
-    }
-
     /** Extends TypeNext.constConv by also checking for matching attributes **/
     override MATCH constConv(Type to)
     {
@@ -3447,39 +2989,11 @@ extern (C++) final class TypeDelegate : TypeNext
         return result;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return target.ptrsize * 2;
-    }
-
     override uint alignsize()
     {
         return target.ptrsize;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeDelegate.implicitConvTo(this=%p, to=%p)\n", this, to);
-        //printf("from: %s\n", toChars());
-        //printf("to  : %s\n", to.toChars());
-        if (this.equals(to))
-            return MATCH.exact;
-
-        if (auto toDg = to.isTypeDelegate())
-        {
-            MATCH m = this.next.isTypeFunction().implicitPointerConv(toDg.next);
-
-            // Retain the old behaviour for this refactoring
-            // Should probably be changed to constant to match function pointers
-            if (m > MATCH.convert)
-                m = MATCH.convert;
-
-            return m;
-        }
-
-        return MATCH.nomatch;
-    }
-
     override bool isZeroInit(const ref Loc loc)
     {
         return true;
@@ -3534,11 +3048,6 @@ extern (C++) final class TypeTraits : Type
     {
         v.visit(this);
     }
-
-    override uinteger_t size(const ref Loc loc)
-    {
-        return SIZE_INVALID;
-    }
 }
 
 /******
@@ -3648,12 +3157,6 @@ extern (C++) abstract class TypeQualified : Type
         idents.push(e);
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        error(this.loc, "size of type `%s` is not known", toChars());
-        return SIZE_INVALID;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3759,14 +3262,6 @@ extern (C++) final class TypeTypeof : TypeQualified
         return t;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        if (exp.type)
-            return exp.type.size(loc);
-        else
-            return TypeQualified.size(loc);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -3825,11 +3320,6 @@ extern (C++) final class TypeStruct : Type
         return "struct";
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return sym.size(loc);
-    }
-
     override uint alignsize()
     {
         sym.size(Loc.initial); // give error for forward references
@@ -3895,7 +3385,7 @@ extern (C++) final class TypeStruct : Type
         /* Copy from the initializer symbol for larger symbols,
          * otherwise the literals expressed as code get excessively large.
          */
-        if (size(loc) > target.ptrsize * 4 && !needsNested())
+        if (size(this, loc) > target.ptrsize * 4 && !needsNested())
             structinit.useStaticInit = true;
 
         structinit.type = this;
@@ -4028,7 +3518,7 @@ extern (C++) final class TypeStruct : Type
              * The check should check for overlap of v with the previous field,
              * not just starting at the same point
              */
-            if (v.offset == offset) // v is at same offset as previous field
+            if (!global.params.fixImmutableConv && v.offset == offset) // v is at same offset as previous field
                 continue;       // ignore
 
             Type tvf = v.type.addMod(mod);    // from type
@@ -4065,13 +3555,6 @@ extern (C++) final class TypeStruct : Type
         return MATCH.nomatch;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeStruct::implicitConvTo(%s => %s)\n", toChars(), to.toChars());
-        MATCH m = implicitConvToWithoutAliasThis(to);
-        return m == MATCH.nomatch ? implicitConvToThroughAliasThis(to) : m;
-    }
-
     override MATCH constConv(Type to)
     {
         if (equals(to))
@@ -4129,11 +3612,6 @@ extern (C++) final class TypeEnum : Type
         return this;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return sym.getMemtype(loc).size(loc);
-    }
-
     Type memType()
     {
         return sym.getMemtype(Loc.initial);
@@ -4212,19 +3690,6 @@ extern (C++) final class TypeEnum : Type
         return memType().needsNested();
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        MATCH m;
-        //printf("TypeEnum::implicitConvTo() %s to %s\n", toChars(), to.toChars());
-        if (ty == to.ty && sym == (cast(TypeEnum)to).sym)
-            m = (mod == to.mod) ? MATCH.exact : MATCH.constant;
-        else if (sym.getMemtype(Loc.initial).implicitConvTo(to))
-            m = MATCH.convert; // match with conversions
-        else
-            m = MATCH.nomatch; // no match
-        return m;
-    }
-
     override MATCH constConv(Type to)
     {
         if (equals(to))
@@ -4292,11 +3757,6 @@ extern (C++) final class TypeClass : Type
         return "class";
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return target.ptrsize;
-    }
-
     override TypeClass syntaxCopy()
     {
         return this;
@@ -4337,13 +3797,6 @@ extern (C++) final class TypeClass : Type
         return m;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeClass::implicitConvTo(to = '%s') %s\n", to.toChars(), toChars());
-        MATCH m = implicitConvToWithoutAliasThis(to);
-        return m ? m : implicitConvToThroughAliasThis(to);
-    }
-
     override MATCH constConv(Type to)
     {
         if (equals(to))
@@ -4542,29 +3995,6 @@ extern (C++) final class TypeTuple : Type
         return false;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        if (this == to)
-            return MATCH.exact;
-        if (auto tt = to.isTypeTuple())
-        {
-            if (arguments.length == tt.arguments.length)
-            {
-                MATCH m = MATCH.exact;
-                for (size_t i = 0; i < tt.arguments.length; i++)
-                {
-                    Parameter arg1 = (*arguments)[i];
-                    Parameter arg2 = (*tt.arguments)[i];
-                    MATCH mi = arg1.type.implicitConvTo(arg2.type);
-                    if (mi < m)
-                        m = mi;
-                }
-                return m;
-            }
-        }
-        return MATCH.nomatch;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4626,36 +4056,11 @@ extern (C++) final class TypeNull : Type
         return this;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeNull::implicitConvTo(this=%p, to=%p)\n", this, to);
-        //printf("from: %s\n", toChars());
-        //printf("to  : %s\n", to.toChars());
-        MATCH m = Type.implicitConvTo(to);
-        if (m != MATCH.nomatch)
-            return m;
-
-        // NULL implicitly converts to any pointer type or dynamic array
-        //if (type.ty == Tpointer && type.nextOf().ty == Tvoid)
-        {
-            Type tb = to.toBasetype();
-            if (tb.ty == Tnull || tb.ty == Tpointer || tb.ty == Tarray || tb.ty == Taarray || tb.ty == Tclass || tb.ty == Tdelegate)
-                return MATCH.constant;
-        }
-
-        return MATCH.nomatch;
-    }
-
     override bool isBoolean()
     {
         return true;
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return tvoidptr.size(loc);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4683,22 +4088,6 @@ extern (C++) final class TypeNoreturn : Type
         return this;
     }
 
-    override MATCH implicitConvTo(Type to)
-    {
-        //printf("TypeNoreturn::implicitConvTo(this=%p, to=%p)\n", this, to);
-        //printf("from: %s\n", toChars());
-        //printf("to  : %s\n", to.toChars());
-        if (this.equals(to))
-            return MATCH.exact;
-
-        // Different qualifiers?
-        if (to.ty == Tnoreturn)
-            return MATCH.constant;
-
-        // Implicitly convertible to any type
-        return MATCH.convert;
-    }
-
     override MATCH constConv(Type to)
     {
         // Either another noreturn or conversion to any type
@@ -4710,11 +4099,6 @@ extern (C++) final class TypeNoreturn : Type
         return true;  // bottom type can be implicitly converted to any other type
     }
 
-    override uinteger_t size(const ref Loc loc)
-    {
-        return 0;
-    }
-
     override uint alignsize()
     {
         return 0;
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 1121711a99fa6ecfb26a2169e3b0283a89cb1509..11c27c67abadd82e8bf789f51dc51c59f63b0b89 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -228,8 +228,6 @@ public:
     char *toPrettyChars(bool QualifyTypes = false);
     static void _init();
 
-    uinteger_t size();
-    virtual uinteger_t size(const Loc &loc);
     virtual unsigned alignsize();
     void modToBuffer(OutBuffer& buf) const;
     char *modToChars() const;
@@ -266,7 +264,6 @@ public:
     virtual Type *makeSharedWildConst();
     virtual Type *makeMutable();
     Type *toBasetype();
-    virtual MATCH implicitConvTo(Type *to);
     virtual MATCH constConv(Type *to);
     virtual unsigned char deduceWild(Type *t, bool isRef);
 
@@ -323,7 +320,6 @@ public:
     const char *kind() override;
     TypeError *syntaxCopy() override;
 
-    uinteger_t size(const Loc &loc) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -358,7 +354,6 @@ public:
 
     const char *kind() override;
     TypeBasic *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     bool isintegral() override;
     bool isfloating() override;
@@ -367,7 +362,6 @@ public:
     bool iscomplex() override;
     bool isscalar() override;
     bool isunsigned() override;
-    MATCH implicitConvTo(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
 
     // For eliminating dynamic_cast
@@ -383,14 +377,12 @@ public:
     static TypeVector *create(Type *basetype);
     const char *kind() override;
     TypeVector *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     bool isintegral() override;
     bool isfloating() override;
     bool isscalar() override;
     bool isunsigned() override;
     bool isBoolean() override;
-    MATCH implicitConvTo(Type *to) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     TypeBasic *elementType();
     bool isZeroInit(const Loc &loc) override;
@@ -413,13 +405,11 @@ public:
     const char *kind() override;
     TypeSArray *syntaxCopy() override;
     bool isIncomplete();
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     bool isString() override;
     bool isZeroInit(const Loc &loc) override;
     structalign_t alignment() override;
     MATCH constConv(Type *to) override;
-    MATCH implicitConvTo(Type *to) override;
     Expression *defaultInitLiteral(const Loc &loc) override;
     bool hasUnsafeBitpatterns() override;
     bool hasVoidInitPointers() override;
@@ -437,12 +427,10 @@ class TypeDArray final : public TypeArray
 public:
     const char *kind() override;
     TypeDArray *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     bool isString() override;
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
-    MATCH implicitConvTo(Type *to) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -456,10 +444,8 @@ public:
     static TypeAArray *create(Type *t, Type *index);
     const char *kind() override;
     TypeAArray *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
-    MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -471,8 +457,6 @@ public:
     static TypePointer *create(Type *t);
     const char *kind() override;
     TypePointer *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
-    MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     bool isscalar() override;
     bool isZeroInit(const Loc &loc) override;
@@ -485,7 +469,6 @@ class TypeReference final : public TypeNext
 public:
     const char *kind() override;
     TypeReference *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     bool isZeroInit(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -615,9 +598,7 @@ public:
     static TypeDelegate *create(TypeFunction *t);
     const char *kind() override;
     TypeDelegate *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
-    MATCH implicitConvTo(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
     bool isBoolean() override;
 
@@ -634,7 +615,6 @@ class TypeTraits final : public Type
 
     const char *kind() override;
     TypeTraits *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -657,7 +637,6 @@ public:
     // representing ident.ident!tiargs.ident. ... etc.
     Objects idents;
 
-    uinteger_t size(const Loc &loc) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -694,7 +673,6 @@ public:
 
     const char *kind() override;
     TypeTypeof *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -727,7 +705,6 @@ public:
 
     static TypeStruct *create(StructDeclaration *sym);
     const char *kind() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     TypeStruct *syntaxCopy() override;
     structalign_t alignment() override;
@@ -741,7 +718,6 @@ public:
     bool hasVoidInitPointers() override;
     bool hasUnsafeBitpatterns() override;
     bool hasInvariant() override;
-    MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override;
 
@@ -755,7 +731,6 @@ public:
 
     const char *kind() override;
     TypeEnum *syntaxCopy() override;
-    uinteger_t size(const Loc &loc) override;
     unsigned alignsize() override;
     Type *memType(const Loc &loc);
     bool isintegral() override;
@@ -771,7 +746,6 @@ public:
     bool needsDestruction() override;
     bool needsCopyOrPostblit() override;
     bool needsNested() override;
-    MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     bool isZeroInit(const Loc &loc) override;
     bool hasVoidInitPointers() override;
@@ -790,10 +764,8 @@ public:
     CPPMANGLE cppmangle;
 
     const char *kind() override;
-    uinteger_t size(const Loc &loc) override;
     TypeClass *syntaxCopy() override;
     ClassDeclaration *isClassHandle() override;
-    MATCH implicitConvTo(Type *to) override;
     MATCH constConv(Type *to) override;
     unsigned char deduceWild(Type *t, bool isRef) override;
     bool isZeroInit(const Loc &loc) override;
@@ -838,10 +810,8 @@ public:
     const char *kind() override;
 
     TypeNull *syntaxCopy() override;
-    MATCH implicitConvTo(Type *to) override;
     bool isBoolean() override;
 
-    uinteger_t size(const Loc &loc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -850,10 +820,8 @@ class TypeNoreturn final : public Type
 public:
     const char *kind() override;
     TypeNoreturn *syntaxCopy() override;
-    MATCH implicitConvTo(Type* to) override;
     MATCH constConv(Type* to) override;
     bool isBoolean() override;
-    uinteger_t size(const Loc& loc) override;
     unsigned alignsize() override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -902,4 +870,7 @@ namespace dmd
     Type *addMod(Type *type, MOD mod);
     Type *addStorageClass(Type *type, StorageClass stc);
     Type *substWildTo(Type *type, unsigned mod);
+    uinteger_t size(Type *type);
+    uinteger_t size(Type *type, const Loc &loc);
+    MATCH implicitConvTo(Type* from, Type* to);
 }
diff --git a/gcc/d/dmd/objc.d b/gcc/d/dmd/objc.d
index 624210bf527905a2d11f0e5c76400e2ac7f64d93..a9227195e816336f099356d85730de7dbf7ebead 100644
--- a/gcc/d/dmd/objc.d
+++ b/gcc/d/dmd/objc.d
@@ -96,7 +96,7 @@ struct ObjcSelector
     extern (C++) static ObjcSelector* create(FuncDeclaration fdecl)
     {
         OutBuffer buf;
-        TypeFunction ftype = cast(TypeFunction)fdecl.type;
+        auto ftype = cast(TypeFunction)fdecl.type;
         const id = fdecl.ident.toString();
         const nparams = ftype.parameterList.length;
         // Special case: property setter
@@ -571,7 +571,7 @@ extern(C++) private final class Supported : Objc
     {
         if (!fd.objc.selector)
             return;
-        TypeFunction tf = cast(TypeFunction)fd.type;
+        auto tf = cast(TypeFunction)fd.type;
         if (fd.objc.selector.paramCount != tf.parameterList.parameters.length)
             .error(fd.loc, "%s `%s` number of colons in Objective-C selector must match number of parameters", fd.kind, fd.toPrettyChars);
         if (fd.parent && fd.parent.isTemplateInstance())
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 2c89a58d5d23f3b2fa6f66ae151f5303bd81408a..ab1b67c53be1dd994acd73e9e7ad6f22d59cd88b 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -110,7 +110,7 @@ Expression expandVar(int result, VarDeclaration v)
                 }
                 if (ei.op == EXP.construct || ei.op == EXP.blit)
                 {
-                    AssignExp ae = cast(AssignExp)ei;
+                    auto ae = cast(AssignExp)ei;
                     ei = ae.e2;
                     if (ei.isConst() == 1)
                     {
@@ -1238,18 +1238,21 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
         if (expOptimize(e.e1, WANTvalue))
             return;
         const oror = e.op == EXP.orOr;
-        if (e.e1.toBool().hasValue(oror))
+        void returnE_e1()
         {
-            // Replace with (e1, oror)
-            ret = IntegerExp.createBool(oror);
-            ret = Expression.combine(e.e1, ret);
-            if (e.type.toBasetype().ty == Tvoid)
+            ret = e.e1;
+            if (!e.e1.type.equals(e.type))
             {
-                ret = new CastExp(e.loc, ret, Type.tvoid);
+                ret = new CastExp(e.loc, ret, e.type);
                 ret.type = e.type;
+                ret = optimize(ret, result, false);
             }
-            ret = optimize(ret, result, false);
-            return;
+        }
+        if (e.e1.toBool().hasValue(oror))
+        {
+            // e_true || e2 -> e_true
+            // e_false && e2 -> e_false
+            return returnE_e1();
         }
         expOptimize(e.e2, WANTvalue);
         if (e.e1.isConst())
@@ -1263,6 +1266,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
             }
             else if (e1Opt.hasValue(!oror))
             {
+
                 if (e.type.toBasetype().ty == Tvoid)
                     ret = e.e2;
                 else
@@ -1272,6 +1276,29 @@ Expression optimize(Expression e, int result, bool keepLvalue = false)
                 }
             }
         }
+        else if (e.e2.isConst())
+        {
+            const e2Opt = e.e2.toBool();
+            if (e2Opt.hasValue(oror))
+            {
+                // e1 || true -> (e1, true)
+                // e1 && false -> (e1, false)
+                ret = IntegerExp.createBool(oror);
+                ret = Expression.combine(e.e1, ret);
+                if (e.type.toBasetype().ty == Tvoid)
+                {
+                    ret = new CastExp(e.loc, ret, Type.tvoid);
+                    ret.type = e.type;
+                }
+                ret = optimize(ret, result, false);
+            }
+            else if (e2Opt.hasValue(!oror))
+            {
+                // e1 || false -> e1
+                // e1 && true -> e1
+                return returnE_e1();
+            }
+        }
     }
 
     void visitCmp(CmpExp e)
diff --git a/gcc/d/dmd/safe.d b/gcc/d/dmd/safe.d
index 5064ac2d9cdbf5ff41ea7d8855d96ecb4a66c28e..f1bd6c98c80fced7c3c45dba45ae3fce43c14b95 100644
--- a/gcc/d/dmd/safe.d
+++ b/gcc/d/dmd/safe.d
@@ -17,6 +17,7 @@ import core.stdc.stdio;
 
 import dmd.aggregate;
 import dmd.astenums;
+import dmd.dcast : implicitConvTo;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dscope;
@@ -26,7 +27,7 @@ import dmd.identifier;
 import dmd.mtype;
 import dmd.target;
 import dmd.tokens;
-import dmd.typesem : hasPointers, arrayOf;
+import dmd.typesem : hasPointers, arrayOf, size;
 import dmd.funcsem : setUnsafe, setUnsafePreview;
 
 /*************************************************************
@@ -49,7 +50,7 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
     //printf("checkUnsafeAccess(e: '%s', readonly: %d, printmsg: %d)\n", e.toChars(), readonly, printmsg);
     if (e.op != EXP.dotVariable)
         return false;
-    DotVarExp dve = cast(DotVarExp)e;
+    auto dve = cast(DotVarExp)e;
     if (VarDeclaration v = dve.var.isVarDeclaration())
     {
         if (!sc.func)
@@ -156,10 +157,11 @@ bool checkUnsafeAccess(Scope* sc, Expression e, bool readonly, bool printmsg)
  *      e = expression to be cast
  *      tfrom = type of e
  *      tto = type to cast e to
+ *      msg = reason why cast is unsafe or deprecated
  * Returns:
- *      true if @safe
+ *      true if @safe or deprecated
  */
-bool isSafeCast(Expression e, Type tfrom, Type tto)
+bool isSafeCast(Expression e, Type tfrom, Type tto, ref string msg)
 {
     // Implicit conversions are always safe
     if (tfrom.implicitConvTo(tto))
@@ -175,18 +177,34 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
     {
         ClassDeclaration cdfrom = tfromb.isClassHandle();
         ClassDeclaration cdto = ttob.isClassHandle();
-
         int offset;
+
+        if (cdfrom == cdto)
+            goto Lsame;
+
         if (!cdfrom.isBaseOf(cdto, &offset) &&
             !((cdfrom.isInterfaceDeclaration() || cdto.isInterfaceDeclaration())
                 && cdfrom.classKind == ClassKind.d && cdto.classKind == ClassKind.d))
+        {
+            msg = "Source object type is incompatible with target type";
             return false;
+        }
 
+        // no RTTI
         if (cdfrom.isCPPinterface() || cdto.isCPPinterface())
+        {
+            msg = "No dynamic type information for extern(C++) classes";
             return false;
+        }
+        if (cdfrom.classKind == ClassKind.cpp || cdto.classKind == ClassKind.cpp)
+            msg = "No dynamic type information for extern(C++) classes";
 
+    Lsame:
         if (!MODimplicitConv(tfromb.mod, ttob.mod))
+        {
+            msg = "Incompatible type qualifier";
             return false;
+        }
         return true;
     }
 
@@ -210,22 +228,52 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
         {
             if (ttob.ty == Tarray && e.op == EXP.arrayLiteral)
                 return true;
+            msg = "`void` data may contain pointers and target element type is mutable";
             return false;
         }
 
         // If the struct is opaque we don't know about the struct members then the cast becomes unsafe
-        if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members ||
-            tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+        if (ttobn.ty == Tstruct && !(cast(TypeStruct)ttobn).sym.members)
+        {
+            msg = "Target element type is opaque";
+            return false;
+        }
+        if (tfromn.ty == Tstruct && !(cast(TypeStruct)tfromn).sym.members)
+        {
+            msg = "Source element type is opaque";
             return false;
+        }
+
+        if (e.op != EXP.arrayLiteral)
+        {
+            // For bool, only 0 and 1 are safe values
+            // Runtime array cast reinterprets data
+            if (ttobn.ty == Tbool && tfromn.ty != Tbool)
+                msg = "Source element may have bytes which are not 0 or 1";
+            else if (ttobn.hasUnsafeBitpatterns())
+                msg = "Target element type has unsafe bit patterns";
+
+            // Can't alias a bool pointer with a non-bool pointer
+            if (ttobn.ty != Tbool && tfromn.ty == Tbool && ttobn.isMutable())
+                msg = "Target element could be assigned a byte which is not 0 or 1";
+            else if (tfromn.hasUnsafeBitpatterns() && ttobn.isMutable())
+                msg = "Source element type has unsafe bit patterns and target element type is mutable";
+        }
 
         const frompointers = tfromn.hasPointers();
         const topointers = ttobn.hasPointers();
 
         if (frompointers && !topointers && ttobn.isMutable())
+        {
+            msg = "Target element type is mutable and source element type contains a pointer";
             return false;
+        }
 
         if (!frompointers && topointers)
+        {
+            msg = "Target element type contains a pointer";
             return false;
+        }
 
         if (!topointers &&
             ttobn.ty != Tfunction && tfromn.ty != Tfunction &&
@@ -235,6 +283,7 @@ bool isSafeCast(Expression e, Type tfrom, Type tto)
             return true;
         }
     }
+    msg = "Source type is incompatible with target type containing a pointer";
     return false;
 }
 
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 4bb39028f0418a9da1a66fc4106d077790e1ac3b..06a5eef47bf18a02f41fae9f11f4017eb81ccf54 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -315,7 +315,7 @@ private extern(C++) final class Semantic2Visitor : Visitor
                         return arrayHasInvalidEnumInitializer((cast(StructLiteralExp)e).elements);
                     if (e.op == EXP.assocArrayLiteral)
                     {
-                        AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e;
+                        auto ae = cast(AssocArrayLiteralExp)e;
                         return arrayHasInvalidEnumInitializer(ae.values) ||
                                arrayHasInvalidEnumInitializer(ae.keys);
                     }
@@ -888,4 +888,11 @@ private extern(C++) final class StaticAAVisitor : SemanticTimeTransitiveVisitor
 
         aaExp.lowering = loweredExp;
     }
+
+    // https://issues.dlang.org/show_bug.cgi?id=24602
+    // TODO: Is this intionally not visited by SemanticTimeTransitiveVisitor?
+    override void visit(ClassReferenceExp crExp)
+    {
+        this.visit(crExp.value);
+    }
 }
diff --git a/gcc/d/dmd/sideeffect.d b/gcc/d/dmd/sideeffect.d
index 1d4745afbc1996a717d20469376e817c68c53f56..57a6639575c9c5693aa26691c23cf69e4da1fec0 100644
--- a/gcc/d/dmd/sideeffect.d
+++ b/gcc/d/dmd/sideeffect.d
@@ -18,6 +18,7 @@ import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
+import dmd.funcsem;
 import dmd.globals;
 import dmd.id;
 import dmd.identifier;
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index a79b78acf247830fdf4353f5274d75cfb9508f2e..81891ff7aa6b87f1540782206c8d3644a625667f 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -267,57 +267,58 @@ extern (C++) abstract class Statement : ASTNode
     pure nothrow @nogc
     inout(ReturnStatement) endsWithReturnStatement() inout { return null; }
 
-    final pure inout nothrow @nogc @safe:
-
-    /********************
-     * A cheaper method of doing downcasting of Statements.
-     * Returns:
-     *    the downcast statement if it can be downcasted, otherwise `null`
-     */
-    inout(ErrorStatement)       isErrorStatement()       { return stmt == STMT.Error       ? cast(typeof(return))this : null; }
-    inout(PeelStatement)        isPeelStatement()        { return stmt == STMT.Peel        ? cast(typeof(return))this : null; }
-    inout(ScopeStatement)       isScopeStatement()       { return stmt == STMT.Scope       ? cast(typeof(return))this : null; }
-    inout(ExpStatement)         isExpStatement()         { return stmt == STMT.Exp         ? cast(typeof(return))this : null; }
-    inout(CompoundStatement)    isCompoundStatement()    { return stmt == STMT.Compound    ? cast(typeof(return))this : null; }
-    inout(ReturnStatement)      isReturnStatement()      { return stmt == STMT.Return      ? cast(typeof(return))this : null; }
-    inout(IfStatement)          isIfStatement()          { return stmt == STMT.If          ? cast(typeof(return))this : null; }
-    inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
-    inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
-    inout(CaseStatement)        isCaseStatement()        { return stmt == STMT.Case        ? cast(typeof(return))this : null; }
-    inout(DefaultStatement)     isDefaultStatement()     { return stmt == STMT.Default     ? cast(typeof(return))this : null; }
-    inout(LabelStatement)       isLabelStatement()       { return stmt == STMT.Label       ? cast(typeof(return))this : null; }
-    inout(GotoStatement)        isGotoStatement()        { return stmt == STMT.Goto        ? cast(typeof(return))this : null; }
-    inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
-    inout(GotoCaseStatement)    isGotoCaseStatement()    { return stmt == STMT.GotoCase    ? cast(typeof(return))this : null; }
-    inout(BreakStatement)       isBreakStatement()       { return stmt == STMT.Break       ? cast(typeof(return))this : null; }
-    inout(DtorExpStatement)     isDtorExpStatement()     { return stmt == STMT.DtorExp     ? cast(typeof(return))this : null; }
-    inout(MixinStatement)       isMixinStatement()       { return stmt == STMT.Mixin       ? cast(typeof(return))this : null; }
-    inout(ForwardingStatement)  isForwardingStatement()  { return stmt == STMT.Forwarding  ? cast(typeof(return))this : null; }
-    inout(DoStatement)          isDoStatement()          { return stmt == STMT.Do          ? cast(typeof(return))this : null; }
-    inout(WhileStatement)       isWhileStatement()       { return stmt == STMT.While       ? cast(typeof(return))this : null; }
-    inout(ForStatement)         isForStatement()         { return stmt == STMT.For         ? cast(typeof(return))this : null; }
-    inout(ForeachStatement)     isForeachStatement()     { return stmt == STMT.Foreach     ? cast(typeof(return))this : null; }
-    inout(SwitchStatement)      isSwitchStatement()      { return stmt == STMT.Switch      ? cast(typeof(return))this : null; }
-    inout(ContinueStatement)    isContinueStatement()    { return stmt == STMT.Continue    ? cast(typeof(return))this : null; }
-    inout(WithStatement)        isWithStatement()        { return stmt == STMT.With        ? cast(typeof(return))this : null; }
-    inout(TryCatchStatement)    isTryCatchStatement()    { return stmt == STMT.TryCatch    ? cast(typeof(return))this : null; }
-    inout(ThrowStatement)       isThrowStatement()       { return stmt == STMT.Throw       ? cast(typeof(return))this : null; }
-    inout(DebugStatement)       isDebugStatement()       { return stmt == STMT.Debug       ? cast(typeof(return))this : null; }
-    inout(TryFinallyStatement)  isTryFinallyStatement()  { return stmt == STMT.TryFinally  ? cast(typeof(return))this : null; }
-    inout(ScopeGuardStatement)  isScopeGuardStatement()  { return stmt == STMT.ScopeGuard  ? cast(typeof(return))this : null; }
-    inout(SwitchErrorStatement)  isSwitchErrorStatement()  { return stmt == STMT.SwitchError  ? cast(typeof(return))this : null; }
-    inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
-    inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
-    inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
-    inout(CompoundAsmStatement)  isCompoundAsmStatement()  { return stmt == STMT.CompoundAsm  ? cast(typeof(return))this : null; }
-    inout(PragmaStatement)       isPragmaStatement()       { return stmt == STMT.Pragma       ? cast(typeof(return))this : null; }
-    inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
-    inout(CaseRangeStatement)    isCaseRangeStatement()    { return stmt == STMT.CaseRange    ? cast(typeof(return))this : null; }
-    inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
-    inout(AsmStatement)          isAsmStatement()          { return stmt == STMT.Asm          ? cast(typeof(return))this : null; }
-    inout(InlineAsmStatement)    isInlineAsmStatement()    { return stmt == STMT.InlineAsm    ? cast(typeof(return))this : null; }
-    inout(GccAsmStatement)       isGccAsmStatement()       { return stmt == STMT.GccAsm       ? cast(typeof(return))this : null; }
-    inout(ImportStatement)       isImportStatement()       { return stmt == STMT.Import       ? cast(typeof(return))this : null; }
+    final pure inout nothrow @nogc @trusted
+    {
+        /********************
+         * A cheaper method of doing downcasting of Statements.
+         * Returns:
+         *    the downcast statement if it can be downcasted, otherwise `null`
+         */
+        inout(ErrorStatement)       isErrorStatement()       { return stmt == STMT.Error       ? cast(typeof(return))this : null; }
+        inout(PeelStatement)        isPeelStatement()        { return stmt == STMT.Peel        ? cast(typeof(return))this : null; }
+        inout(ScopeStatement)       isScopeStatement()       { return stmt == STMT.Scope       ? cast(typeof(return))this : null; }
+        inout(ExpStatement)         isExpStatement()         { return stmt == STMT.Exp         ? cast(typeof(return))this : null; }
+        inout(CompoundStatement)    isCompoundStatement()    { return stmt == STMT.Compound    ? cast(typeof(return))this : null; }
+        inout(ReturnStatement)      isReturnStatement()      { return stmt == STMT.Return      ? cast(typeof(return))this : null; }
+        inout(IfStatement)          isIfStatement()          { return stmt == STMT.If          ? cast(typeof(return))this : null; }
+        inout(ConditionalStatement) isConditionalStatement() { return stmt == STMT.Conditional ? cast(typeof(return))this : null; }
+        inout(StaticForeachStatement) isStaticForeachStatement() { return stmt == STMT.StaticForeach ? cast(typeof(return))this : null; }
+        inout(CaseStatement)        isCaseStatement()        { return stmt == STMT.Case        ? cast(typeof(return))this : null; }
+        inout(DefaultStatement)     isDefaultStatement()     { return stmt == STMT.Default     ? cast(typeof(return))this : null; }
+        inout(LabelStatement)       isLabelStatement()       { return stmt == STMT.Label       ? cast(typeof(return))this : null; }
+        inout(GotoStatement)        isGotoStatement()        { return stmt == STMT.Goto        ? cast(typeof(return))this : null; }
+        inout(GotoDefaultStatement) isGotoDefaultStatement() { return stmt == STMT.GotoDefault ? cast(typeof(return))this : null; }
+        inout(GotoCaseStatement)    isGotoCaseStatement()    { return stmt == STMT.GotoCase    ? cast(typeof(return))this : null; }
+        inout(BreakStatement)       isBreakStatement()       { return stmt == STMT.Break       ? cast(typeof(return))this : null; }
+        inout(DtorExpStatement)     isDtorExpStatement()     { return stmt == STMT.DtorExp     ? cast(typeof(return))this : null; }
+        inout(MixinStatement)       isMixinStatement()       { return stmt == STMT.Mixin       ? cast(typeof(return))this : null; }
+        inout(ForwardingStatement)  isForwardingStatement()  { return stmt == STMT.Forwarding  ? cast(typeof(return))this : null; }
+        inout(DoStatement)          isDoStatement()          { return stmt == STMT.Do          ? cast(typeof(return))this : null; }
+        inout(WhileStatement)       isWhileStatement()       { return stmt == STMT.While       ? cast(typeof(return))this : null; }
+        inout(ForStatement)         isForStatement()         { return stmt == STMT.For         ? cast(typeof(return))this : null; }
+        inout(ForeachStatement)     isForeachStatement()     { return stmt == STMT.Foreach     ? cast(typeof(return))this : null; }
+        inout(SwitchStatement)      isSwitchStatement()      { return stmt == STMT.Switch      ? cast(typeof(return))this : null; }
+        inout(ContinueStatement)    isContinueStatement()    { return stmt == STMT.Continue    ? cast(typeof(return))this : null; }
+        inout(WithStatement)        isWithStatement()        { return stmt == STMT.With        ? cast(typeof(return))this : null; }
+        inout(TryCatchStatement)    isTryCatchStatement()    { return stmt == STMT.TryCatch    ? cast(typeof(return))this : null; }
+        inout(ThrowStatement)       isThrowStatement()       { return stmt == STMT.Throw       ? cast(typeof(return))this : null; }
+        inout(DebugStatement)       isDebugStatement()       { return stmt == STMT.Debug       ? cast(typeof(return))this : null; }
+        inout(TryFinallyStatement)  isTryFinallyStatement()  { return stmt == STMT.TryFinally  ? cast(typeof(return))this : null; }
+        inout(ScopeGuardStatement)  isScopeGuardStatement()  { return stmt == STMT.ScopeGuard  ? cast(typeof(return))this : null; }
+        inout(SwitchErrorStatement)  isSwitchErrorStatement()  { return stmt == STMT.SwitchError  ? cast(typeof(return))this : null; }
+        inout(UnrolledLoopStatement) isUnrolledLoopStatement() { return stmt == STMT.UnrolledLoop ? cast(typeof(return))this : null; }
+        inout(ForeachRangeStatement) isForeachRangeStatement() { return stmt == STMT.ForeachRange ? cast(typeof(return))this : null; }
+        inout(CompoundDeclarationStatement) isCompoundDeclarationStatement() { return stmt == STMT.CompoundDeclaration ? cast(typeof(return))this : null; }
+        inout(CompoundAsmStatement)  isCompoundAsmStatement()  { return stmt == STMT.CompoundAsm  ? cast(typeof(return))this : null; }
+        inout(PragmaStatement)       isPragmaStatement()       { return stmt == STMT.Pragma       ? cast(typeof(return))this : null; }
+        inout(StaticAssertStatement) isStaticAssertStatement() { return stmt == STMT.StaticAssert ? cast(typeof(return))this : null; }
+        inout(CaseRangeStatement)    isCaseRangeStatement()    { return stmt == STMT.CaseRange    ? cast(typeof(return))this : null; }
+        inout(SynchronizedStatement) isSynchronizedStatement() { return stmt == STMT.Synchronized ? cast(typeof(return))this : null; }
+        inout(AsmStatement)          isAsmStatement()          { return stmt == STMT.Asm          ? cast(typeof(return))this : null; }
+        inout(InlineAsmStatement)    isInlineAsmStatement()    { return stmt == STMT.InlineAsm    ? cast(typeof(return))this : null; }
+        inout(GccAsmStatement)       isGccAsmStatement()       { return stmt == STMT.GccAsm       ? cast(typeof(return))this : null; }
+        inout(ImportStatement)       isImportStatement()       { return stmt == STMT.Import       ? cast(typeof(return))this : null; }
+    }
 }
 
 /***********************************************************
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index d0e1b9a23d9e8d29c27fe392386f9b40aedf3d06..c5c8a12593653faef4833d642b4d26c167213ea7 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -1381,7 +1381,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc)
                         p.type = p.type.addStorageClass(sc).typeSemantic(loc, sc2);
                         if (!exp.implicitConvTo(p.type))
                         {
-                            error(fs.loc, "cannot implicilty convert range element of type `%s` to variable `%s` of type `%s`",
+                            error(fs.loc, "cannot implicitly convert tuple element of type `%s` to variable `%s` of type `%s`",
                                 exp.type.toChars(), p.toChars(), p.type.toChars());
                             return retError();
                         }
diff --git a/gcc/d/dmd/target.d b/gcc/d/dmd/target.d
index dadf51912db45b6c1fd4160fdfdcd6802e98fa4d..d86be85b7330446984f73a09c44f09ce8ff3340b 100644
--- a/gcc/d/dmd/target.d
+++ b/gcc/d/dmd/target.d
@@ -25,6 +25,8 @@
 
 module dmd.target;
 
+import core.stdc.stdio;
+
 import dmd.astenums : CHECKENABLE;
 import dmd.globals : Param;
 
@@ -344,8 +346,8 @@ struct TargetCPP
     enum Runtime : ubyte
     {
         Unspecified,
-        Clang,
-        Gcc,
+        LLVM,
+        GNU,
         Microsoft,
         Sun
     }
diff --git a/gcc/d/dmd/target.h b/gcc/d/dmd/target.h
index a5caa74c80e882e196661e36b7451c131fdeefda..a380bb8bbe5007fff8470a41ac101b73ab9e7b63 100644
--- a/gcc/d/dmd/target.h
+++ b/gcc/d/dmd/target.h
@@ -84,8 +84,8 @@ struct TargetCPP
     enum class Runtime : unsigned char
     {
         Unspecified,
-        Clang,
-        Gcc,
+        LLVM,
+        GNU,
         Microsoft,
         Sun
     };
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 31ebc4c809c62ee8834056c4739a6f70c6ff6b14..33d825a2b848b933ed44fe936123e86d364e7ea9 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1299,6 +1299,152 @@ Type getIndirection(Type t)
     return null;
 }
 
+uinteger_t size(Type t)
+{
+    return size(t, Loc.initial);
+}
+
+uinteger_t size(Type t, const ref Loc loc)
+{
+
+    uinteger_t visitType(Type t)
+    {
+        error(loc, "no size for type `%s`", t.toChars());
+        return SIZE_INVALID;
+    }
+
+    uinteger_t visitBasic(TypeBasic t)
+    {
+        uint size;
+        //printf("TypeBasic::size()\n");
+        switch (t.ty)
+        {
+            case Tint8:
+            case Tuns8:
+                size = 1;
+                break;
+
+            case Tint16:
+            case Tuns16:
+                size = 2;
+                break;
+
+            case Tint32:
+            case Tuns32:
+            case Tfloat32:
+            case Timaginary32:
+                size = 4;
+                break;
+
+            case Tint64:
+            case Tuns64:
+            case Tfloat64:
+            case Timaginary64:
+                size = 8;
+                break;
+
+            case Tfloat80:
+            case Timaginary80:
+                size = target.realsize;
+                break;
+
+            case Tcomplex32:
+                size = 8;
+                break;
+
+            case Tcomplex64:
+            case Tint128:
+            case Tuns128:
+                size = 16;
+                break;
+
+            case Tcomplex80:
+                size = target.realsize * 2;
+                break;
+
+            case Tvoid:
+                //size = Type::size();      // error message
+                size = 1;
+                break;
+
+            case Tbool:
+                size = 1;
+                break;
+
+            case Tchar:
+                size = 1;
+                break;
+
+            case Twchar:
+                size = 2;
+                break;
+
+            case Tdchar:
+                size = 4;
+                break;
+
+            default:
+                assert(0);
+            }
+
+        //printf("TypeBasic::size() = %d\n", size);
+        return size;
+    }
+
+    uinteger_t visitSArray(TypeSArray t)
+    {
+        //printf("TypeSArray::size()\n");
+        const n = t.numberOfElems(loc);
+        const elemsize = t.baseElemOf().size(loc);
+        bool overflow = false;
+        const sz = mulu(n, elemsize, overflow);
+        if (overflow || sz >= uint.max)
+        {
+            if (elemsize != SIZE_INVALID && n != uint.max)
+                error(loc, "static array `%s` size overflowed to %lld", t.toChars(), cast(long)sz);
+            return SIZE_INVALID;
+        }
+        return sz;
+
+    }
+
+    uinteger_t visitTypeQualified(TypeQualified t)
+    {
+        if (t.ty == Ttypeof)
+        {
+            auto type = (cast(TypeTypeof)t).exp.type;
+            if (type)
+                return type.size(loc);
+        }
+
+        error(t.loc, "size of type `%s` is not known", t.toChars());
+        return SIZE_INVALID;
+    }
+
+    switch(t.ty)
+    {
+        default:            return t.isTypeBasic() ? visitBasic(t.isTypeBasic()) : visitType(t);
+        case Ttraits:
+        case Terror:        return SIZE_INVALID;
+        case Tvector:       return t.isTypeVector().basetype.size();
+        case Tsarray:       return visitSArray(t.isTypeSArray());
+        case Tdelegate:
+        case Tarray:        return target.ptrsize * 2;
+        case Tpointer:
+        case Treference:
+        case Tclass:
+        case Taarray:       return target.ptrsize;
+        case Tident:
+        case Tinstance:
+        case Ttypeof:
+        case Treturn:       return visitTypeQualified(cast(TypeQualified)t);
+        case Tstruct:       return t.isTypeStruct().sym.size(loc);
+        case Tenum:         return t.isTypeEnum().sym.getMemtype(loc).size(loc);
+        case Tnull:         return t.tvoidptr.size(loc);
+        case Tnoreturn:     return 0;
+    }
+}
+
 /******************************************
  * Perform semantic analysis on a type.
  * Params:
diff --git a/gcc/d/dmd/visitor.d b/gcc/d/dmd/visitor.d
index abfd8caa5844ee34804b5ba32c45d8577fe7b6bb..9082909ba2e2e5d427264bb990c78114081e1cec 100644
--- a/gcc/d/dmd/visitor.d
+++ b/gcc/d/dmd/visitor.d
@@ -162,6 +162,11 @@ extern (C++) class SemanticTimeTransitiveVisitor : SemanticTimePermissiveVisitor
         }
     }
 
+    override void visit(ASTCodegen.ClassReferenceExp e)
+    {
+        e.value.accept(this);
+    }
+
     override void visit(ASTCodegen.CompoundLiteralExp e)
     {
         if (e.initializer)
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 9ec83500a8c5a49c297699b968155252f38ce43e..46d30514287396aea3c5a36517705f828ad6e102 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -414,7 +414,8 @@ public:
 	    if (t1elem->ty != TY::Tstruct
 		|| identity_compare_p (t1elem->isTypeStruct ()->sym))
 	      {
-		tree size = size_mult_expr (t1len, size_int (t1elem->size ()));
+		tree size =
+		  size_mult_expr (t1len, size_int (dmd::size (t1elem)));
 
 		result = build_memcmp_call (t1ptr, t2ptr, size);
 		result = build_boolop (code, result, integer_zero_node);
@@ -442,7 +443,7 @@ public:
 	       The frontend should have already guaranteed that static arrays
 	       have same size.  */
 	    if (tb1->ty == TY::Tsarray && tb2->ty == TY::Tsarray)
-	      gcc_assert (tb1->size () == tb2->size ());
+	      gcc_assert (dmd::size (tb1) == dmd::size (tb2));
 	    else
 	      {
 		tree tlencmp = build_boolop (code, t1len, t2len);
@@ -917,7 +918,7 @@ public:
 	    if (integer_zerop (t2))
 	      {
 		tree size = size_mult_expr (d_array_length (t1),
-					    size_int (etype->size ()));
+					    size_int (dmd::size (etype)));
 		result = build_memset_call (d_array_ptr (t1), size);
 	      }
 	    else
@@ -943,7 +944,8 @@ public:
 		tree t2ptr = d_array_ptr (t2);
 
 		/* Generate: memcpy(to, from, size)  */
-		tree size = size_mult_expr (t1len, size_int (etype->size ()));
+		tree size =
+		  size_mult_expr (t1len, size_int (dmd::size (etype)));
 		tree result = build_memcpy_call (t1ptr, t2ptr, size);
 
 		/* Insert check that array lengths match and do not overlap.  */
@@ -986,7 +988,7 @@ public:
 	      {
 		/* Generate: _d_arraycopy()  */
 		this->result_ = build_libcall (LIBCALL_ARRAYCOPY, e->type, 3,
-					       size_int (etype->size ()),
+					       size_int (dmd::size (etype)),
 					       d_array_convert (e->e2),
 					       d_array_convert (e->e1));
 	      }
@@ -1100,7 +1102,7 @@ public:
 	    || (e->op == EXP::construct && e->e2->op == EXP::arrayLiteral)
 	    || (e->op == EXP::construct && e->e2->op == EXP::call)
 	    || (e->op == EXP::construct && !lvalue && postblit)
-	    || (e->op == EXP::blit || e->e1->type->size () == 0))
+	    || (e->op == EXP::blit || dmd::size (e->e1->type) == 0))
 	  {
 	    tree t1 = build_expr (e->e1);
 	    tree t2 = convert_for_assignment (e->e2, e->e1->type);
@@ -1190,7 +1192,7 @@ public:
 	/* Index the associative array.  */
 	tree result = build_libcall (libcall, dmd::pointerTo (e->type), 4,
 				     ptr, tinfo,
-				     size_int (tb1->nextOf ()->size ()),
+				     size_int (dmd::size (tb1->nextOf ())),
 				     build_address (key));
 
 	if (!e->indexIsInBounds && array_bounds_check ())
@@ -2391,7 +2393,7 @@ public:
 	/* Allocating memory for a new pointer.  */
 	TypePointer *tpointer = tb->isTypePointer ();
 
-	if (tpointer->next->size () == 0)
+	if (dmd::size (tpointer->next) == 0)
 	  {
 	    /* Pointer element size is unknown.  */
 	    this->result_ = d_convert (build_ctype (e->type),
@@ -2692,7 +2694,7 @@ public:
 
 	/* Now copy the constructor into memory.  */
 	tree size = size_mult_expr (size_int (e->elements->length),
-				    size_int (tb->nextOf ()->size ()));
+				    size_int (dmd::size (tb->nextOf ())));
 
 	tree result = build_memcpy_call (mem, build_address (ctor), size);
 
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index ea2e4b5deec46717acc8bbda9648d704b8d3525b..982d7cc95dd52104d26b9c1f165817274572d20c 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -664,7 +664,7 @@ public:
     /* Default initializer for enum.  */
     if (ed->members && !d->tinfo->isZeroInit ())
       {
-	tree length = size_int (ed->type->size ());
+	tree length = size_int (dmd::size (ed->type));
 	tree ptr = build_address (enum_initializer_decl (ed));
 	this->layout_field (d_array_value (array_type_node, length, ptr));
       }
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index 6689278061992f07484e810658fd7245b8c4e389..ad461cb6969bde374933f15f0cf065214b35ead6 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -1181,7 +1181,7 @@ public:
 	TYPE_UNSIGNED (t->ctype) = TYPE_UNSIGNED (basetype);
 	SET_TYPE_ALIGN (t->ctype, TYPE_ALIGN (basetype));
 	TYPE_SIZE (t->ctype) = NULL_TREE;
-	TYPE_PRECISION (t->ctype) = t->size (t->sym->loc) * 8;
+	TYPE_PRECISION (t->ctype) = dmd::size (t, t->sym->loc) * 8;
 
 	layout_type (t->ctype);
 
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle.d b/gcc/testsuite/gdc.test/compilable/cppmangle.d
index 948fee2cfdaacbe8dbedb072561c11d9bb2ad9d3..4b9046e81102728e40485cd9d64b9a04448f235c 100644
--- a/gcc/testsuite/gdc.test/compilable/cppmangle.d
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle.d
@@ -7,8 +7,8 @@
 
 import core.stdc.stdio;
 
-version (CppRuntime_Clang)       version = CppMangle_Itanium;
-version (CppRuntime_Gcc)         version = CppMangle_Itanium;
+version (CppRuntime_LLVM)        version = CppMangle_Itanium;
+version (CppRuntime_GNU)         version = CppMangle_Itanium;
 version (CppRuntime_Microsoft)   version = CppMangle_MSVC;
 version (CppRuntime_Sun)         version = CppMangle_Itanium;
 
diff --git a/gcc/testsuite/gdc.test/compilable/cppmangle3.d b/gcc/testsuite/gdc.test/compilable/cppmangle3.d
index 92c858854f0cd291b848faf930fb6813203e1ceb..94de1fa9ff43fe0294efabcd83661daf1693bf2c 100644
--- a/gcc/testsuite/gdc.test/compilable/cppmangle3.d
+++ b/gcc/testsuite/gdc.test/compilable/cppmangle3.d
@@ -3,8 +3,8 @@
 // https://issues.dlang.org/show_bug.cgi?id=19920
 module cppmangle3;
 
-version (CppRuntime_Clang)       version = CppMangle_Itanium;
-version (CppRuntime_Gcc)         version = CppMangle_Itanium;
+version (CppRuntime_LLVM)      version = CppMangle_Itanium;
+version (CppRuntime_GNU)   version = CppMangle_Itanium;
 version (CppRuntime_Microsoft)   version = CppMangle_MSVC;
 version (CppRuntime_Sun)         version = CppMangle_Itanium;
 
diff --git a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
index 93f05a50c31f71558122cc198f53327cb5b8e9de..9756264fcc3e753b29f363eade539aad8a94cb27 100644
--- a/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
+++ b/gcc/testsuite/gdc.test/compilable/extra-files/header1.d
@@ -575,12 +575,17 @@ struct SafeS
         return this;
     }
 
-    ref SafeS foo3() return scope
+    ref SafeS foo3() scope
     {
         static SafeS s;
         return s;
     }
 
+    ref SafeS foo4() scope return
+    {
+        return this;
+    }
+
     int* p;
 }
 
diff --git a/gcc/testsuite/gdc.test/compilable/import_exp.d b/gcc/testsuite/gdc.test/compilable/import_exp.d
new file mode 100644
index 0000000000000000000000000000000000000000..014d0f65f6f9ac626f60b8a32c528cb9d4a0ed8a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/import_exp.d
@@ -0,0 +1,36 @@
+// REQUIRED_ARGS: -Jcompilable/imports/
+// EXTRA_FILES: imports/imp16088.d imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt
+
+// https://issues.dlang.org/show_bug.cgi?id=16088
+
+void bar(string x) {}
+auto foo()
+{
+    import("imp16088.d").bar;
+}
+
+
+// https://issues.dlang.org/show_bug.cgi?id=21227
+
+void test21227()
+{
+    import("./test21227/a.txt").bar;
+    import("test21227//a..b.txt").bar;
+    import("test21227/..foo/a.txt").bar;
+
+    version(Windows)
+    {
+        import(r".\test21227\a.txt").bar;
+        import(r"test21227\\a..b.txt").bar;
+        import(r"test21227\..foo\a.txt").bar;
+    }
+}
+
+// Test that it's treated like a hex string, allowing implicit conversion to byte array
+
+// Can't test whole contents because line endings may vary
+enum expectedStart = "module imports.imp16088;";
+
+immutable ubyte[] s0 = import("imp16088.d");
+
+static assert(s0[0 .. expectedStart.length] == "module imports.imp16088;");
diff --git a/gcc/testsuite/gdc.test/compilable/issue21203.d b/gcc/testsuite/gdc.test/compilable/issue21203.d
index 30291a35e626c2ea1acd329c15663b29b8a74f3c..ee394b310a5dc3c3e8b4b9ed532f769b547f2162 100644
--- a/gcc/testsuite/gdc.test/compilable/issue21203.d
+++ b/gcc/testsuite/gdc.test/compilable/issue21203.d
@@ -1,6 +1,6 @@
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc)   version = CppMangle_Itanium;
-version (CppRuntime_Sun)   version = CppMangle_Itanium;
+version (CppRuntime_LLVM)    version = CppMangle_Itanium;
+version (CppRuntime_GNU) version = CppMangle_Itanium;
+version (CppRuntime_Sun)       version = CppMangle_Itanium;
 
 template ScopeClass(C , string name = C.stringof)
 //if (is(C == class) && __traits(getLinkage, C) == "C++")
diff --git a/gcc/testsuite/gdc.test/compilable/issue21340.d b/gcc/testsuite/gdc.test/compilable/issue21340.d
index 03d37bdc61a4bfb792c959ba354cc78a3743a9cd..26280998692b287fd904754371a9501a4d111e29 100644
--- a/gcc/testsuite/gdc.test/compilable/issue21340.d
+++ b/gcc/testsuite/gdc.test/compilable/issue21340.d
@@ -1,5 +1,5 @@
-version (CppRuntime_Clang) version = CppMangle_Itanium;
-version (CppRuntime_Gcc)   version = CppMangle_Itanium;
+version (CppRuntime_LLVM) version = CppMangle_Itanium;
+version (CppRuntime_GNU)   version = CppMangle_Itanium;
 version (CppRuntime_Sun)   version = CppMangle_Itanium;
 
 template ScopeClass(C)
diff --git a/gcc/testsuite/gdc.test/compilable/issue24566.d b/gcc/testsuite/gdc.test/compilable/issue24566.d
new file mode 100644
index 0000000000000000000000000000000000000000..df1bf6f0e183a1431dec370fdb06136c231af639
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/issue24566.d
@@ -0,0 +1,23 @@
+// https://issues.dlang.org/show_bug.cgi?id=24566
+
+void test24566a()
+{
+    enum a = true;
+    bool b = true;
+    enum str = "a";
+    if (a && str.length > 1 && str[1] == 'a') {}
+    if (b && str.length > 1 && str[1] == 'a') {}
+    if (!b && str.length > 1 && str[1] == 'a') {}
+    if (str.length > 1 && b && str[1] == 'a') {}
+}
+
+void test24566b()
+{
+    enum a = false;
+    bool b = false;
+    enum str = "a";
+    if (a || str.length <= 1 || str[1] == 'a') {}
+    if (b || str.length <= 1 || str[1] == 'a') {}
+    if (!b || str.length <= 1 || str[1] == 'a') {}
+    if (str.length <= 1 || b || str[1] == 'a') {}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test16088.d b/gcc/testsuite/gdc.test/compilable/test16088.d
deleted file mode 100644
index 97326f1fcd7a19afa43567d1f7c70d2b77eb5bb9..0000000000000000000000000000000000000000
--- a/gcc/testsuite/gdc.test/compilable/test16088.d
+++ /dev/null
@@ -1,10 +0,0 @@
-// REQUIRED_ARGS: -Jcompilable/imports/
-// EXTRA_FILES: imports/imp16088.d
-
-// https://issues.dlang.org/show_bug.cgi?id=16088
-
-void bar(string x) {}
-auto foo()
-{
-    import("imp16088.d").bar;
-}
diff --git a/gcc/testsuite/gdc.test/compilable/test21227.d b/gcc/testsuite/gdc.test/compilable/test21227.d
deleted file mode 100644
index 29dd2af29c37cb91d5c27be54249d1ffac3fbab6..0000000000000000000000000000000000000000
--- a/gcc/testsuite/gdc.test/compilable/test21227.d
+++ /dev/null
@@ -1,19 +0,0 @@
-// REQUIRED_ARGS: -Jcompilable/imports
-// EXTRA_FILES: imports/test21227/a..b.txt imports/test21227/a.txt imports/test21227/..foo/a.txt
-
-// https://issues.dlang.org/show_bug.cgi?id=21227
-
-void bar(string x) {}
-void test21227()
-{
-    import("./test21227/a.txt").bar;
-    import("test21227//a..b.txt").bar;
-    import("test21227/..foo/a.txt").bar;
-
-    version(Windows)
-    {
-        import(r".\test21227\a.txt").bar;
-        import(r"test21227\\a..b.txt").bar;
-        import(r"test21227\..foo\a.txt").bar;
-    }
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d b/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d
new file mode 100644
index 0000000000000000000000000000000000000000..830360a74c34a43c7a4f2cac3b8034d72e646862
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/bool_cast.d
@@ -0,0 +1,26 @@
+/*
+REQUIRED_ARGS: -de -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/bool_cast.d(17): Deprecation: cast from `ubyte[]` to `bool[]` not allowed in safe code
+fail_compilation/bool_cast.d(17):        Source element may have bytes which are not 0 or 1
+fail_compilation/bool_cast.d(22): Deprecation: cast from `int*` to `bool*` not allowed in safe code
+fail_compilation/bool_cast.d(22):        Source element may have bytes which are not 0 or 1
+fail_compilation/bool_cast.d(24): Deprecation: cast from `bool*` to `byte*` not allowed in safe code
+fail_compilation/bool_cast.d(24):        Target element could be assigned a byte which is not 0 or 1
+---
+*/
+
+void main() @safe
+{
+    ubyte[] a = [2, 4];
+    auto b = cast(bool[]) a; // reinterprets a's data
+    auto c = cast(bool[]) [2, 4]; // OK, literal cast applies to each element
+    auto d = cast(const(byte)[]) b; // OK, result's elements are const
+
+    int i = 2;
+    auto p = cast(bool*) &i;
+    bool v;
+    auto bp = cast(byte*) &v;
+    *bp = 2; // v is now invalid
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d b/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d
index 19932f811653ecc9907e33af1a43c7edefde8189..5821dc14994031cbac754abcf0150f3fcc93bb17 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/cast_qual.d
@@ -2,8 +2,10 @@
 REQUIRED_ARGS: -preview=dip1000 -de
 TEST_OUTPUT:
 ---
-fail_compilation/cast_qual.d(15): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
 fail_compilation/cast_qual.d(17): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
+fail_compilation/cast_qual.d(19): Deprecation: cast from `const(int)` to `int` cannot be used as an lvalue in @safe code
+fail_compilation/cast_qual.d(25): Error: cast from `const(Object)` to `object.Object` not allowed in safe code
+fail_compilation/cast_qual.d(25):        Incompatible type qualifier
 ---
 */
 
@@ -17,3 +19,8 @@ void main() {
     cast() i = 5; // NG
     auto q = &cast(const) j; // OK, int* to const int*
 }
+
+void test() {
+    const Object co;
+    auto o = cast() co;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d b/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d
new file mode 100644
index 0000000000000000000000000000000000000000..3802ebd5e92fadf207849ef14939c3ffd06ce312
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/cpp_cast.d
@@ -0,0 +1,23 @@
+// See also: fail20000.d
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/cpp_cast.d(19): Error: cast from `cpp_cast.I` to `cpp_cast.C` not allowed in safe code
+fail_compilation/cpp_cast.d(19):        No dynamic type information for extern(C++) classes
+fail_compilation/cpp_cast.d(21): Deprecation: cast from `cpp_cast.C` to `cpp_cast.D` not allowed in safe code
+fail_compilation/cpp_cast.d(21):        No dynamic type information for extern(C++) classes
+---
+*/
+extern(C++) interface I { void f(); }
+extern(C++) class C : I { void f() { } }
+extern(C++) class D : C { }
+
+void main() @safe
+{
+    I i;
+    C c = cast(C) i; // unsafe
+    i = cast(I) c; // OK
+    c = cast(D) c; // reinterpret cast
+    c = cast(C) new D; // OK
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d
index 79f9068c759317a147d57ecbb15e98c3dab598e5..f1048073591e991724b5ea5859cad722205928e7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13577.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13577.d
@@ -3,7 +3,7 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13577.d(27): Error: cannot implicilty convert range element of type `int[]` to variable `x` of type `immutable(int[])`
+fail_compilation/fail13577.d(27): Error: cannot implicitly convert tuple element of type `int[]` to variable `x` of type `immutable(int[])`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail20000.d b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d
index fe481216be65aaa6856301cf3fe6606387712ada..a049dacb2e6d05fef5f432767e54c3b49be6e70c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail20000.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail20000.d
@@ -1,18 +1,30 @@
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail20000.d(25): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(26): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(27): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(28): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
-fail_compilation/fail20000.d(30): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(31): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(32): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(33): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
-fail_compilation/fail20000.d(35): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
-fail_compilation/fail20000.d(36): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
-fail_compilation/fail20000.d(38): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
-fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(37): Error: cast from `fail20000.DClass` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(37):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(38): Error: cast from `fail20000.DInterface` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(38):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(39): Error: cast from `fail20000.CppClass2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(39):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(40): Error: cast from `fail20000.CppInterface2` to `fail20000.CppClass` not allowed in safe code
+fail_compilation/fail20000.d(40):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(42): Error: cast from `fail20000.DClass` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(42):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(43): Error: cast from `fail20000.DInterface` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(43):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(44): Error: cast from `fail20000.CppClass2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(44):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(45): Error: cast from `fail20000.CppInterface2` to `fail20000.CppInterface` not allowed in safe code
+fail_compilation/fail20000.d(45):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(47): Error: cast from `fail20000.CppClass` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(47):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(48): Error: cast from `fail20000.CppInterface` to `fail20000.DClass` not allowed in safe code
+fail_compilation/fail20000.d(48):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(50): Error: cast from `fail20000.CppClass` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(50):        Source object type is incompatible with target type
+fail_compilation/fail20000.d(51): Error: cast from `fail20000.CppInterface` to `fail20000.DInterface` not allowed in safe code
+fail_compilation/fail20000.d(51):        Source object type is incompatible with target type
 ---
 */
 extern(C++) class CppClass { int a; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20042.d b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d
index 6b71903c9ca233fb8af74c63f05b10fbcc6183ad..7a674b3c546418869a9f3abf9fda15e7a18e28e5 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice20042.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20042.d
@@ -1,5 +1,5 @@
 /*
-DISABLED: freebsd32 linux32 osx32 win32
+DISABLED: freebsd32 openbsd32 linux32 osx32 win32
 TEST_OUTPUT:
 ---
 fail_compilation/ice20042.d(18): Error: slice operation `cast(__vector(float[4]))[nanF, nanF, nanF, nanF] = [1.0F, 2.0F, 3.0F, 4.0F][0..4]` cannot be evaluated at compile time
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
index df6667d9e4b1f73b7eb1e7b0bf3451e533bb726c..a8a1e7119bee14a2efb19650903335cb00581344 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
@@ -1,5 +1,5 @@
 /*
-DISABLED: freebsd32 linux32 osx32 win32
+DISABLED: freebsd32 openbsd32 linux32 osx32 win32
 TEST_OUTPUT:
 ---
 fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue
diff --git a/gcc/testsuite/gdc.test/fail_compilation/impconv.d b/gcc/testsuite/gdc.test/fail_compilation/impconv.d
index cb1cb8e21eecd6e1b571642c91a4c0c6480b0cbb..0cc2deb13d867046f26260d273633aaa911fd044 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/impconv.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/impconv.d
@@ -3,7 +3,7 @@ FIXME: DMD host compilers < 2.073 with faulty optimization
 lead to unfortunate test failures, see
 https://github.com/dlang/dmd/pull/6831#issuecomment-304495842.
 
-DISABLED: win32 win64 linux osx freebsd
+DISABLED: win32 win64 linux osx freebsd openbsd
 */
 
 /*
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
index ac00b4d3b5004f36656100064006bf50e3033f01..502ae4a5bcaec26a59a0e44466e2ddc510b73ea2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version.d
@@ -110,9 +110,9 @@ fail_compilation/reserved_version.d(211): Error: version identifier `AsmJS` is r
 fail_compilation/reserved_version.d(212): Error: version identifier `Emscripten` is reserved and cannot be set
 fail_compilation/reserved_version.d(213): Error: version identifier `WebAssembly` is reserved and cannot be set
 fail_compilation/reserved_version.d(214): Error: version identifier `WASI` is reserved and cannot be set
-fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
+fail_compilation/reserved_version.d(215): Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set
 fail_compilation/reserved_version.d(216): Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
-fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
+fail_compilation/reserved_version.d(217): Error: version identifier `CppRuntime_GNU` is reserved and cannot be set
 fail_compilation/reserved_version.d(218): Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
 fail_compilation/reserved_version.d(219): Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
 fail_compilation/reserved_version.d(220): Error: version identifier `D_PIE` is reserved and cannot be set
@@ -239,9 +239,9 @@ version = AsmJS;
 version = Emscripten;
 version = WebAssembly;
 version = WASI;
-version = CppRuntime_Clang;
+version = CppRuntime_LLVM;
 version = CppRuntime_DigitalMars;
-version = CppRuntime_Gcc;
+version = CppRuntime_GNU;
 version = CppRuntime_Microsoft;
 version = CppRuntime_Sun;
 version = D_PIE;
@@ -339,9 +339,9 @@ debug = CRuntime_Musl;
 debug = CRuntime_Newlib;
 debug = CRuntime_UClibc;
 debug = CRuntime_WASI;
-debug = CppRuntime_Clang;
+debug = CppRuntime_LLVM;
 debug = CppRuntime_DigitalMars;
-debug = CppRuntime_Gcc;
+debug = CppRuntime_GNU;
 debug = CppRuntime_Microsoft;
 debug = CppRuntime_Sun;
 debug = D_Coverage;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
index 44db40410289566a04ef6b7b85107bc16d9a1c5a..2b6bb5e5351f7f680aad18eb234e295cd902ca18 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/reserved_version_switch.d
@@ -86,9 +86,9 @@
 // REQUIRED_ARGS: -version=CRuntime_Newlib
 // REQUIRED_ARGS: -version=CRuntime_UClibc
 // REQUIRED_ARGS: -version=CRuntime_WASI
-// REQUIRED_ARGS: -version=CppRuntime_Clang
+// REQUIRED_ARGS: -version=CppRuntime_LLVM
 // REQUIRED_ARGS: -version=CppRuntime_DigitalMars
-// REQUIRED_ARGS: -version=CppRuntime_Gcc
+// REQUIRED_ARGS: -version=CppRuntime_GNU
 // REQUIRED_ARGS: -version=CppRuntime_Microsoft
 // REQUIRED_ARGS: -version=CppRuntime_Sun
 // REQUIRED_ARGS: -version=D_Coverage
@@ -195,9 +195,9 @@
 // REQUIRED_ARGS: -debug=CRuntime_Newlib
 // REQUIRED_ARGS: -debug=CRuntime_UClibc
 // REQUIRED_ARGS: -debug=CRuntime_WASI
-// REQUIRED_ARGS: -debug=CppRuntime_Clang
+// REQUIRED_ARGS: -debug=CppRuntime_LLVM
 // REQUIRED_ARGS: -debug=CppRuntime_DigitalMars
-// REQUIRED_ARGS: -debug=CppRuntime_Gcc
+// REQUIRED_ARGS: -debug=CppRuntime_GNU
 // REQUIRED_ARGS: -debug=CppRuntime_Microsoft
 // REQUIRED_ARGS: -debug=CppRuntime_Sun
 // REQUIRED_ARGS: -debug=D_Coverage
@@ -310,9 +310,9 @@ Error: version identifier `CRuntime_Musl` is reserved and cannot be set
 Error: version identifier `CRuntime_Newlib` is reserved and cannot be set
 Error: version identifier `CRuntime_UClibc` is reserved and cannot be set
 Error: version identifier `CRuntime_WASI` is reserved and cannot be set
-Error: version identifier `CppRuntime_Clang` is reserved and cannot be set
+Error: version identifier `CppRuntime_LLVM` is reserved and cannot be set
 Error: version identifier `CppRuntime_DigitalMars` is reserved and cannot be set
-Error: version identifier `CppRuntime_Gcc` is reserved and cannot be set
+Error: version identifier `CppRuntime_GNU` is reserved and cannot be set
 Error: version identifier `CppRuntime_Microsoft` is reserved and cannot be set
 Error: version identifier `CppRuntime_Sun` is reserved and cannot be set
 Error: version identifier `D_Coverage` is reserved and cannot be set
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retref2.d b/gcc/testsuite/gdc.test/fail_compilation/retref2.d
index aaa5b41e306c69b639f839783c417e1e101c4232..ca64653efaec8e8a13da80fd26ad7f8252dcf98d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retref2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retref2.d
@@ -2,7 +2,7 @@
 TEST_OUTPUT:
 ---
 fail_compilation/retref2.d(18): Error: function `ref int retref2.D.foo(return ref int)` does not override any function, did you mean to override `ref int retref2.C.foo(ref int)`?
-fail_compilation/retref2.d(19): Error: function `ref scope int retref2.D.bar() return` does not override any function, did you mean to override `ref int retref2.C.bar()`?
+fail_compilation/retref2.d(19): Error: function `ref int retref2.D.bar() scope return` does not override any function, did you mean to override `ref int retref2.C.bar()`?
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/shared.d b/gcc/testsuite/gdc.test/fail_compilation/shared.d
index 8b94a7981a1fd26a183980f68615f04618b29ff8..13b24c81cf833455dbf71c2270f5fbd283947395 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/shared.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/shared.d
@@ -241,9 +241,13 @@ struct BitRange
 TEST_OUTPUT:
 ---
 fail_compilation/shared.d(3004): Error: cast from `void*` to `shared(int*)` not allowed in safe code
+fail_compilation/shared.d(3004):        `void` data may contain pointers and target element type is mutable
 fail_compilation/shared.d(3005): Error: cast from `void*` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3005):        Source type is incompatible with target type containing a pointer
 fail_compilation/shared.d(3008): Error: cast from `shared(void*)` to `int*` not allowed in safe code
+fail_compilation/shared.d(3008):        `void` data may contain pointers and target element type is mutable
 fail_compilation/shared.d(3009): Error: cast from `shared(void*)` to `shared(const(int*))` not allowed in safe code
+fail_compilation/shared.d(3009):        Source type is incompatible with target type containing a pointer
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d b/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d
new file mode 100644
index 0000000000000000000000000000000000000000..fc10b2a78010265a1d04605ac6c613f658b1aab5
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/system_ptr_cast.d
@@ -0,0 +1,25 @@
+/*
+REQUIRED_ARGS: -preview=dip1000 -de
+TEST_OUTPUT:
+---
+fail_compilation/system_ptr_cast.d(20): Deprecation: cast from `S*` to `int*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(20):        Source element type has unsafe bit patterns and target element type is mutable
+fail_compilation/system_ptr_cast.d(24): Deprecation: cast from `int*` to `S*` not allowed in safe code
+fail_compilation/system_ptr_cast.d(24):        Target element type has unsafe bit patterns
+---
+*/
+
+struct S
+{
+    @system int i;
+}
+
+void main() @safe
+{
+    S s;
+    auto p = cast(int*) &s;
+    *p = 8;
+
+    int i = 8;
+    auto ps = cast(S*) &i;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15660.d b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
index ae573b2af2a77e87185d7e617876412c74ac5aa3..9bf05d125384265af1ffd9dc5e66dc9c34a14386 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15660.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15660.d
@@ -1,7 +1,13 @@
 /* REQUIRED_ARGS: -preview=fixImmutableConv
 TEST_OUTPUT:
 ---
-fail_compilation/test15660.d(20): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
+fail_compilation/test15660.d(26): Error: cannot implicitly convert expression `f(v)` of type `int[]` to `immutable(int[])`
+fail_compilation/test15660.d(34): Error: cannot copy `const(void)[]` to `void[]`
+fail_compilation/test15660.d(34):        Source data has incompatible type qualifier(s)
+fail_compilation/test15660.d(34):        Use `cast(void[])` to force copy
+fail_compilation/test15660.d(36): Error: cannot copy `const(int*)[]` to `void[]`
+fail_compilation/test15660.d(36):        Source data has incompatible type qualifier(s)
+fail_compilation/test15660.d(36):        Use `cast(void[])` to force copy
 ---
 */
 
@@ -19,3 +25,13 @@ void main()
     void[] v;
     immutable x = f(v);
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=17148
+void f(int*[] a, const int*[] b) @system
+{
+	void[] a1 = a;
+	const(void)[] b1 = b;
+	a1[] = b1[];
+	*a[0] = 0; //modify const data
+	a1[] = new const(int*)[2];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15672.d b/gcc/testsuite/gdc.test/fail_compilation/test15672.d
index 1c3bedfc2a2aa9f595b10c2e0c494bcadfaac908..c3d14db21000f3d5c6259484b5cd98fc8ccf769f 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15672.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15672.d
@@ -1,8 +1,10 @@
 /*
  * TEST_OUTPUT:
 ---
-fail_compilation/test15672.d(15): Error: cast from `void[]` to `byte[]` not allowed in safe code
-fail_compilation/test15672.d(25): Error: cast from `void*` to `byte*` not allowed in safe code
+fail_compilation/test15672.d(17): Error: cast from `void[]` to `byte[]` not allowed in safe code
+fail_compilation/test15672.d(17):        `void` data may contain pointers and target element type is mutable
+fail_compilation/test15672.d(27): Error: cast from `void*` to `byte*` not allowed in safe code
+fail_compilation/test15672.d(27):        `void` data may contain pointers and target element type is mutable
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=15672
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15703.d b/gcc/testsuite/gdc.test/fail_compilation/test15703.d
index dd07857dbe6d4e957b822e9cb7ffea0b308cb7d0..9ee9ac52ec75b25c3b20776d17918daa83a1b273 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15703.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15703.d
@@ -2,9 +2,16 @@
 REQUIRED_ARGS: -m32
 TEST_OUTPUT:
 ---
-fail_compilation/test15703.d(16): Error: cast from `Object[]` to `uint[]` not allowed in safe code
-fail_compilation/test15703.d(18): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
-fail_compilation/test15703.d(21): Error: cast from `uint[]` to `Object[]` not allowed in safe code
+fail_compilation/test15703.d(23): Error: cast from `Object[]` to `uint[]` not allowed in safe code
+fail_compilation/test15703.d(23):        Target element type is mutable and source element type contains a pointer
+fail_compilation/test15703.d(25): Error: cast from `object.Object` to `const(uint)*` not allowed in safe code
+fail_compilation/test15703.d(25):        Source type is incompatible with target type containing a pointer
+fail_compilation/test15703.d(28): Error: cast from `uint[]` to `Object[]` not allowed in safe code
+fail_compilation/test15703.d(28):        Target element type contains a pointer
+fail_compilation/test15703.d(44): Error: cast from `int[]` to `S[]` not allowed in safe code
+fail_compilation/test15703.d(44):        Target element type is opaque
+fail_compilation/test15703.d(45): Error: cast from `S[]` to `int[]` not allowed in safe code
+fail_compilation/test15703.d(45):        Source element type is opaque
 ---
 */
 
@@ -28,3 +35,12 @@ void test2() @safe
     const(ubyte)[] a;
     auto b = cast(const(uint[])) a;
 }
+
+struct S;
+
+void opaque() @safe
+{
+    auto a = [1, 2];
+    S[] b = cast(S[]) a;
+    a = cast(int[]) b;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15704.d b/gcc/testsuite/gdc.test/fail_compilation/test15704.d
index 2be9d30f0a00c80a5920ae92f8c297a2a16ac519..04d4be4aa93ab40b08427ccb51439574cde49004 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15704.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15704.d
@@ -1,7 +1,9 @@
 /*
  * TEST_OUTPUT:
 ---
-fail_compilation/test15704.d(15): Error: cannot copy `void[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(17): Error: cannot copy `void[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(18): Error: cannot copy `const(void)[]` to `void[]` in `@safe` code
+fail_compilation/test15704.d(19): Deprecation: cannot copy `int[]` to `void[]` in `@safe` code
 ---
  */
 
@@ -13,4 +15,6 @@ void main() @safe {
     void[] arr2 = [ 123, 345, 567 ];
 
     arr1[] = arr2[];  // overwrites pointers with arbitrary ints
+    arr1[] = new const(void)[3];
+    arr1[] = [5];
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19646.d b/gcc/testsuite/gdc.test/fail_compilation/test19646.d
index c9d0e08f6e0e6f65fc63c304c68f8871f595f337..766b387a559e6f619fc767aa962c943f04743edc 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test19646.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19646.d
@@ -1,7 +1,8 @@
 /* TEST_OUTPUT:
 ---
-fail_compilation/test19646.d(11): Error: cast from `const(int)*` to `int*` not allowed in safe code
-fail_compilation/test19646.d(17): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f`
+fail_compilation/test19646.d(12): Error: cast from `const(int)*` to `int*` not allowed in safe code
+fail_compilation/test19646.d(12):        Source type is incompatible with target type containing a pointer
+fail_compilation/test19646.d(18): Error: `@safe` variable `z` cannot be initialized by calling `@system` function `f`
 ---
 https://issues.dlang.org/show_bug.cgi?id=19646
  */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/union_conv.d b/gcc/testsuite/gdc.test/fail_compilation/union_conv.d
new file mode 100644
index 0000000000000000000000000000000000000000..f08809c4850052540972a8ef9af6f0252fff3c8e
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/union_conv.d
@@ -0,0 +1,19 @@
+/*
+REQUIRED_ARGS: -preview=fixImmutableConv
+TEST_OUTPUT:
+---
+fail_compilation/union_conv.d(18): Error: cannot implicitly convert expression `c` of type `const(U)` to `U`
+---
+*/
+
+union U
+{
+    int i;
+    int* p;
+}
+
+void main()
+{
+    const U c;
+    U m = c;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/void_cat.d b/gcc/testsuite/gdc.test/fail_compilation/void_cat.d
new file mode 100644
index 0000000000000000000000000000000000000000..da92d3b75b4c341b0ebddbe9e81f92700bd63ded
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/void_cat.d
@@ -0,0 +1,21 @@
+/*
+REQUIRED_ARGS: -preview=fixImmutableConv
+TEST_OUTPUT:
+---
+fail_compilation/void_cat.d(15): Error: cannot copy `const(void)[]` to `void[]`
+fail_compilation/void_cat.d(15):        Source data has incompatible type qualifier(s)
+fail_compilation/void_cat.d(15):        Use `cast(void[])` to force copy
+fail_compilation/void_cat.d(19): Error: cannot append type `const(void)[]` to type `void[]`
+---
+*/
+
+void g(int*[] a, const(int*)[] b) @system
+{
+    void[] va = a;
+    va[] = va.init ~ b; // a now contains b's data
+    *a[0] = 0; // modify const data
+
+    const(void)[] vb = b;
+    va ~= vb; // also leaks const pointers into void[]
+    // va could be copied into `a` via another void[]
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d b/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d
index 6cf0e238f29bd6c2afaf5d0fdd59730f8d1372ad..f91ac1f52521ffd4678168bf3cec0a93d342ad9b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/xmmslice.d
@@ -1,6 +1,6 @@
 
 /* REQUIRED_ARGS: -mcpu=avx
-DISABLED: win32 freebsd32 linux32 osx32
+DISABLED: win32 freebsd32 openbsd32 linux32 osx32
 TEST_OUTPUT:
 ---
 fail_compilation/xmmslice.d(110): Error: `__vector(int[4])` cannot be sliced with `[]`
diff --git a/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d b/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d
new file mode 100644
index 0000000000000000000000000000000000000000..5ea04f572fa0ec7177724a3704d3539790e8b0fd
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/extra-files/test24590.d
@@ -0,0 +1,10 @@
+shared static this() {
+    throw new Exception("module constructor");
+}
+
+shared static ~this() {
+    import core.stdc.stdio;
+    puts("module destructor");
+}
+
+void main() {}
diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d
index 089144c4fb5c336084d8e74f5d6ceea4249c5e1f..6b8fb458075affac7042d6fd947528c9cb0a2844 100644
--- a/gcc/testsuite/gdc.test/runnable/staticaa.d
+++ b/gcc/testsuite/gdc.test/runnable/staticaa.d
@@ -181,6 +181,32 @@ void testStaticArray()
 
 /////////////////////////////////////////////
 
+// https://issues.dlang.org/show_bug.cgi?id=24602
+
+class Set
+{
+    bool[string] aa;
+
+    this(bool[string] aa)
+    {
+        this.aa = aa;
+    }
+}
+
+class Bar
+{
+    Set x = new Set(["a": 1, "b": 0]);
+}
+
+void testClassLiteral()
+{
+    assert(new Bar().x.aa["a"] == 1);
+    assert(new Bar().x.aa["b"] == 0);
+}
+
+/////////////////////////////////////////////
+
+
 void main()
 {
     testSimple();
@@ -192,4 +218,5 @@ void main()
     testLocalStatic();
     testEnumInit();
     testStaticArray();
+    testClassLiteral();
 }
diff --git a/gcc/testsuite/gdc.test/runnable/test12.d b/gcc/testsuite/gdc.test/runnable/test12.d
index 22f4b849226744347cf9514366218f9e87d07a82..9f99d1cc844d582b678fb60a73eb05004e61e057 100644
--- a/gcc/testsuite/gdc.test/runnable/test12.d
+++ b/gcc/testsuite/gdc.test/runnable/test12.d
@@ -1,4 +1,5 @@
 // PERMUTE_ARGS: -unittest -O -release -inline -fPIC -g
+// TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused")
 
 extern(C) int printf(const char*, ...);
 extern(C) int sprintf(char*, const char*, ...);
diff --git a/gcc/testsuite/gdc.test/runnable/test17559.d b/gcc/testsuite/gdc.test/runnable/test17559.d
index a759f1564c6cabc1d90f478dd34f1064c8b6bd39..e485a683349d21962dd0939c5d47290f30c62c0d 100644
--- a/gcc/testsuite/gdc.test/runnable/test17559.d
+++ b/gcc/testsuite/gdc.test/runnable/test17559.d
@@ -1,5 +1,5 @@
 // REQUIRED_ARGS: -g
-// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic
+// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic
 // PERMUTE_ARGS:
 // DISABLED: osx
 
diff --git a/gcc/testsuite/gdc.test/runnable/test19086.d b/gcc/testsuite/gdc.test/runnable/test19086.d
index 026aee436c8c7cc232c70b22666f75a318328d97..9935f552921f150aea1f62f8b9221f7a95d942e7 100644
--- a/gcc/testsuite/gdc.test/runnable/test19086.d
+++ b/gcc/testsuite/gdc.test/runnable/test19086.d
@@ -1,64 +1,64 @@
-// REQUIRED_ARGS: -g
-// REQUIRED_ARGS(linux freebsd dragonflybsd): -L-export-dynamic
-// PERMUTE_ARGS:
-// DISABLED: osx
-
-void run19086()
-{
-	long x = 1;
-	int y = 0;
-#line 20
-    throw newException();
-}
-
-// moved here to keep run19086 short
-Exception newException() { return new Exception("hi"); }
-
-void test19086()
-{
-	try
-	{
-		run19086();
-	}
-	catch(Exception e)
-	{
-		int line = findLineStackTrace(e.toString(), "run19086");
-		assert(line >= 20 && line <= 21);
-	}
-}
-
-int findLineStackTrace(string msg, string func)
-{
-    // find line number of _Dmain in stack trace
-    // on linux:   file.d:line _Dmain [addr]
-    // on windows: addr in _Dmain at file.d(line)
-    int line = 0;
-    bool found = false;
-    for (size_t pos = 0; pos + func.length < msg.length; pos++)
-    {
-        if (msg[pos] == '\n')
-        {
-            line = 0;
-            found = false;
-        }
-        else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)
-        {
-            for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)
-                line = line * 10 + msg[pos] - '0';
-            if (line > 0 && found)
-                return line;
-        }
-        else if (msg[pos .. pos + func.length] == func)
-        {
-            found = true;
-            if (line > 0 && found)
-                return line;
-        }
-    }
-    return 0;
-}
-
-void main()
-{
-	test19086();
-}
+// REQUIRED_ARGS: -g
+// REQUIRED_ARGS(linux freebsd openbsd dragonflybsd): -L-export-dynamic
+// PERMUTE_ARGS:
+// DISABLED: osx
+
+void run19086()
+{
+	long x = 1;
+	int y = 0;
+#line 20
+    throw newException();
+}
+
+// moved here to keep run19086 short
+Exception newException() { return new Exception("hi"); }
+
+void test19086()
+{
+	try
+	{
+		run19086();
+	}
+	catch(Exception e)
+	{
+		int line = findLineStackTrace(e.toString(), "run19086");
+		assert(line >= 20 && line <= 21);
+	}
+}
+
+int findLineStackTrace(string msg, string func)
+{
+    // find line number of _Dmain in stack trace
+    // on linux:   file.d:line _Dmain [addr]
+    // on windows: addr in _Dmain at file.d(line)
+    int line = 0;
+    bool found = false;
+    for (size_t pos = 0; pos + func.length < msg.length; pos++)
+    {
+        if (msg[pos] == '\n')
+        {
+            line = 0;
+            found = false;
+        }
+        else if ((msg[pos] == ':' || msg[pos] == '(') && line == 0)
+        {
+            for (pos++; pos < msg.length && msg[pos] >= '0' && msg[pos] <= '9'; pos++)
+                line = line * 10 + msg[pos] - '0';
+            if (line > 0 && found)
+                return line;
+        }
+        else if (msg[pos .. pos + func.length] == func)
+        {
+            found = true;
+            if (line > 0 && found)
+                return line;
+        }
+    }
+    return 0;
+}
+
+void main()
+{
+	test19086();
+}
diff --git a/gcc/testsuite/gdc.test/runnable/testthread2.d b/gcc/testsuite/gdc.test/runnable/testthread2.d
index 2c87ecd8a7dfa46194593f20f847f58720ace943..346e3862e59ac26bf38d1dab4f199b1ccc8e1f12 100644
--- a/gcc/testsuite/gdc.test/runnable/testthread2.d
+++ b/gcc/testsuite/gdc.test/runnable/testthread2.d
@@ -1,4 +1,5 @@
 // PERMUTE_ARGS:
+// TRANSFORM_OUTPUT: remove_lines("warning: rand\(\) may return deterministic values")
 
 // Quick, dirty and inefficient AA using linear search, useful for testing.
 struct LinearAA(K, V) {
diff --git a/gcc/testsuite/gdc.test/runnable/variadic.d b/gcc/testsuite/gdc.test/runnable/variadic.d
index 7e9473c332edc50db1dd21ed329f426ac8d018a3..ddfd92c1676f164ae7fe2a75aa74591b7bbd7223 100644
--- a/gcc/testsuite/gdc.test/runnable/variadic.d
+++ b/gcc/testsuite/gdc.test/runnable/variadic.d
@@ -1,3 +1,5 @@
+// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused")
+
 alias TypeTuple(T...) = T;
 
 class A { }
diff --git a/gcc/testsuite/gdc.test/runnable/whetstone.d b/gcc/testsuite/gdc.test/runnable/whetstone.d
index 9145c74bcfd1327bc6de07a8159b1d49283e136b..48f6010b9ffd5fd67a4740b3d3ba6a84236cd45f 100644
--- a/gcc/testsuite/gdc.test/runnable/whetstone.d
+++ b/gcc/testsuite/gdc.test/runnable/whetstone.d
@@ -1,5 +1,6 @@
 /*
 PERMUTE_ARGS: -O
+TRANSFORM_OUTPUT: remove_lines("warning: sprintf\(\) is often misused")
 */
 
 /*
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
index 5d4bc99c1bd4b731c5c36a39fe366a686d383df3..4e241749fbc9d9cac2fe8005eed8f4c2918c1f08 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_abi_tests.d
@@ -1,5 +1,5 @@
 // EXTRA_CPP_SOURCES: cpp_abi_tests.cpp
-// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11
 
 // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
 // N.B MSVC 2013 doesn't support char16_t/char32_t
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d
index dd7bb11fc648e44b91b78cd73ba8faac855bcf5d..5b7d00a381941a5414bc6bf69300cc5641d64b7a 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cpp_stdlib.d
@@ -5,7 +5,7 @@ import core.stdc.stdio;
 
 // Disabled on windows because it needs bindings
 
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
 {
     extern(C++, `std`, `__1`)
     {
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
index 34c295590e391b4b8e5f23fa887df362c1597365..c62bc6face183837da1a1585a816dc47032f6ec6 100644
--- a/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
+++ b/gcc/testsuite/gdc.test/runnable_cxx/cppa.d
@@ -2,9 +2,10 @@
 // PERMUTE_ARGS: -g
 // EXTRA_CPP_SOURCES: cppb.cpp
 // EXTRA_FILES: extra-files/cppb.h
-// CXXFLAGS(linux freebsd osx netbsd dragonflybsd): -std=c++11
+// CXXFLAGS(linux freebsd osx openbsd netbsd dragonflybsd): -std=c++11
 // druntime isn't linked, this prevents missing symbols '_d_arraybounds_slicep':
 // REQUIRED_ARGS: -checkaction=C
+// TRANSFORM_OUTPUT: remove_lines("warning: vsprintf\(\) is often misused")
 
 // N.B MSVC doesn't have a C++11 switch, but it defaults to the latest fully-supported standard
 
@@ -454,7 +455,7 @@ extern (C++, std)
     {
     }
 
-    version (CppRuntime_Gcc)
+    version (CppRuntime_GNU)
     {
         // https://gcc.gnu.org/onlinedocs/libstdc++/manual/using_dual_abi.html
         static if (__traits(getTargetInfo, "cppStd") >= 201103)
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..c320ec5582166d1a2a4b2563b5df0902dda6b52c
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/extra-files/cpp_nonpod_byval.cpp
@@ -0,0 +1,74 @@
+extern "C" int printf(const char *, ...);
+
+#define Foo(T) \
+    T fooD(T param); \
+    T fooCpp(T param) \
+    { \
+        printf("fooCpp %d [%p]\n", param.a, &param); \
+        return fooD(T{2 * param.a}); \
+    }
+
+struct POD
+{
+    int a;
+};
+Foo(POD);
+
+struct CtorOnly
+{
+    int a;
+    CtorOnly() : a(0) {}
+    CtorOnly(int a) : a(a) {}
+};
+Foo(CtorOnly);
+
+struct DtorOnly
+{
+    int a;
+    ~DtorOnly(); // implemented in D
+};
+Foo(DtorOnly);
+
+struct CtorDtor
+{
+    int a;
+    CtorDtor(int a) : a(a) {}
+    ~CtorDtor(); // implemented in D
+};
+Foo(CtorDtor);
+
+struct Copy
+{
+    int a;
+    Copy(int a) : a(a) {}
+    ~Copy(); // implemented in D
+    Copy(const Copy &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); }
+};
+Foo(Copy);
+
+struct CopyAndMove
+{
+    int a;
+    CopyAndMove(int a) : a(a) {}
+    ~CopyAndMove(); // implemented in D
+    CopyAndMove(const CopyAndMove &rhs) : a(rhs.a) { printf("cppcpy %d [%p]\n", a, this); }
+    CopyAndMove(CopyAndMove &&) = default;
+};
+Foo(CopyAndMove);
+
+struct MoveOnly
+{
+    int a;
+    MoveOnly(int a) : a(a) {}
+    ~MoveOnly(); // implemented in D
+    MoveOnly(const MoveOnly &) = delete;
+    MoveOnly(MoveOnly &&) = default;
+};
+Foo(MoveOnly);
+
+struct MemberWithCtor
+{
+    int a;
+    CtorOnly m;
+};
+Foo(MemberWithCtor);
diff --git a/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d b/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d
new file mode 100644
index 0000000000000000000000000000000000000000..c7fac46a040a2844df9956f7886584100d7b9a90
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable_cxx/nonpod_byval.d
@@ -0,0 +1,118 @@
+// EXTRA_CPP_SOURCES: cpp_nonpod_byval.cpp
+// CXXFLAGS(linux osx freebsd dragonflybsd): -std=c++11
+
+extern (C) int printf(const(char)*, ...);
+
+extern (C++):
+
+template Foo(T)
+{
+    T fooCpp(T param); // calls fooD() with a new, doubled literal
+
+    T fooD(T param)
+    {
+        printf("fooD   %d [%p]\n", param.a, &param);
+        assert(param.a == 2 * 123);
+        static if (__traits(compiles, { T copy = param; }))
+            return param; // invokes postblit
+        else
+            return T(param.a);
+    }
+}
+
+void test(T)()
+{
+    printf(".: %.*s\n", cast(int) T.stringof.length, T.stringof.ptr);
+
+    {
+        auto result = fooCpp(T(123));
+        assert(result.a == 246);
+    }
+
+    static if (__traits(hasMember, T, "numDtor"))
+    {
+        // fooCpp param + fooD param + result => 3 T instances.
+        // There may be an additional destruction of the moved-from T literal
+        // in fooCpp, depending on in-place construction vs. move.
+        assert(T.numDtor == 3 || T.numDtor == 4);
+    }
+}
+
+struct POD
+{
+    int a;
+}
+mixin Foo!POD;
+
+struct CtorOnly
+{
+    int a;
+    this(int a) { this.a = a; }
+}
+mixin Foo!CtorOnly;
+
+struct DtorOnly
+{
+    static __gshared int numDtor = 0;
+    int a;
+    ~this() { printf("dtor   %d [%p]\n", a, &this); ++numDtor; }
+}
+mixin Foo!DtorOnly;
+
+struct CtorDtor
+{
+    static __gshared int numDtor = 0;
+    int a;
+    this(int a) { this.a = a; }
+    ~this() { printf("dtor   %d [%p]\n", a, &this); ++numDtor; }
+}
+mixin Foo!CtorDtor;
+
+struct Copy
+{
+    static __gshared int numDtor = 0;
+    int a;
+    this(int a) { this.a = a; }
+    ~this() { printf("dtor   %d [%p]\n", a, &this); ++numDtor; }
+    this(this) { printf("post   %d [%p]\n", a, &this); }
+}
+mixin Foo!Copy;
+
+struct CopyAndMove
+{
+    static __gshared int numDtor = 0;
+    int a;
+    this(int a) { this.a = a; }
+    ~this() { printf("dtor   %d [%p]\n", a, &this); ++numDtor; }
+    this(this) { printf("post   %d [%p]\n", a, &this); }
+}
+mixin Foo!CopyAndMove;
+
+struct MoveOnly
+{
+    static __gshared int numDtor = 0;
+    int a;
+    this(int a) { this.a = a; }
+    ~this() { printf("dtor   %d [%p]\n", a, &this); ++numDtor; }
+    this(this) @disable;
+}
+mixin Foo!MoveOnly;
+
+struct MemberWithCtor
+{
+    int a;
+    CtorOnly m;
+}
+mixin Foo!MemberWithCtor;
+
+void main()
+{
+    test!POD();
+    test!CtorOnly();
+    test!DtorOnly();
+    test!CtorDtor();
+    test!Copy();
+    test!CopyAndMove();
+    test!MoveOnly();
+    test!MemberWithCtor();
+}
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 77e8562abcc346f344c4d264393c1bce0f9dd798..d458bea5e1a593bfcd3455a9fe99cdc29f4c5b09 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@
-07bc5b9b3c81cc0d4314e0040de981124b363ea5
+66b93fc24a7ab5e2a8aa7f53c613df4abddc188b
 
 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/checkedint.d b/libphobos/libdruntime/core/checkedint.d
index 49a5c11d1373bd96ba27db3b9e60135282338546..4c40b9957a994096109537bf5d88b02072bb5814 100644
--- a/libphobos/libdruntime/core/checkedint.d
+++ b/libphobos/libdruntime/core/checkedint.d
@@ -186,8 +186,8 @@ unittest
     {
         bool overflow;
         immutable uint r = addu (uint.max - i, uint.max - i, overflow);
-        assert (r == 2 * (uint.max - i));
-        assert (overflow);
+        assert(r == 2 * (uint.max - i));
+        assert(overflow);
     }
 
     bool overflow;
diff --git a/libphobos/libdruntime/core/internal/newaa.d b/libphobos/libdruntime/core/internal/newaa.d
index 2fd93651a22b40456b28563eac63db3e048390e9..7c858f33522ceaade006076c39350a20ed660f4f 100644
--- a/libphobos/libdruntime/core/internal/newaa.d
+++ b/libphobos/libdruntime/core/internal/newaa.d
@@ -102,7 +102,7 @@ AAShell makeAA(K, V)(V[K] src) @trusted
         dim = dim * GROW_FAC;
 
     // used during runtime.
-    size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) {
+    typeof(Impl.hashFn) hashFn = (scope const void* val) {
         auto x = cast(K*)val;
         return hashOf(*x);
     };
diff --git a/libphobos/libdruntime/core/internal/parseoptions.d b/libphobos/libdruntime/core/internal/parseoptions.d
index 2bf1da2fbfa5845cd60e0a7dba19f66d229553bc..2dd3ec8375b2bba484344ba8b53febee6aa6b73a 100644
--- a/libphobos/libdruntime/core/internal/parseoptions.d
+++ b/libphobos/libdruntime/core/internal/parseoptions.d
@@ -219,13 +219,12 @@ do
                     return overflowedError(optname, str);
 
                 i++;
-                break;
             }
             else // unexpected non-digit character
             {
                 i = 0;
-                break;
             }
+            break;
         }
     }
 
diff --git a/libphobos/libdruntime/core/internal/traits.d b/libphobos/libdruntime/core/internal/traits.d
index 0b2eb1f21a711a3b2bd6ee473013ffc56fc00eec..f0d9ebc9a81362b41005ea76f7607373c377698e 100644
--- a/libphobos/libdruntime/core/internal/traits.d
+++ b/libphobos/libdruntime/core/internal/traits.d
@@ -51,7 +51,7 @@ unittest
     static assert(is(BaseElemOf!(int[1][2]) == int));
     static assert(is(BaseElemOf!(int[1][]) == int[1][]));
     static assert(is(BaseElemOf!(int[][1]) == int[]));
-    static enum E : int[2]{ test = [0, 1] }
+    enum E : int[2]{ test = [0, 1] }
     static assert(is(BaseElemOf!(E) == int));
 }
 
@@ -809,30 +809,23 @@ unittest
 
 template hasUDA(alias symbol, alias attribute)
 {
-    alias attrs = __traits(getAttributes, symbol);
+    enum isAttr(T) = is(T == attribute);
 
-    static foreach (a; attrs)
-    {
-        static if (is(a == attribute))
-        {
-            enum hasUDA = true;
-        }
-    }
-
-    static if (!__traits(compiles, (hasUDA == true)))
-        enum hasUDA = false;
+    enum hasUDA = anySatisfy!(isAttr, __traits(getAttributes, symbol));
 }
 
 unittest
 {
-    struct SomeUDA{}
+    enum SomeUDA;
 
     struct Test
     {
         int woUDA;
-        @SomeUDA int withUDA;
+        @SomeUDA int oneUDA;
+        @SomeUDA @SomeUDA int twoUDAs;
     }
 
-    static assert(hasUDA!(Test.withUDA, SomeUDA));
+    static assert(hasUDA!(Test.oneUDA, SomeUDA));
+    static assert(hasUDA!(Test.twoUDAs, SomeUDA));
     static assert(!hasUDA!(Test.woUDA, SomeUDA));
 }
diff --git a/libphobos/libdruntime/core/lifetime.d b/libphobos/libdruntime/core/lifetime.d
index 9e563ad43a30622fe58c04f77b13ca56e5761037..f3dab3624acc08ae5914316d089662b63c076599 100644
--- a/libphobos/libdruntime/core/lifetime.d
+++ b/libphobos/libdruntime/core/lifetime.d
@@ -104,7 +104,7 @@ T emplace(T, Args...)(T chunk, auto ref Args args)
 
     // Initialize the object in its pre-ctor state
     const initializer = __traits(initSymbol, T);
-    (() @trusted { (cast(void*) chunk)[0 .. initializer.length] = initializer[]; })();
+    () @trusted { (cast(void*) chunk)[0 .. initializer.length] = cast(void[]) initializer[]; }();
 
     static if (isInnerClass!T)
     {
@@ -2683,7 +2683,7 @@ T _d_newThrowable(T)() @trusted
     debug(PRINTF) printf(" p = %p\n", p);
 
     // initialize it
-    p[0 .. init.length] = init[];
+    p[0 .. init.length] = cast(void[]) init[];
 
     import core.internal.traits : hasIndirections;
     if (hasIndirections!T)
@@ -2776,7 +2776,7 @@ if (is(T == class))
     }
 
     // initialize it
-    p[0 .. init.length] = init[];
+    p[0 .. init.length] = cast(void[]) init[];
 
     debug(PRINTF) printf("initialization done\n");
     return cast(T) p;
diff --git a/libphobos/libdruntime/core/runtime.d b/libphobos/libdruntime/core/runtime.d
index 4ff728cc38c3df0ff9451330b4097917d78a5f5d..182886175a6b2232b23b2f91ff8b1fbd8d1ceca5 100644
--- a/libphobos/libdruntime/core/runtime.d
+++ b/libphobos/libdruntime/core/runtime.d
@@ -613,7 +613,7 @@ extern (C) UnitTestResult runModuleUnitTests()
 
         static extern (C) void unittestSegvHandler( int signum, siginfo_t* info, void* ptr ) nothrow
         {
-            static enum MAXFRAMES = 128;
+            enum MAXFRAMES = 128;
             void*[MAXFRAMES]  callstack;
 
             auto numframes = backtrace( callstack.ptr, MAXFRAMES );
@@ -942,7 +942,7 @@ else static if (hasExecinfo) private class DefaultTraceInfo : Throwable.TraceInf
 
 private:
     int     numframes;
-    static enum MAXFRAMES = 128;
+    enum MAXFRAMES = 128;
     void*[MAXFRAMES]  callstack = void;
 
 private:
diff --git a/libphobos/libdruntime/core/stdcpp/allocator.d b/libphobos/libdruntime/core/stdcpp/allocator.d
index abf97c48b0b57acd759a0c102539c66772f95268..a574cd39e8b48723f379242e2358acebc7268398 100644
--- a/libphobos/libdruntime/core/stdcpp/allocator.d
+++ b/libphobos/libdruntime/core/stdcpp/allocator.d
@@ -147,7 +147,7 @@ extern(D):
         ///
         enum size_t max_size = size_t.max / T.sizeof;
     }
-    else version (CppRuntime_Gcc)
+    else version (CppRuntime_GNU)
     {
         ///
         T* allocate(size_t count, const(void)* = null) @nogc
@@ -174,7 +174,7 @@ extern(D):
         ///
         enum size_t max_size = (ptrdiff_t.max < size_t.max ? cast(size_t)ptrdiff_t.max : size_t.max) / T.sizeof;
     }
-    else version (CppRuntime_Clang)
+    else version (CppRuntime_LLVM)
     {
         ///
         T* allocate(size_t count, const(void)* = null) @nogc
@@ -360,7 +360,7 @@ version (CppRuntime_Microsoft)
         }
     }
 }
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
 {
     // Helper for container swap
     package(core.stdcpp) void __swap_allocator(Alloc)(ref Alloc __a1, ref Alloc __a2)
diff --git a/libphobos/libdruntime/core/stdcpp/array.d b/libphobos/libdruntime/core/stdcpp/array.d
index 4cb0c56ec5fff00f2f3793feeb408685ee52ff87..912587c6c75bed299924e25d062079f2bfd24262 100644
--- a/libphobos/libdruntime/core/stdcpp/array.d
+++ b/libphobos/libdruntime/core/stdcpp/array.d
@@ -74,7 +74,7 @@ pure nothrow @nogc:
     private:
         T[N ? N : 1] _Elems;
     }
-    else version (CppRuntime_Gcc)
+    else version (CppRuntime_GNU)
     {
         ///
         inout(T)* data() inout @safe                    { static if (N > 0) { return &_M_elems[0]; } else { return null; } }
@@ -94,7 +94,7 @@ pure nothrow @nogc:
             _Placeholder _M_placeholder;
         }
     }
-    else version (CppRuntime_Clang)
+    else version (CppRuntime_LLVM)
     {
         ///
         inout(T)* data() inout @trusted                 { static if (N > 0) { return &__elems_[0]; } else { return cast(inout(T)*)__elems_.ptr; } }
diff --git a/libphobos/libdruntime/core/stdcpp/exception.d b/libphobos/libdruntime/core/stdcpp/exception.d
index 4774b98615bf675c9ec3a15a3b5258823a92c5ea..bd3be0937f639eb1c802b8c1e9bc4c40bf640a0c 100644
--- a/libphobos/libdruntime/core/stdcpp/exception.d
+++ b/libphobos/libdruntime/core/stdcpp/exception.d
@@ -15,9 +15,9 @@ module core.stdcpp.exception;
 import core.stdcpp.xutility : __cplusplus, CppStdRevision;
 import core.attribute : weak;
 
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
     version = GenericBaseException;
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
     version = GenericBaseException;
 version (CppRuntime_Sun)
     version = GenericBaseException;
diff --git a/libphobos/libdruntime/core/stdcpp/memory.d b/libphobos/libdruntime/core/stdcpp/memory.d
index bd7976cfbc59694e8e1ba3900cba9b9174e61af1..d7b6f173878ed909995d11bf1291f8d715565abd 100644
--- a/libphobos/libdruntime/core/stdcpp/memory.d
+++ b/libphobos/libdruntime/core/stdcpp/memory.d
@@ -123,7 +123,7 @@ nothrow pure @safe @nogc:
 
         _Compressed_pair!(Deleter, pointer) _Mypair;
     }
-    else version (CppRuntime_Gcc)
+    else version (CppRuntime_GNU)
     {
         ///
         ref inout(deleter_type) get_deleter() inout nothrow { return _M_t.get!1; }
@@ -136,7 +136,7 @@ nothrow pure @safe @nogc:
 
         tuple!(pointer, Deleter) _M_t;
     }
-    else version (CppRuntime_Clang)
+    else version (CppRuntime_LLVM)
     {
         ///
         ref inout(deleter_type) get_deleter() inout nothrow { return __ptr_.second; }
diff --git a/libphobos/libdruntime/core/stdcpp/string.d b/libphobos/libdruntime/core/stdcpp/string.d
index 722b82fe41848267ebb1a22fd4b0d3d96038f945..0315867da60c8228b58ea789216003f30887d5fa 100644
--- a/libphobos/libdruntime/core/stdcpp/string.d
+++ b/libphobos/libdruntime/core/stdcpp/string.d
@@ -31,7 +31,7 @@ version (Darwin)
     version = _LIBCPP_ABI_ALTERNATE_STRING_LAYOUT;
 }
 
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
 {
     version (_GLIBCXX_USE_CXX98_ABI)
     {
@@ -894,7 +894,7 @@ extern(D):
 
         _String_alloc!(_String_base_types!(T, Alloc)) _Base;
     }
-    else version (CppRuntime_Gcc)
+    else version (CppRuntime_GNU)
     {
         version (_GLIBCXX_USE_CXX98_ABI)
         {
@@ -1873,10 +1873,10 @@ extern(D):
             __d[0 .. __n] = __s[0 .. __n];
         }
     }
-    else version (CppRuntime_Clang)
+    else version (CppRuntime_LLVM)
     {
         //----------------------------------------------------------------------------------
-        // Clang/libc++ implementation
+        // libc++ implementation
         //----------------------------------------------------------------------------------
 
         ///
diff --git a/libphobos/libdruntime/core/stdcpp/string_view.d b/libphobos/libdruntime/core/stdcpp/string_view.d
index 47f58b014ef1e9efde512511b0aac38fa8cf18d5..fd79a121be51f2ca43c8fffee4674c020d38a1c4 100644
--- a/libphobos/libdruntime/core/stdcpp/string_view.d
+++ b/libphobos/libdruntime/core/stdcpp/string_view.d
@@ -99,7 +99,7 @@ private:
         alias __data = _Mydata;
         alias __size = _Mysize;
     }
-    else version (CppRuntime_Gcc)
+    else version (CppRuntime_GNU)
     {
         size_t _M_len;
         const(T)* _M_str;
@@ -107,7 +107,7 @@ private:
         alias __data = _M_str;
         alias __size = _M_len;
     }
-    else version (CppRuntime_Clang)
+    else version (CppRuntime_LLVM)
     {
         const value_type* __data;
         size_type __size;
diff --git a/libphobos/libdruntime/core/stdcpp/typeinfo.d b/libphobos/libdruntime/core/stdcpp/typeinfo.d
index b8478b39414acd9d43cc2e11f93eb5aae2b2a90b..463a813bc968c5923f5458db23fe460b344d2615 100644
--- a/libphobos/libdruntime/core/stdcpp/typeinfo.d
+++ b/libphobos/libdruntime/core/stdcpp/typeinfo.d
@@ -56,7 +56,7 @@ version (CppRuntime_Microsoft)
         //virtual ~this();
     }
 }
-else version (CppRuntime_Gcc)
+else version (CppRuntime_GNU)
 {
     import core.stdcpp.exception;
 
@@ -110,7 +110,7 @@ else version (CppRuntime_Gcc)
         @weak override const(char)* what() const nothrow { return "bad typeid"; }
     }
 }
-else version (CppRuntime_Clang)
+else version (CppRuntime_LLVM)
 {
     import core.stdcpp.exception;
 
diff --git a/libphobos/libdruntime/core/stdcpp/xutility.d b/libphobos/libdruntime/core/stdcpp/xutility.d
index 0142d0b9455feb4155488373218fefda3152f0e9..5e2e711ba67bf8dff123989779fe83eced2b728d 100644
--- a/libphobos/libdruntime/core/stdcpp/xutility.d
+++ b/libphobos/libdruntime/core/stdcpp/xutility.d
@@ -13,7 +13,7 @@ module core.stdcpp.xutility;
 
 @nogc:
 
-version (CppRuntime_Clang)
+version (CppRuntime_LLVM)
 {
     import core.internal.traits : AliasSeq;
     enum StdNamespace = AliasSeq!("std", "__1");
@@ -349,7 +349,7 @@ package:
     void _Xoverflow_error(const(char)* message) nothrow;
     void _Xruntime_error(const(char)* message) nothrow;
 }
-else version (CppRuntime_Clang)
+else version (CppRuntime_LLVM)
 {
     import core.stdcpp.type_traits : is_empty;
 
@@ -379,7 +379,7 @@ extern(C++, "std"):
             @property ref inout(_T2) __value2_() inout nothrow @trusted @nogc { return *__get_base2(); }
     }
 }
-version (CppRuntime_Gcc)
+version (CppRuntime_GNU)
 {
     import core.atomic;
 
diff --git a/libphobos/libdruntime/core/sys/posix/dirent.d b/libphobos/libdruntime/core/sys/posix/dirent.d
index c7e8649d6c58b9258839e44e3fb1184b42f26565..cb76573a95b5391a6e73e027acdb31de502ddab5 100644
--- a/libphobos/libdruntime/core/sys/posix/dirent.d
+++ b/libphobos/libdruntime/core/sys/posix/dirent.d
@@ -42,7 +42,18 @@ struct dirent
 }
 */
 
-version (linux)
+version (CRuntime_Bionic)
+{
+    struct dirent
+    {
+        ulong       d_ino;
+        long        d_off;
+        ushort      d_reclen;
+        ubyte       d_type;
+        char[256]   d_name = 0;
+    }
+}
+else version (linux)
 {
     struct dirent
     {
diff --git a/libphobos/libdruntime/core/sys/posix/dlfcn.d b/libphobos/libdruntime/core/sys/posix/dlfcn.d
index f457c1f22b776aba714ee18d14f9503748585514..76542c64c8a3edd82db8cee21110d227ae313d57 100644
--- a/libphobos/libdruntime/core/sys/posix/dlfcn.d
+++ b/libphobos/libdruntime/core/sys/posix/dlfcn.d
@@ -372,12 +372,20 @@ else version (Solaris)
 }
 else version (CRuntime_Bionic)
 {
-    enum
+    enum RTLD_LOCAL    = 0;
+    enum RTLD_LAZY     = 0x00001;
+    enum RTLD_NOLOAD   = 0x00004;
+    enum RTLD_NODELETE = 0x01000;
+
+    version (D_LP64)
+    {
+        enum RTLD_NOW      = 0x00002;
+        enum RTLD_GLOBAL   = 0x00100;
+    }
+    else // NDK: 'LP32 is broken for historical reasons'
     {
-        RTLD_NOW    = 0,
-        RTLD_LAZY   = 1,
-        RTLD_LOCAL  = 0,
-        RTLD_GLOBAL = 2
+        enum RTLD_NOW      = 0;
+        enum RTLD_GLOBAL   = 0x00002;
     }
 
     int          dladdr(const scope void*, Dl_info*);
diff --git a/libphobos/libdruntime/core/sys/posix/sys/stat.d b/libphobos/libdruntime/core/sys/posix/sys/stat.d
index b89478fe7d7515b745232bc5e82f9346d22cc22e..328f620a42a2234e9652d49c71360f1148730522 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/stat.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/stat.d
@@ -33,6 +33,11 @@ version (RISCV64) version = RISCV_Any;
 version (SPARC)   version = SPARC_Any;
 version (SPARC64) version = SPARC_Any;
 
+// Android uses 64-bit offsets for stat, but 32-bit offsets for most
+// other types on 32-bit architectures.
+version (CRuntime_Bionic)
+    private enum __USE_FILE_OFFSET64 = true;
+
 version (Posix):
 extern (C) nothrow @nogc:
 
diff --git a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d
index eae0e5c95c6ba2ee9010b80ae7b34e7a15d22235..9405a6d5387ebdfd6ef9619b85040a92ebaed193 100644
--- a/libphobos/libdruntime/core/sys/posix/sys/statvfs.d
+++ b/libphobos/libdruntime/core/sys/posix/sys/statvfs.d
@@ -84,7 +84,57 @@ version (CRuntime_Glibc) {
         int statvfs (const char * file, statvfs_t* buf);
         int fstatvfs (int fildes, statvfs_t *buf);
     }
+}
+else version (CRuntime_Musl)
+{
+    struct statvfs_t
+    {
+        c_ulong f_bsize;
+        c_ulong f_frsize;
+        fsblkcnt_t f_blocks;
+        fsblkcnt_t f_bfree;
+        fsblkcnt_t f_bavail;
+        fsfilcnt_t f_files;
+        fsfilcnt_t f_ffree;
+        fsfilcnt_t f_favail;
+        static if (true /+__BYTE_ORDER == __LITTLE_ENDIAN+/)
+        {
+            c_ulong f_fsid;
+            byte[2*int.sizeof-c_long.sizeof] __padding;
+        }
+        else
+        {
+            byte[2*int.sizeof-c_long.sizeof] __padding;
+            c_ulong f_fsid;
+        }
+        c_ulong f_flag;
+        c_ulong f_namemax;
+        uint    f_type;
+        int[5]  __reserved;
+    }
+
+    enum FFlag
+    {
+        ST_RDONLY = 1,        /* Mount read-only.  */
+        ST_NOSUID = 2,
+        ST_NODEV = 4,         /* Disallow access to device special files.  */
+        ST_NOEXEC = 8,        /* Disallow program execution.  */
+        ST_SYNCHRONOUS = 16,      /* Writes are synced at once.  */
+        ST_MANDLOCK = 64,     /* Allow mandatory locks on an FS.  */
+        ST_WRITE = 128,       /* Write on file/directory/symlink.  */
+        ST_APPEND = 256,      /* Append-only file.  */
+        ST_IMMUTABLE = 512,       /* Immutable file.  */
+        ST_NOATIME = 1024,        /* Do not update access times.  */
+        ST_NODIRATIME = 2048,     /* Do not update directory access times.  */
+        ST_RELATIME = 4096        /* Update atime relative to mtime/ctime.  */
+
+    }
+
+    int statvfs (const char * file, statvfs_t* buf);
+    int fstatvfs (int fildes, statvfs_t *buf);
 
+    alias statvfs statvfs64;
+    alias fstatvfs fstatvfs64;
 }
 else version (NetBSD)
 {
diff --git a/libphobos/libdruntime/core/sys/windows/stacktrace.d b/libphobos/libdruntime/core/sys/windows/stacktrace.d
index 29ffc1b078546d4c613675a3796c78fa2ea6f322..04aafd3f6022d136bd0997760dbd8d0497d88ca8 100644
--- a/libphobos/libdruntime/core/sys/windows/stacktrace.d
+++ b/libphobos/libdruntime/core/sys/windows/stacktrace.d
@@ -48,9 +48,9 @@ public:
         if (context is null)
         {
             version (Win64)
-                static enum INTERNALFRAMES = 3;
+                enum INTERNALFRAMES = 3;
             else version (Win32)
-                static enum INTERNALFRAMES = 2;
+                enum INTERNALFRAMES = 2;
 
             skip += INTERNALFRAMES; //skip the stack frames within the StackTrace class
         }
@@ -58,9 +58,9 @@ public:
         {
             //When a exception context is given the first stack frame is repeated for some reason
             version (Win64)
-                static enum INTERNALFRAMES = 1;
+                enum INTERNALFRAMES = 1;
             else version (Win32)
-                static enum INTERNALFRAMES = 1;
+                enum INTERNALFRAMES = 1;
 
             skip += INTERNALFRAMES;
         }
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 0bdb45a343fa9133db372f5e3944ef64ae54ee45..307048135b8546a5c9f2987bde47dcb6ff042888 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -2211,7 +2211,7 @@ extern (C) void thread_init() @nogc nothrow
         status = sem_init( &suspendCount, 0, 0 );
         assert( status == 0 );
     }
-    _mainThreadStore[] = __traits(initSymbol, Thread)[];
+    _mainThreadStore[] = cast(void[]) __traits(initSymbol, Thread)[];
     Thread.sm_main = attachThread((cast(Thread)_mainThreadStore.ptr).__ctor());
 }
 
diff --git a/libphobos/libdruntime/core/thread/threadbase.d b/libphobos/libdruntime/core/thread/threadbase.d
index f593387c755a00e93f78c567f16a662f1c4346a9..58dd259e30ddb458fbca17abb9840a04f7fe696b 100644
--- a/libphobos/libdruntime/core/thread/threadbase.d
+++ b/libphobos/libdruntime/core/thread/threadbase.d
@@ -778,7 +778,7 @@ package void thread_term_tpl(ThreadT, MainThreadStore)(ref MainThreadStore _main
     // destruct manually as object.destroy is not @nogc
     (cast(ThreadT) cast(void*) ThreadBase.sm_main).__dtor();
     _d_monitordelete_nogc(ThreadBase.sm_main);
-    _mainThreadStore[] = __traits(initSymbol, ThreadT)[];
+    _mainThreadStore[] = cast(void[]) __traits(initSymbol, ThreadT)[];
     ThreadBase.sm_main = null;
 
     assert(ThreadBase.sm_tbeg && ThreadBase.sm_tlen == 1);
diff --git a/libphobos/libdruntime/gcc/sections/elf.d b/libphobos/libdruntime/gcc/sections/elf.d
index 1a3ff409d5802b2c0fc18b71adeefbef31976efe..bbebedf345ecbb6ed293f83e45d988ba18a7fe8d 100644
--- a/libphobos/libdruntime/gcc/sections/elf.d
+++ b/libphobos/libdruntime/gcc/sections/elf.d
@@ -161,18 +161,11 @@ private:
     }
 }
 
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
-
 /****
  * Gets called on program startup just before GC is initialized.
  */
 void initSections() nothrow @nogc
 {
-    _isRuntimeInitialized = true;
 }
 
 
@@ -181,7 +174,6 @@ void initSections() nothrow @nogc
  */
 void finiSections() nothrow @nogc
 {
-    _isRuntimeInitialized = false;
 }
 
 alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
@@ -482,7 +474,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         }
 
         // don't initialize modules before rt_init was called (see Bugzilla 11378)
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             registerGCRanges(pdso);
             // rt_loadLibrary will run tls ctors, so do this only for dlopen
@@ -497,7 +489,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         *data._slot = null;
 
         // don't finalizes modules after rt_term was called (see Bugzilla 11378)
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
             immutable runTlsDtors = !_rtLoading;
diff --git a/libphobos/libdruntime/gcc/sections/macho.d b/libphobos/libdruntime/gcc/sections/macho.d
index 645c0f48350cdbbb0dec25dae93bdd4027f082ff..7211fa773905e556d946e9124d791ab63eba310b 100644
--- a/libphobos/libdruntime/gcc/sections/macho.d
+++ b/libphobos/libdruntime/gcc/sections/macho.d
@@ -30,6 +30,7 @@ import core.sys.darwin.dlfcn;
 import core.sys.darwin.mach.dyld;
 import core.sys.darwin.mach.getsect;
 import core.sys.posix.pthread;
+import rt.dmain2;
 import rt.minfo;
 import core.internal.container.array;
 import core.internal.container.hashtab;
@@ -95,17 +96,11 @@ private:
     }
 }
 
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
 /****
  * Gets called on program startup just before GC is initialized.
  */
 void initSections() nothrow @nogc
 {
-    _isRuntimeInitialized = true;
 }
 
 /***
@@ -113,7 +108,6 @@ void initSections() nothrow @nogc
  */
 void finiSections() nothrow @nogc
 {
-    _isRuntimeInitialized = false;
 }
 
 alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
@@ -379,7 +373,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         }
 
         // don't initialize modules before rt_init was called
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             registerGCRanges(pdso);
             // rt_loadLibrary will run tls ctors, so do this only for dlopen
@@ -394,7 +388,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         *data._slot = null;
 
         // don't finalizes modules after rt_term was called (see Bugzilla 11378)
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
             immutable runTlsDtors = !_rtLoading;
diff --git a/libphobos/libdruntime/gcc/sections/pecoff.d b/libphobos/libdruntime/gcc/sections/pecoff.d
index 038e37398ed63d92db096f620c9037abab6c7cb6..fb49f6201e0666dece1b000b990ba39883c02011 100644
--- a/libphobos/libdruntime/gcc/sections/pecoff.d
+++ b/libphobos/libdruntime/gcc/sections/pecoff.d
@@ -29,6 +29,7 @@ import core.stdc.stdlib;
 import core.sys.windows.winbase;
 import core.sys.windows.windef;
 import core.sys.windows.winnt;
+import rt.dmain2;
 import rt.minfo;
 import core.internal.container.array;
 import core.internal.container.hashtab;
@@ -94,17 +95,11 @@ private:
     }
 }
 
-/****
- * Boolean flag set to true while the runtime is initialized.
- */
-__gshared bool _isRuntimeInitialized;
-
 /****
  * Gets called on program startup just before GC is initialized.
  */
 void initSections() nothrow @nogc
 {
-    _isRuntimeInitialized = true;
 }
 
 /***
@@ -112,7 +107,6 @@ void initSections() nothrow @nogc
  */
 void finiSections() nothrow @nogc
 {
-    _isRuntimeInitialized = false;
 }
 
 alias ScanDG = void delegate(void* pbeg, void* pend) nothrow;
@@ -372,7 +366,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         }
 
         // don't initialize modules before rt_init was called
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             registerGCRanges(pdso);
             // rt_loadLibrary will run tls ctors, so do this only for dlopen
@@ -387,7 +381,7 @@ extern(C) void _d_dso_registry(CompilerDSOData* data)
         *data._slot = null;
 
         // don't finalizes modules after rt_term was called (see Bugzilla 11378)
-        if (_isRuntimeInitialized)
+        if (isRuntimeInitialized())
         {
             // rt_unloadLibrary already ran tls dtors, so do this only for dlclose
             immutable runTlsDtors = !_rtLoading;
diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d
index 5903d9cd754b1bf8dddd20ec7355ef5143a21a95..26c16d3af0a400aa1d13f24b1c208b0ba30df1cc 100644
--- a/libphobos/libdruntime/rt/aaA.d
+++ b/libphobos/libdruntime/rt/aaA.d
@@ -688,7 +688,7 @@ extern (C) inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t
     {
         if (!b.filled)
             continue;
-        pval[0 .. valsz] = b.entry[off .. valsz + off];
+        pval[0 .. valsz] = cast(void[]) b.entry[off .. valsz + off];
         pval += valsz;
     }
     // postblit is done in object.values
@@ -710,7 +710,7 @@ extern (C) inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo
     {
         if (!b.filled)
             continue;
-        pkey[0 .. keysz] = b.entry[0 .. keysz];
+        pkey[0 .. keysz] = cast(void[]) b.entry[0 .. keysz];
         pkey += keysz;
     }
     // postblit is done in object.keys
diff --git a/libphobos/libdruntime/rt/dmain2.d b/libphobos/libdruntime/rt/dmain2.d
index 5ac053cef152dbe90f027c6e355ef528d84921f2..052b859fd4905a746a603c74d04966af910fe1ff 100644
--- a/libphobos/libdruntime/rt/dmain2.d
+++ b/libphobos/libdruntime/rt/dmain2.d
@@ -102,7 +102,7 @@ alias void delegate(Throwable) ExceptionHandler;
 /**
  * Keep track of how often rt_init/rt_term were called.
  */
-shared size_t _initCount;
+private shared size_t _initCount;
 
 /**********************************************
  * Initialize druntime.
@@ -177,6 +177,13 @@ extern (C) int rt_term()
     return 0;
 }
 
+/**
+ * Indicates whether druntime has been or is being initialized.
+ */
+bool isRuntimeInitialized() @nogc nothrow {
+    return atomicLoad!(MemoryOrder.raw)(_initCount) != 0;
+}
+
 /**********************************************
  * Trace handler
  */
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 4a071f3d81bb0acdfcd4c9a8dafdea36ae849047..676f88d5ae403e10c6ba715541daba6e6c8cb186 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -129,7 +129,7 @@ extern (C) Object _d_newclass(const ClassInfo ci) @weak
     }
 
     // initialize it
-    p[0 .. init.length] = init[];
+    p[0 .. init.length] = cast(void[]) init[];
 
     debug(PRINTF) printf("initialization done\n");
     return cast(Object) p;
@@ -1294,7 +1294,7 @@ extern (C) void rt_finalize2(void* p, bool det = true, bool resetMemory = true)
         if (resetMemory)
         {
             auto w = (*pc).initializer;
-            p[0 .. w.length] = w[];
+            p[0 .. w.length] = cast(void[]) w[];
         }
     }
     catch (Exception e)
diff --git a/libphobos/libdruntime/rt/sections.d b/libphobos/libdruntime/rt/sections.d
index 6a15552034042f160a7377557c64612419ae95f0..a7b75d4ba81e793c4ecafa916373e09f758b496b 100644
--- a/libphobos/libdruntime/rt/sections.d
+++ b/libphobos/libdruntime/rt/sections.d
@@ -57,7 +57,7 @@ else version (Darwin)
 else version (CRuntime_Microsoft)
     public import rt.sections_win64;
 else version (CRuntime_Bionic)
-    public import rt.sections_android;
+    public import rt.sections_elf_shared;
 else version (CRuntime_UClibc)
     public import rt.sections_elf_shared;
 else
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index a431ca1e43e67c094b91b2d547ebc75caf5dfdca..46e244379e16ce05a04989b3db105f90a7fee868 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@
-de1dea109f40fe4a551578369c474e48845daec1
+0c28620c301c9ae3136b1e1e5af55c290dbc7aae
 
 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/Makefile.am b/libphobos/src/Makefile.am
index d45d116c691f7d98e4694c325eb29f87f37f2f4e..a8a5ed3a357ddef17f9642af4f244051fbcd0e6e 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -138,18 +138,18 @@ PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
 	std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
 	std/internal/memory.d std/internal/scopebuffer.d \
 	std/internal/test/dummyrange.d std/internal/test/range.d \
-	std/internal/test/uda.d std/internal/unicode_comp.d \
-	std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
-	std/internal/unicode_norm.d std/internal/unicode_tables.d \
-	std/internal/windows/advapi32.d std/json.d std/logger/core.d \
-	std/logger/filelogger.d std/logger/multilogger.d \
-	std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
-	std/math/constants.d std/math/exponential.d std/math/hardware.d \
-	std/math/operations.d std/math/package.d std/math/remainder.d \
-	std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
-	std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \
-	std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \
-	std/parallelism.d std/path.d std/process.d std/random.d \
+	std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \
+	std/internal/unicode_comp.d std/internal/unicode_decomp.d \
+	std/internal/unicode_grapheme.d std/internal/unicode_norm.d \
+	std/internal/unicode_tables.d std/internal/windows/advapi32.d \
+	std/json.d std/logger/core.d std/logger/filelogger.d \
+	std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \
+	std/math/algebraic.d std/math/constants.d std/math/exponential.d \
+	std/math/hardware.d std/math/operations.d std/math/package.d \
+	std/math/remainder.d std/math/rounding.d std/math/traits.d \
+	std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \
+	std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \
+	std/package.d std/parallelism.d std/path.d std/process.d std/random.d \
 	std/range/interfaces.d std/range/package.d std/range/primitives.d \
 	std/regex/internal/backtracking.d std/regex/internal/generator.d \
 	std/regex/internal/ir.d std/regex/internal/kickstart.d \
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index cc3358b437e15d237c6571661816704bd1399aae..52f2d1a2e3b8f49c12cc66a6f3ea71056845de6a 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -237,6 +237,7 @@ am__dirstamp = $(am__leading_dot)dirstamp
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/scopebuffer.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/dummyrange.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/range.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/sumtype_example_overloads.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/uda.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_comp.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_decomp.lo \
@@ -599,18 +600,18 @@ libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/memory.d std/internal/scopebuffer.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/dummyrange.d std/internal/test/range.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/uda.d std/internal/unicode_comp.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_decomp.d std/internal/unicode_grapheme.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_norm.d std/internal/unicode_tables.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/windows/advapi32.d std/json.d std/logger/core.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/logger/filelogger.d std/logger/multilogger.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/logger/nulllogger.d std/logger/package.d std/math/algebraic.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/constants.d std/math/exponential.d std/math/hardware.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/operations.d std/math/package.d std/math/remainder.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/rounding.d std/math/traits.d std/math/trigonometry.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/mathspecial.d std/meta.d std/mmfile.d std/net/curl.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/net/isemail.d std/numeric.d std/outbuffer.d std/package.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/parallelism.d std/path.d std/process.d std/random.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/test/sumtype_example_overloads.d std/internal/test/uda.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_comp.d std/internal/unicode_decomp.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_grapheme.d std/internal/unicode_norm.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/unicode_tables.d std/internal/windows/advapi32.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/json.d std/logger/core.d std/logger/filelogger.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/logger/multilogger.d std/logger/nulllogger.d std/logger/package.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/algebraic.d std/math/constants.d std/math/exponential.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/hardware.d std/math/operations.d std/math/package.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/remainder.d std/math/rounding.d std/math/traits.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/math/trigonometry.d std/mathspecial.d std/meta.d std/mmfile.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/net/curl.d std/net/isemail.d std/numeric.d std/outbuffer.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/package.d std/parallelism.d std/path.d std/process.d std/random.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/range/interfaces.d std/range/package.d std/range/primitives.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/regex/internal/backtracking.d std/regex/internal/generator.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/regex/internal/ir.d std/regex/internal/kickstart.d \
@@ -868,6 +869,8 @@ std/internal/test/$(am__dirstamp):
 	@: > std/internal/test/$(am__dirstamp)
 std/internal/test/dummyrange.lo: std/internal/test/$(am__dirstamp)
 std/internal/test/range.lo: std/internal/test/$(am__dirstamp)
+std/internal/test/sumtype_example_overloads.lo:  \
+	std/internal/test/$(am__dirstamp)
 std/internal/test/uda.lo: std/internal/test/$(am__dirstamp)
 std/internal/unicode_comp.lo: std/internal/$(am__dirstamp)
 std/internal/unicode_decomp.lo: std/internal/$(am__dirstamp)
diff --git a/libphobos/src/std/format/spec.d b/libphobos/src/std/format/spec.d
index b129686f8a3aadc2d7f47e6190902b2e33ea3e17..e5564c99d8fce9f0a765783ad043fb89ee91a1b3 100644
--- a/libphobos/src/std/format/spec.d
+++ b/libphobos/src/std/format/spec.d
@@ -681,7 +681,7 @@ if (is(Unqual!Char == Char))
     auto fmt = "Number: %6.4e\nString: %s";
     auto f = FormatSpec!char(fmt);
 
-    assert(f.writeUpToNextSpec(a) == true);
+    assert(f.writeUpToNextSpec(a));
 
     assert(a.data == "Number: ");
     assert(f.trailing == "\nString: %s");
@@ -689,13 +689,13 @@ if (is(Unqual!Char == Char))
     assert(f.width == 6);
     assert(f.precision == 4);
 
-    assert(f.writeUpToNextSpec(a) == true);
+    assert(f.writeUpToNextSpec(a));
 
     assert(a.data == "Number: \nString: ");
     assert(f.trailing == "");
     assert(f.spec == 's');
 
-    assert(f.writeUpToNextSpec(a) == false);
+    assert(!f.writeUpToNextSpec(a));
 
     assert(a.data == "Number: \nString: ");
 }
diff --git a/libphobos/src/std/internal/test/sumtype_example_overloads.d b/libphobos/src/std/internal/test/sumtype_example_overloads.d
new file mode 100644
index 0000000000000000000000000000000000000000..235659dc8b7d8e66767d57b464c63be96288ff93
--- /dev/null
+++ b/libphobos/src/std/internal/test/sumtype_example_overloads.d
@@ -0,0 +1,17 @@
+/++
+For testing only.
+
+Overload set used in std.sumtype example. Needs its own internal module so that
+it can be available for `make publictests` without polluting the public API.
++/
+module std.internal.test.sumtype_example_overloads;
+
+import std.sumtype;
+
+@safe
+{
+    string handle(int) { return "got an int"; }
+    string handle(string) { return "got a string"; }
+    string handle(double) { return "got a double"; }
+    alias handle = match!handle;
+}
diff --git a/libphobos/src/std/math/exponential.d b/libphobos/src/std/math/exponential.d
index 5e90f0de897db18bb2047ecc4ae7b0c3816f895f..8fcd88f4c6867969520df67fabe0cd6f244209d3 100644
--- a/libphobos/src/std/math/exponential.d
+++ b/libphobos/src/std/math/exponential.d
@@ -256,7 +256,7 @@ if (isFloatingPoint!(F) && isIntegral!(G))
  *     If x is 0 and n is negative, the result is the same as the result of a
  *     division by zero.
  */
-typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @trusted pure nothrow
+typeof(Unqual!(F).init * Unqual!(G).init) pow(F, G)(F x, G n) @nogc @safe pure nothrow
 if (isIntegral!(F) && isIntegral!(G))
 {
     import std.traits : isSigned;
diff --git a/libphobos/src/std/net/curl.d b/libphobos/src/std/net/curl.d
index 3f823013e650e891e243edf02c41ad72f055a5fe..07905fc7003838eef44782b100bd4232644d9569 100644
--- a/libphobos/src/std/net/curl.d
+++ b/libphobos/src/std/net/curl.d
@@ -1063,7 +1063,7 @@ private auto _basicHTTP(T)(const(char)[] url, const(void)[] sendData, HTTP clien
         {
             size_t minLen = min(buf.length, remainingData.length);
             if (minLen == 0) return 0;
-            buf[0 .. minLen] = remainingData[0 .. minLen];
+            buf[0 .. minLen] = cast(void[]) remainingData[0 .. minLen];
             remainingData = remainingData[minLen..$];
             return minLen;
         };
@@ -1202,7 +1202,7 @@ private auto _basicFTP(T)(const(char)[] url, const(void)[] sendData, FTP client)
         {
             size_t minLen = min(buf.length, sendData.length);
             if (minLen == 0) return 0;
-            buf[0 .. minLen] = sendData[0 .. minLen];
+            buf[0 .. minLen] = cast(void[]) sendData[0 .. minLen];
             sendData = sendData[minLen..$];
             return minLen;
         };
diff --git a/libphobos/src/std/range/package.d b/libphobos/src/std/range/package.d
index 995bf1e6c9b5acb04c3df282ec6e2fc8a46e807d..b6fddf76559bf250ec0a748cfdc7faae165473c2 100644
--- a/libphobos/src/std/range/package.d
+++ b/libphobos/src/std/range/package.d
@@ -13539,10 +13539,10 @@ if (isInputRange!R && isIntegral!(ElementType!R))
     {
         size_t bitsNum = IntegralType.sizeof * 8;
 
-        auto first = cast(IntegralType)(1);
+        auto first = IntegralType(1);
 
         // 2 ^ (bitsNum - 1)
-        auto second = cast(IntegralType)(cast(IntegralType)(1) << (bitsNum - 2));
+        auto second = cast(IntegralType)(IntegralType(1) << (bitsNum - 2));
 
         IntegralType[] a = [first, second];
         auto bw = Bitwise!(IntegralType[])(a);
@@ -13571,7 +13571,7 @@ if (isInputRange!R && isIntegral!(ElementType!R))
 
         auto bw2 = bw[0 .. $ - 5];
         auto bw3 = bw2[];
-        assert(bw2.length == (bw.length - 5));
+        assert(bw2.length == bw.length - 5);
         assert(bw2.length == bw3.length);
         bw2.popFront();
         assert(bw2.length != bw3.length);
diff --git a/libphobos/src/std/string.d b/libphobos/src/std/string.d
index b350d6b7134c69da6b75eadf201ebd58a8b9baeb..21e1ca356f8605f3fb01ee0b28ef952fb58b4d0d 100644
--- a/libphobos/src/std/string.d
+++ b/libphobos/src/std/string.d
@@ -6331,42 +6331,42 @@ if (isSomeString!S ||
     assertCTFEable!(
     {
     // Test the isNumeric(in string) function
-    assert(isNumeric("1") == true );
-    assert(isNumeric("1.0") == true );
-    assert(isNumeric("1e-1") == true );
-    assert(isNumeric("12345xxxx890") == false );
-    assert(isNumeric("567L") == true );
-    assert(isNumeric("23UL") == true );
-    assert(isNumeric("-123..56f") == false );
-    assert(isNumeric("12.3.5.6") == false );
-    assert(isNumeric(" 12.356") == false );
-    assert(isNumeric("123 5.6") == false );
-    assert(isNumeric("1233E-1+1.0e-1i") == true );
-
-    assert(isNumeric("123.00E-5+1234.45E-12Li") == true);
-    assert(isNumeric("123.00e-5+1234.45E-12iL") == false);
-    assert(isNumeric("123.00e-5+1234.45e-12uL") == false);
-    assert(isNumeric("123.00E-5+1234.45e-12lu") == false);
-
-    assert(isNumeric("123fi") == true);
-    assert(isNumeric("123li") == true);
-    assert(isNumeric("--123L") == false);
-    assert(isNumeric("+123.5UL") == false);
-    assert(isNumeric("123f") == true);
-    assert(isNumeric("123.u") == false);
+    assert(isNumeric("1"));
+    assert(isNumeric("1.0"));
+    assert(isNumeric("1e-1"));
+    assert(!isNumeric("12345xxxx890"));
+    assert(isNumeric("567L"));
+    assert(isNumeric("23UL"));
+    assert(!isNumeric("-123..56f"));
+    assert(!isNumeric("12.3.5.6"));
+    assert(!isNumeric(" 12.356"));
+    assert(!isNumeric("123 5.6"));
+    assert(isNumeric("1233E-1+1.0e-1i"));
+
+    assert(isNumeric("123.00E-5+1234.45E-12Li"));
+    assert(!isNumeric("123.00e-5+1234.45E-12iL"));
+    assert(!isNumeric("123.00e-5+1234.45e-12uL"));
+    assert(!isNumeric("123.00E-5+1234.45e-12lu"));
+
+    assert(isNumeric("123fi"));
+    assert(isNumeric("123li"));
+    assert(!isNumeric("--123L"));
+    assert(!isNumeric("+123.5UL"));
+    assert(isNumeric("123f"));
+    assert(!isNumeric("123.u"));
 
   // @@@BUG@@ to!string(float) is not CTFEable.
   // Related: formatValue(T) if (is(FloatingPointTypeOf!T))
   if (!__ctfe)
   {
-    assert(isNumeric(to!string(real.nan)) == true);
-    assert(isNumeric(to!string(-real.infinity)) == true);
+    assert(isNumeric(to!string(real.nan)));
+    assert(isNumeric(to!string(-real.infinity)));
   }
 
     string s = "$250.99-";
-    assert(isNumeric(s[1 .. s.length - 2]) == true);
-    assert(isNumeric(s) == false);
-    assert(isNumeric(s[0 .. s.length - 1]) == false);
+    assert(isNumeric(s[1 .. $ - 2]));
+    assert(!isNumeric(s));
+    assert(!isNumeric(s[0 .. $ - 1]));
     });
 
     assert(!isNumeric("-"));
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 80ce73d6a75fa4ce880f554757f2099154f98a4c..69c2a49dd7faed5b62c00e69ccb9eb6beaf78d62 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -11,6 +11,15 @@ include:
 * No dependency on runtime type information (`TypeInfo`).
 * Compatibility with BetterC.
 
+$(H3 List of examples)
+
+* [Basic usage](#basic-usage)
+* [Matching with an overload set](#matching-with-an-overload-set)
+* [Recursive SumTypes](#recursive-sumtypes)
+* [Memory corruption](#memory-corruption) (why assignment can be `@system`)
+* [Avoiding unintentional matches](#avoiding-unintentional-matches)
+* [Multiple dispatch](#multiple-dispatch)
+
 License: Boost License 1.0
 Authors: Paul Backus
 Source: $(PHOBOSSRC std/sumtype.d)
@@ -77,52 +86,38 @@ version (D_BetterC) {} else
     assert(!isFahrenheit(t3));
 }
 
-/** $(DIVID introspection-based-matching, $(H3 Introspection-based matching))
+/** $(DIVID matching-with-an-overload-set, $(H3 Matching with an overload set))
+ *
+ * Instead of writing `match` handlers inline as lambdas, you can write them as
+ * overloads of a function. An `alias` can be used to create an additional
+ * overload for the `SumType` itself.
+ *
+ * For example, with this overload set:
  *
- * In the `length` and `horiz` functions below, the handlers for `match` do not
- * specify the types of their arguments. Instead, matching is done based on how
- * the argument is used in the body of the handler: any type with `x` and `y`
- * properties will be matched by the `rect` handlers, and any type with `r` and
- * `theta` properties will be matched by the `polar` handlers.
+ * ---
+ * string handle(int n) { return "got an int"; }
+ * string handle(string s) { return "got a string"; }
+ * string handle(double d) { return "got a double"; }
+ * alias handle = match!handle;
+ * ---
+ *
+ * Usage would look like this:
  */
 version (D_BetterC) {} else
 @safe unittest
 {
-    import std.math.operations : isClose;
-    import std.math.trigonometry : cos;
-    import std.math.constants : PI;
-    import std.math.algebraic : sqrt;
-
-    struct Rectangular { double x, y; }
-    struct Polar { double r, theta; }
-    alias Vector = SumType!(Rectangular, Polar);
-
-    double length(Vector v)
-    {
-        return v.match!(
-            rect => sqrt(rect.x^^2 + rect.y^^2),
-            polar => polar.r
-        );
-    }
-
-    double horiz(Vector v)
-    {
-        return v.match!(
-            rect => rect.x,
-            polar => polar.r * cos(polar.theta)
-        );
-    }
+    alias ExampleSumType = SumType!(int, string, double);
 
-    Vector u = Rectangular(1, 1);
-    Vector v = Polar(1, PI/4);
+    ExampleSumType a = 123;
+    ExampleSumType b = "hello";
+    ExampleSumType c = 3.14;
 
-    assert(length(u).isClose(sqrt(2.0)));
-    assert(length(v).isClose(1));
-    assert(horiz(u).isClose(1));
-    assert(horiz(v).isClose(sqrt(0.5)));
+    assert(a.handle == "got an int");
+    assert(b.handle == "got a string");
+    assert(c.handle == "got a double");
 }
 
-/** $(DIVID arithmetic-expression-evaluator, $(H3 Arithmetic expression evaluator))
+/** $(DIVID recursive-sumtypes, $(H3 Recursive SumTypes))
  *
  * This example makes use of the special placeholder type `This` to define a
  * [recursive data type](https://en.wikipedia.org/wiki/Recursive_data_type): an
@@ -227,6 +222,10 @@ version (D_BetterC) {} else
     assert(pprint(*myExpr) == "(a + (2 * b))");
 }
 
+// For the "Matching with an overload set" example above
+// Needs public import to work with `make publictests`
+version (unittest) public import std.internal.test.sumtype_example_overloads;
+
 import std.format.spec : FormatSpec, singleSpec;
 import std.meta : AliasSeq, Filter, IndexOf = staticIndexOf, Map = staticMap;
 import std.meta : NoDuplicates;
@@ -266,8 +265,7 @@ private enum isInout(T) = is(T == inout);
  *
  * The special type `This` can be used as a placeholder to create
  * self-referential types, just like with `Algebraic`. See the
- * ["Arithmetic expression evaluator" example](#arithmetic-expression-evaluator) for
- * usage.
+ * ["Recursive SumTypes" example](#recursive-sumtypes) for usage.
  *
  * A `SumType` is initialized by default to hold the `.init` value of its
  * first member type, just like a regular union. The version identifier
@@ -1619,9 +1617,9 @@ enum bool isSumType(T) = is(T : SumType!Args, Args...);
  * overloads are considered as potential matches.
  *
  * Templated handlers are also accepted, and will match any type for which they
- * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti). See
- * ["Introspection-based matching"](#introspection-based-matching) for an
- * example of templated handler usage.
+ * can be [implicitly instantiated](https://dlang.org/glossary.html#ifti).
+ * (Remember that a $(DDSUBLINK spec/expression,function_literals, function literal)
+ * without an explicit argument type is considered a template.)
  *
  * If multiple [SumType]s are passed to match, their values are passed to the
  * handlers as separate arguments, and matching is done for each possible
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index c0cd3863b329ecdfc0c52b100f00ef086126b786..f0d5d4d268bec6ad7b916d14b4e26a97ea87ac3d 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -2528,8 +2528,8 @@ size_t encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(
     encode(buf, '\u0000'); assert(buf[0] == '\u0000');
     encode(buf, '\uD7FF'); assert(buf[0] == '\uD7FF');
     encode(buf, '\uE000'); assert(buf[0] == '\uE000');
-    encode(buf, 0xFFFE ); assert(buf[0] == 0xFFFE);
-    encode(buf, 0xFFFF ); assert(buf[0] == 0xFFFF);
+    encode(buf, 0xFFFE); assert(buf[0] == 0xFFFE);
+    encode(buf, 0xFFFF); assert(buf[0] == 0xFFFF);
     encode(buf, '\U0010FFFF'); assert(buf[0] == '\U0010FFFF');
 
     assertThrown!UTFException(encode(buf, cast(dchar) 0xD800));
@@ -2749,8 +2749,8 @@ void encode(UseReplacementDchar useReplacementDchar = No.useReplacementDchar)(
     encode(buf, '\u0000'); assert(buf[0] == '\u0000');
     encode(buf, '\uD7FF'); assert(buf[1] == '\uD7FF');
     encode(buf, '\uE000'); assert(buf[2] == '\uE000');
-    encode(buf, 0xFFFE ); assert(buf[3] == 0xFFFE);
-    encode(buf, 0xFFFF ); assert(buf[4] == 0xFFFF);
+    encode(buf, 0xFFFE); assert(buf[3] == 0xFFFE);
+    encode(buf, 0xFFFF); assert(buf[4] == 0xFFFF);
     encode(buf, '\U0010FFFF'); assert(buf[5] == '\U0010FFFF');
 
     assertThrown!UTFException(encode(buf, cast(dchar) 0xD800));