diff mbox series

[committed] d: Merge upstream dmd, druntime 643b1261bb, phobos 1c98326e7

Message ID 20231102135719.33814-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd, druntime 643b1261bb, phobos 1c98326e7 | expand

Commit Message

Iain Buclaw Nov. 2, 2023, 1:57 p.m. UTC
Hi,

This patch merges the D front-end and runtime library with upstream dmd
643b1261bb, and standard library with phobos 1c98326e7.

Synchronizing with the v2.106.0-beta.1 release.

This is being done a little earlier than usual as there's a lot of
internal moving code around within upstream at the moment to reduce both
the extern(C++) surface area, and cyclic dependencies between all D
modules that implement the compiler. So it is done now to keep the diff
below the 400kb threshold enforced on the mailing list.

D front-end changes:

    - Suggested preview switches now give gdc flags (PR109681).
    - `new S[10]' is now lowered to `_d_newarrayT!S(10)'.

D runtime changes:

    - Runtime compiler library functions `_d_newarrayU', `_d_newarrayT',
      `_d_newarrayiT' have been converted to templates.

Phobos changes:

    - Add new `std.traits.Unshared' template.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 643b1261bb.
	* d-attribs.cc (build_attributes): Update for new front-end interface.
	* d-lang.cc (d_post_options): Likewise.
	* decl.cc (layout_class_initializer): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 643b1261bb.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES_FREEBSD): Add
	core/sys/freebsd/ifaddrs.d, core/sys/freebsd/net/if_dl.d,
	core/sys/freebsd/sys/socket.d, core/sys/freebsd/sys/types.d.
	(DRUNTIME_DSOURCES_LINUX): Add core/sys/linux/linux/if_arp.d,
	core/sys/linux/linux/if_packet.d.
	* libdruntime/Makefile.in: Regenerate.
	* src/MERGE: Merge upstream phobos 1c98326e7.
---
 gcc/d/d-attribs.cc                            |   2 +-
 gcc/d/d-lang.cc                               |   1 -
 gcc/d/decl.cc                                 |   2 +-
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/aggregate.d                         | 184 +++---
 gcc/d/dmd/attrib.d                            |   6 +-
 gcc/d/dmd/cond.d                              |   1 +
 gcc/d/dmd/constfold.d                         |  24 +-
 gcc/d/dmd/cparse.d                            |   1 +
 gcc/d/dmd/dcast.d                             |   3 +-
 gcc/d/dmd/dclass.d                            |   2 +-
 gcc/d/dmd/declaration.d                       |  50 +-
 gcc/d/dmd/dinterpret.d                        |   3 +-
 gcc/d/dmd/dmangle.d                           |   1 +
 gcc/d/dmd/doc.d                               |   2 +-
 gcc/d/dmd/dstruct.d                           |   2 +-
 gcc/d/dmd/dsymbol.d                           |  74 ++-
 gcc/d/dmd/dsymbolsem.d                        |  11 +-
 gcc/d/dmd/dtemplate.d                         |  15 +-
 gcc/d/dmd/expression.d                        | 546 +-----------------
 gcc/d/dmd/expression.h                        |  20 +-
 gcc/d/dmd/expressionsem.d                     | 511 +++++++++++++++-
 gcc/d/dmd/func.d                              |   1 +
 gcc/d/dmd/globals.h                           |   1 -
 gcc/d/dmd/gluelayer.d                         |   5 -
 gcc/d/dmd/initsem.d                           |   1 +
 gcc/d/dmd/lexer.d                             |   1 -
 gcc/d/dmd/mtype.d                             |  25 +-
 gcc/d/dmd/mtype.h                             |   2 +-
 gcc/d/dmd/optimize.d                          |   1 +
 gcc/d/dmd/parse.d                             |  22 +-
 gcc/d/dmd/semantic3.d                         |   7 +-
 gcc/d/dmd/statementsem.d                      |   5 +-
 gcc/d/dmd/staticcond.d                        |   1 +
 gcc/d/dmd/templateparamsem.d                  |   1 +
 gcc/d/dmd/traits.d                            |   1 +
 gcc/d/dmd/typesem.d                           |   2 +
 gcc/d/dmd/typinf.d                            |  30 +-
 gcc/d/dmd/typinf.h                            |  22 +
 gcc/testsuite/gdc.test/compilable/dbitfield.d |  13 +
 .../gdc.test/compilable/deprecate14283.d      |   8 +-
 .../gdc.test/compilable/named_arguments.d     |  18 +-
 gcc/testsuite/gdc.test/compilable/test20039.d |   2 +-
 .../gdc.test/fail_compilation/b23686.d        |  42 ++
 .../gdc.test/fail_compilation/diag4596.d      |   4 +-
 .../gdc.test/fail_compilation/fail13116.d     |   2 +-
 .../gdc.test/fail_compilation/fail24208.d     |  20 +
 .../gdc.test/fail_compilation/fail24212.d     |  30 +
 .../gdc.test/fail_compilation/fail24213.d     |  17 +
 .../gdc.test/fail_compilation/ice23865.d      |  32 +
 .../gdc.test/fail_compilation/ice24188.d      |  14 +
 .../fail_compilation/ice24188_a/ice24188_c.d  |   0
 .../gdc.test/fail_compilation/test18480.d     |   1 +
 .../gdc.test/fail_compilation/test24157.d     |  28 +
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/Makefile.am             |   7 +-
 libphobos/libdruntime/Makefile.in             |  34 +-
 .../libdruntime/core/sys/linux/linux/if_arp.d | 136 +++++
 .../core/sys/linux/linux/if_packet.d          | 315 ++++++++++
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/parallelism.d               |   4 +-
 libphobos/src/std/range/primitives.d          |  17 +-
 libphobos/src/std/traits.d                    |  41 ++
 63 files changed, 1594 insertions(+), 786 deletions(-)
 create mode 100644 gcc/d/dmd/typinf.h
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/b23686.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24208.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24212.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24213.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice23865.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice24188.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24157.d
 create mode 100644 libphobos/libdruntime/core/sys/linux/linux/if_arp.d
 create mode 100644 libphobos/libdruntime/core/sys/linux/linux/if_packet.d
diff mbox series

Patch

diff --git a/gcc/d/d-attribs.cc b/gcc/d/d-attribs.cc
index cc46220ddc2..c0dc0e24ded 100644
--- a/gcc/d/d-attribs.cc
+++ b/gcc/d/d-attribs.cc
@@ -351,7 +351,7 @@  build_attributes (Expressions *eattrs)
 
       /* Get the result of the attribute if it hasn't already been folded.  */
       if (attr->op == EXP::call)
-	attr = attr->ctfeInterpret ();
+	attr = ctfeInterpret (attr);
 
       if (attr->op != EXP::structLiteral)
 	{
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 902fd86b5ab..61fc1608b40 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -936,7 +936,6 @@  d_post_options (const char ** fn)
      fields with params.  */
   global.compileEnv.previewIn = global.params.previewIn;
   global.compileEnv.ddocOutput = global.params.ddoc.doOutput;
-  global.compileEnv.shortenedMethods = global.params.shortenedMethods;
 
   if (warn_return_type == -1)
     warn_return_type = 0;
diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index c80bb8aebd7..1a61a1c4498 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -2377,7 +2377,7 @@  layout_class_initializer (ClassDeclaration *cd)
   NewExp *ne = NewExp::create (cd->loc, NULL, cd->type, NULL);
   ne->type = cd->type;
 
-  Expression *e = ne->ctfeInterpret ();
+  Expression *e = ctfeInterpret (ne);
   gcc_assert (e->op == EXP::classReference);
 
   return build_class_instance (e->isClassReferenceExp ());
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 2a0baf09a4b..235db4b2ef1 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-e48bc0987dfec35bc76a3015ee3e85906ce86dfd
+643b1261bba0757d97efa3ff1f63e461271eb000
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index d9b48b531d7..d42ef951085 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -501,90 +501,6 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
         return !errors;
     }
 
-    /****************************
-     * Do byte or word alignment as necessary.
-     * Align sizes of 0, as we may not know array sizes yet.
-     * Params:
-     *   alignment = struct alignment that is in effect
-     *   memalignsize = natural alignment of field
-     *   poffset = pointer to offset to be aligned
-     */
-    extern (D) static void alignmember(structalign_t alignment, uint memalignsize, uint* poffset) pure nothrow @safe
-    {
-        //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, *poffset);
-        uint alignvalue;
-
-        if (alignment.isDefault())
-        {
-            // Alignment in Target::fieldalignsize must match what the
-            // corresponding C compiler's default alignment behavior is.
-            alignvalue = memalignsize;
-        }
-        else if (alignment.isPack())    // #pragma pack semantics
-        {
-            alignvalue = alignment.get();
-            if (memalignsize < alignvalue)
-                alignvalue = memalignsize;      // align to min(memalignsize, alignment)
-        }
-        else if (alignment.get() > 1)
-        {
-            // Align on alignment boundary, which must be a positive power of 2
-            alignvalue = alignment.get();
-        }
-        else
-            return;
-
-        assert(alignvalue > 0 && !(alignvalue & (alignvalue - 1)));
-        *poffset = (*poffset + alignvalue - 1) & ~(alignvalue - 1);
-    }
-
-    /****************************************
-     * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
-     * Params:
-     *    nextoffset    = location just past the end of the previous field in the aggregate.
-     *                    Updated to be just past the end of this field to be placed, i.e. the future nextoffset
-     *    memsize       = size of field
-     *    memalignsize  = natural alignment of field
-     *    alignment     = alignment in effect for this field
-     *    paggsize      = size of aggregate (updated)
-     *    paggalignsize = alignment of aggregate (updated)
-     *    isunion       = the aggregate is a union
-     * Returns:
-     *    aligned offset to place field at
-     *
-     */
-    extern (D) static uint placeField(uint* nextoffset, uint memsize, uint memalignsize,
-        structalign_t alignment, uint* paggsize, uint* paggalignsize, bool isunion)
-    {
-        uint ofs = *nextoffset;
-
-        const uint actualAlignment =
-            alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
-                        ? memalignsize : alignment.get();
-
-        // Ensure no overflow
-        bool overflow;
-        const sz = addu(memsize, actualAlignment, overflow);
-        addu(ofs, sz, overflow);
-        if (overflow) assert(0);
-
-        // Skip no-op for noreturn without custom aligment
-        if (memalignsize != 0 || !alignment.isDefault())
-            alignmember(alignment, memalignsize, &ofs);
-
-        uint memoffset = ofs;
-        ofs += memsize;
-        if (ofs > *paggsize)
-            *paggsize = ofs;
-        if (!isunion)
-            *nextoffset = ofs;
-
-        if (*paggalignsize < actualAlignment)
-            *paggalignsize = actualAlignment;
-
-        return memoffset;
-    }
-
     override final Type getType()
     {
         /* Apply storage classes to forward references. (Issue 22254)
@@ -844,3 +760,103 @@  int apply(Dsymbol symbol, int function(Dsymbol, void*) fp, void* ctx)
 
     return fp(symbol, ctx);
 }
+
+/****************************
+ * Do byte or word alignment as necessary.
+ * Align sizes of 0, as we may not know array sizes yet.
+ * Params:
+ *   alignment = struct alignment that is in effect
+ *   memalignsize = natural alignment of field
+ *   offset = offset to be aligned
+ * Returns:
+ *   aligned offset
+ */
+public uint alignmember(structalign_t alignment, uint memalignsize, uint offset) pure nothrow @safe
+{
+    //debug printf("alignment = %u %d, size = %u, offset = %u\n", alignment.get(), alignment.isPack(), memalignsize, offset);
+    uint alignvalue;
+
+    if (alignment.isDefault())
+    {
+        // Alignment in Target::fieldalignsize must match what the
+        // corresponding C compiler's default alignment behavior is.
+        alignvalue = memalignsize;
+    }
+    else if (alignment.isPack())    // #pragma pack semantics
+    {
+        alignvalue = alignment.get();
+        if (memalignsize < alignvalue)
+            alignvalue = memalignsize;      // align to min(memalignsize, alignment)
+    }
+    else if (alignment.get() > 1)
+    {
+        // Align on alignment boundary, which must be a positive power of 2
+        alignvalue = alignment.get();
+    }
+    else
+        return offset;
+
+    assert(alignvalue && !(alignvalue & (alignvalue - 1))); // non-zero and power of 2
+    return (offset + alignvalue - 1) & ~(alignvalue - 1);
+}
+
+/****************************************
+ * Place a field (mem) into an aggregate (agg), which can be a struct, union or class
+ * Params:
+ *    nextoffset    = location just past the end of the previous field in the aggregate.
+ *                    Updated to be just past the end of this field to be placed, i.e. the future nextoffset
+ *    memsize       = size of field
+ *    memalignsize  = natural alignment of field
+ *    alignment     = alignment in effect for this field
+ *    aggsize       = size of aggregate (updated)
+ *    aggalignsize  = alignment of aggregate (updated)
+ *    isunion       = the aggregate is a union
+ * Returns:
+ *    aligned offset to place field at
+ *
+ */
+public uint placeField(ref uint nextoffset, uint memsize, uint memalignsize,
+    structalign_t alignment, ref uint aggsize, ref uint aggalignsize, bool isunion) @safe pure nothrow
+{
+    static if (0)
+    {
+        printf("placeField() nextoffset:   %u\n", nextoffset);
+        printf(":            memsize:      %u\n", memsize);
+        printf(":            memalignsize: %u\n", memalignsize);
+        printf(":            alignment:    %u\n", alignment.get());
+        printf(":            aggsize:      %u\n", aggsize);
+        printf(":            aggalignsize: %u\n", aggalignsize);
+        printf(":            isunion:      %d\n", isunion);
+    }
+
+    uint ofs = nextoffset;
+
+    const uint actualAlignment =
+        alignment.isDefault() || alignment.isPack() && memalignsize < alignment.get()
+                    ? memalignsize : alignment.get();
+
+    // Ensure no overflow for (memsize + actualAlignment + ofs)
+    bool overflow;
+    const sz = addu(memsize, actualAlignment, overflow);
+    addu(ofs, sz, overflow);
+    if (overflow) assert(0);
+
+    // Skip no-op for noreturn without custom aligment
+    if (memalignsize != 0 || !alignment.isDefault())
+        ofs = alignmember(alignment, memalignsize, ofs);
+
+    uint memoffset = ofs;
+    ofs += memsize;
+    if (ofs > aggsize)
+        aggsize = ofs;
+    if (!isunion)
+    {
+        nextoffset = ofs;
+        //printf("     revised nextoffset:   %u\n", ofs);
+    }
+
+    if (aggalignsize < actualAlignment)
+        aggalignsize = actualAlignment;
+
+    return memoffset;
+}
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 7b5def1f765..49fc3082ba8 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -839,10 +839,10 @@  extern (C++) final class AnonDeclaration : AttribDeclaration
             /* Given the anon 'member's size and alignment,
              * go ahead and place it.
              */
-            anonoffset = AggregateDeclaration.placeField(
-                &fieldState.offset,
+            anonoffset = placeField(
+                fieldState.offset,
                 anonstructsize, anonalignsize, alignment,
-                &ad.structsize, &ad.alignsize,
+                ad.structsize, ad.alignsize,
                 isunion);
 
             // Add to the anon fields the base offset of this anonymous aggregate
diff --git a/gcc/d/dmd/cond.d b/gcc/d/dmd/cond.d
index 9fa8a25462f..a8d099433a2 100644
--- a/gcc/d/dmd/cond.d
+++ b/gcc/d/dmd/cond.d
@@ -18,6 +18,7 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
 import dmd.dcast;
+import dmd.dinterpret;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index ef408cb5b77..fc3fd3b2486 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -20,6 +20,7 @@  import core.stdc.stdio;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ctfeexpr;
+import dmd.dcast;
 import dmd.declaration;
 import dmd.dstruct;
 import dmd.errors;
@@ -48,29 +49,6 @@  private Expression expType(Type type, Expression e)
     return e;
 }
 
-/************************************
- * Returns:
- *    true if e is a constant
- */
-int isConst(Expression e) @safe
-{
-    //printf("Expression::isConst(): %s\n", e.toChars());
-    switch (e.op)
-    {
-    case EXP.int64:
-    case EXP.float64:
-    case EXP.complex80:
-        return 1;
-    case EXP.null_:
-        return 0;
-    case EXP.symbolOffset:
-        return 2;
-    default:
-        return 0;
-    }
-    assert(0);
-}
-
 /**********************************
  * Initialize a EXP.cantExpression Expression.
  * Params:
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 0b738cdc3d5..b8e80527ec7 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -328,6 +328,7 @@  final class CParser(AST) : Parser!AST
         case TOK._Atomic:
 
         case TOK.__attribute__:
+        case TOK.__declspec:
 
         Ldeclaration:
         {
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index e4d580513fe..f769473f591 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.dinterpret;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
@@ -232,7 +233,7 @@  Expression implicitCastTo(Expression e, Scope* sc, Type t)
  * Returns:
  *   The `MATCH` level between `e.type` and `t`.
  */
-MATCH implicitConvTo(Expression e, Type t)
+extern(C++) MATCH implicitConvTo(Expression e, Type t)
 {
     MATCH visit(Expression e)
     {
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 09a4f4ef3f2..bae942cbd97 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -613,7 +613,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
 
                 if (!b.sym.alignsize)
                     b.sym.alignsize = target.ptrsize;
-                alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, &offset);
+                offset = alignmember(structalign_t(cast(ushort)b.sym.alignsize), b.sym.alignsize, offset);
                 assert(bi < vtblInterfaces.length);
 
                 BaseClass* bv = (*vtblInterfaces)[bi];
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index d634e7fe545..76a31f4caf7 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -818,6 +818,11 @@  extern (C++) final class AliasDeclaration : Declaration
                 return this._import && this.equals(s);
             }
 
+            // https://issues.dlang.org/show_bug.cgi?id=23865
+            // only insert if the symbol can be part of a set
+            const s1 = s.toAlias();
+            const isInsertCandidate = s1.isFuncDeclaration() || s1.isOverDeclaration() || s1.isTemplateDeclaration();
+
             /* When s is added in member scope by static if, mixin("code") or others,
              * aliassym is determined already. See the case in: test/compilable/test61.d
              */
@@ -832,7 +837,8 @@  extern (C++) final class AliasDeclaration : Declaration
                 fa.visibility = visibility;
                 fa.parent = parent;
                 aliassym = fa;
-                return aliassym.overloadInsert(s);
+                if (isInsertCandidate)
+                    return aliassym.overloadInsert(s);
             }
             if (auto td = sa.isTemplateDeclaration())
             {
@@ -840,7 +846,8 @@  extern (C++) final class AliasDeclaration : Declaration
                 od.visibility = visibility;
                 od.parent = parent;
                 aliassym = od;
-                return aliassym.overloadInsert(s);
+                if (isInsertCandidate)
+                    return aliassym.overloadInsert(s);
             }
             if (auto od = sa.isOverDeclaration())
             {
@@ -851,7 +858,8 @@  extern (C++) final class AliasDeclaration : Declaration
                     od.parent = parent;
                     aliassym = od;
                 }
-                return od.overloadInsert(s);
+                if (isInsertCandidate)
+                    return od.overloadInsert(s);
             }
             if (auto os = sa.isOverloadSet())
             {
@@ -877,8 +885,11 @@  extern (C++) final class AliasDeclaration : Declaration
                     os.parent = parent;
                     aliassym = os;
                 }
-                os.push(s);
-                return true;
+                if (isInsertCandidate)
+                {
+                    os.push(s);
+                    return true;
+                }
             }
             return false;
         }
@@ -1287,10 +1298,10 @@  extern (C++) class VarDeclaration : Declaration
         assert(sz != SIZE_INVALID && sz < uint.max);
         uint memsize = cast(uint)sz;                // size of member
         uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
-        offset = AggregateDeclaration.placeField(
-            &fieldState.offset,
+        offset = placeField(
+            fieldState.offset,
             memsize, memalignsize, alignment,
-            &ad.structsize, &ad.alignsize,
+            ad.structsize, ad.alignsize,
             isunion);
 
         //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
@@ -1813,11 +1824,7 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
             printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
             void print(const ref FieldState fieldState)
             {
-                printf("FieldState.offset      = %d bytes\n",   fieldState.offset);
-                printf("          .fieldOffset = %d bytes\n",   fieldState.fieldOffset);
-                printf("          .bitOffset   = %d bits\n",    fieldState.bitOffset);
-                printf("          .fieldSize   = %d bytes\n",   fieldState.fieldSize);
-                printf("          .inFlight    = %d\n",         fieldState.inFlight);
+                fieldState.print();
                 printf("          fieldWidth   = %d bits\n",    fieldWidth);
             }
             print(fieldState);
@@ -1866,11 +1873,11 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
                 alignsize = memsize; // not memalignsize
 
             uint dummy;
-            offset = AggregateDeclaration.placeField(
-                &fieldState.offset,
+            offset = placeField(
+                fieldState.offset,
                 memsize, alignsize, alignment,
-                &ad.structsize,
-                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? &dummy : &ad.alignsize,
+                ad.structsize,
+                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
                 isunion);
 
             fieldState.inFlight = true;
@@ -1989,7 +1996,14 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
             auto size = (pastField + 7) / 8;
             fieldState.fieldSize = size;
             //printf(" offset: %d, size: %d\n", offset, size);
-            ad.structsize = offset + size;
+            if (isunion)
+            {
+                const newstructsize = offset + size;
+                if (newstructsize > ad.structsize)
+                    ad.structsize = newstructsize;
+            }
+            else
+                ad.structsize = offset + size;
         }
         else
             fieldState.fieldSize = memsize;
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index cbd9740e089..90352e32bea 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -22,6 +22,7 @@  import dmd.attrib;
 import dmd.builtin;
 import dmd.constfold;
 import dmd.ctfeexpr;
+import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dstruct;
@@ -59,7 +60,7 @@  import dmd.visitor;
  * functions and may invoke a function that contains `ErrorStatement` in its body.
  * If that, the "CTFE failed because of previous errors" error is raised.
  */
-public Expression ctfeInterpret(Expression e)
+extern(C++) public Expression ctfeInterpret(Expression e)
 {
     switch (e.op)
     {
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 8fdb1ae835c..c58b5857482 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -139,6 +139,7 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.dclass;
 import dmd.declaration;
+import dmd.dinterpret;
 import dmd.dmodule;
 import dmd.dsymbol;
 import dmd.dtemplate;
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index b1a4c2fe504..5488d5a0008 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -438,7 +438,7 @@  void gendocfile(Module m, const char[] ddoctext, const char* datetime, ErrorSink
         if (!loc.filename)
             loc.filename = srcfilename.ptr;
 
-        size_t commentlen = strlen(cast(char*)m.comment);
+        size_t commentlen = m.comment ? strlen(cast(char*)m.comment) : 0;
         Dsymbols a;
         // https://issues.dlang.org/show_bug.cgi?id=9764
         // Don't push m in a, to prevent emphasize ddoc file name.
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 5171e1f3106..f77a263a894 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -357,7 +357,7 @@  extern (C++) class StructDeclaration : AggregateDeclaration
 
         sizeok = Sizeok.done;
 
-        //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), fields.length, structsize);
+        //printf("-StructDeclaration::finalizeSize() %s, fields.length = %d, structsize = %d\n", toChars(), cast(int)fields.length, cast(int)structsize);
 
         if (errors)
             return;
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 579a542de3c..914213c1e57 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -56,6 +56,8 @@  import dmd.staticassert;
 import dmd.tokens;
 import dmd.visitor;
 
+import dmd.common.outbuffer;
+
 /***************************************
  * Calls dg(Dsymbol *sym) for each Dsymbol.
  * If dg returns !=0, stops and returns that value else returns 0.
@@ -236,6 +238,15 @@  struct FieldState
     uint bitOffset;     /// bit offset for field
 
     bool inFlight;      /// bit field is in flight
+
+    void print() const
+    {
+        printf("FieldState.offset      = %d bytes\n",   offset);
+        printf("          .fieldOffset = %d bytes\n",   fieldOffset);
+        printf("          .bitOffset   = %d bits\n",    bitOffset);
+        printf("          .fieldSize   = %d bytes\n",   fieldSize);
+        printf("          .inFlight    = %d\n",         inFlight);
+    }
 }
 
 // 99.9% of Dsymbols don't have attributes (at least in druntime and Phobos),
@@ -684,7 +695,7 @@  extern (C++) class Dsymbol : ASTNode
     const(char)* toPrettyChars(bool QualifyTypes = false)
     {
         if (prettystring && !QualifyTypes)
-            return prettystring;
+            return prettystring; // value cached for speed
 
         //printf("Dsymbol::toPrettyChars() '%s'\n", toChars());
         if (!parent)
@@ -695,42 +706,22 @@  extern (C++) class Dsymbol : ASTNode
             return s;
         }
 
-        // Computer number of components
-        size_t complength = 0;
-        for (Dsymbol p = this; p; p = p.parent)
-            ++complength;
-
-        // Allocate temporary array comp[]
-        alias T = const(char)[];
-        auto compptr = cast(T*)Mem.check(malloc(complength * T.sizeof));
-        auto comp = compptr[0 .. complength];
+        OutBuffer buf;
 
-        // Fill in comp[] and compute length of final result
-        size_t length = 0;
-        int i;
-        for (Dsymbol p = this; p; p = p.parent)
+        void addQualifiers(Dsymbol p)
         {
+            if (p.parent)
+            {
+                addQualifiers(p.parent);
+                buf.writeByte('.');
+            }
             const s = QualifyTypes ? p.toPrettyCharsHelper() : p.toChars();
-            const len = strlen(s);
-            comp[i] = s[0 .. len];
-            ++i;
-            length += len + 1;
+            buf.writestring(s);
         }
 
-        auto s = cast(char*)mem.xmalloc_noscan(length);
-        auto q = s + length - 1;
-        *q = 0;
-        foreach (j; 0 .. complength)
-        {
-            const t = comp[j].ptr;
-            const len = comp[j].length;
-            q -= len;
-            memcpy(q, t, len);
-            if (q == s)
-                break;
-            *--q = '.';
-        }
-        free(comp.ptr);
+        addQualifiers(this);
+        auto s = buf.extractSlice(true).ptr;
+
         if (!QualifyTypes)
             prettystring = s;
         return s;
@@ -1734,8 +1725,8 @@  public:
                 Parameters* p = new Parameter(STC.in_, Type.tchar.constOf().arrayOf(), null, null);
                 parameters.push(p);
                 Type tret = null;
-                tfgetmembers = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
-                tfgetmembers = cast(TypeFunction)tfgetmembers.dsymbolSemantic(Loc.initial, &sc);
+                TypeFunction tf = new TypeFunction(parameters, tret, VarArg.none, LINK.d);
+                tfgetmembers = tf.dsymbolSemantic(Loc.initial, &sc).isTypeFunction();
             }
             if (fdx)
                 fdx = fdx.overloadExactMatch(tfgetmembers);
@@ -1863,11 +1854,11 @@  extern (C++) final class WithScopeSymbol : ScopeDsymbol
         Expression eold = null;
         for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
         {
-            if (e.op == EXP.scope_)
+            if (auto se = e.isScopeExp())
             {
-                s = (cast(ScopeExp)e).sds;
+                s = se.sds;
             }
-            else if (e.op == EXP.type)
+            else if (e.isTypeExp())
             {
                 s = e.type.toDsymbol(null);
             }
@@ -2041,11 +2032,11 @@  extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
                 if (TemplateDeclaration td = s.isTemplateDeclaration())
                 {
                     dinteger_t dim = 0;
-                    if (exp.op == EXP.array)
+                    if (auto ae = exp.isArrayExp())
                     {
-                        dim = (cast(ArrayExp)exp).currentDimension;
+                        dim = ae.currentDimension;
                     }
-                    else if (exp.op == EXP.slice)
+                    else if (exp.isSliceExp())
                     {
                         dim = 0; // slices are currently always one-dimensional
                     }
@@ -2066,7 +2057,8 @@  extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
                      * Note that it's impossible to have both template & function opDollar,
                      * because both take no arguments.
                      */
-                    if (exp.op == EXP.array && (cast(ArrayExp)exp).arguments.length != 1)
+                    auto ae = exp.isArrayExp();
+                    if (ae && ae.arguments.length != 1)
                     {
                         error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
                         return null;
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 8309e4a846b..397c5e53d7f 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -1320,7 +1320,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return;
 
         if (!(global.params.bitfields || sc.flags & SCOPE.Cfile))
-            .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars);
+        {
+            version (IN_GCC)
+                .error(dsym.loc, "%s `%s` use `-fpreview=bitfields` for bitfield support", dsym.kind, dsym.toPrettyChars);
+            else
+                .error(dsym.loc, "%s `%s` use -preview=bitfields for bitfield support", dsym.kind, dsym.toPrettyChars);
+        }
 
         if (!dsym.parent.isStructDeclaration() && !dsym.parent.isClassDeclaration())
         {
@@ -1390,7 +1395,11 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             // if parser errors occur when loading a module
             // we should just stop compilation
             if (imp.load(sc))
+            {
+                for (size_t i = 0; i < imp.aliasdecls.length; i++)
+                    imp.aliasdecls[i].type = Type.terror;
                 return;
+            }
 
             if (imp.mod)
             {
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 5dca6dfec6e..883f4ac94cf 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -49,6 +49,7 @@  import dmd.attrib;
 import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
+import dmd.dinterpret;
 import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
@@ -5725,13 +5726,19 @@  extern (C++) final class TemplateAliasParameter : TemplateParameter
     override RootObject defaultArg(const ref Loc instLoc, Scope* sc)
     {
         RootObject da = defaultAlias;
-        Type ta = isType(defaultAlias);
-        if (ta)
+        if (auto ta = isType(defaultAlias))
         {
-            if (ta.ty == Tinstance)
+            switch (ta.ty)
             {
-                // If the default arg is a template, instantiate for each type
+            // If the default arg is a template, instantiate for each type
+            case Tinstance :
+            // same if the default arg is a mixin, traits, typeof
+            // since the content might rely on a previous parameter
+            // (https://issues.dlang.org/show_bug.cgi?id=23686)
+            case Tmixin, Ttypeof, Ttraits :
                 da = ta.syntaxCopy();
+                break;
+            default:
             }
         }
 
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 32ded3bd5f6..87611f4690f 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -24,24 +24,18 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
 import dmd.gluelayer;
-import dmd.constfold;
 import dmd.ctfeexpr;
 import dmd.ctorflow;
-import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
-import dmd.delegatize;
 import dmd.dimport;
-import dmd.dinterpret;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.errorsink;
-import dmd.escape;
 import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
@@ -49,11 +43,8 @@  import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.init;
-import dmd.inline;
 import dmd.location;
 import dmd.mtype;
-import dmd.nspace;
-import dmd.objc;
 import dmd.opover;
 import dmd.optimize;
 import dmd.root.complex;
@@ -66,10 +57,8 @@  import dmd.rootobject;
 import dmd.root.string;
 import dmd.root.utf;
 import dmd.safe;
-import dmd.sideeffect;
 import dmd.target;
 import dmd.tokens;
-import dmd.typesem;
 import dmd.visitor;
 
 enum LOGSEMANTIC = false;
@@ -745,21 +734,6 @@  extern (C++) abstract class Expression : ASTNode
         return toLvalue(sc, e);
     }
 
-    extern (D) final Expression implicitCastTo(Scope* sc, Type t)
-    {
-        return .implicitCastTo(this, sc, t);
-    }
-
-    final MATCH implicitConvTo(Type t)
-    {
-        return .implicitConvTo(this, t);
-    }
-
-    extern (D) final Expression castTo(Scope* sc, Type t)
-    {
-        return .castTo(this, sc, t);
-    }
-
     /****************************************
      * Resolve __FILE__, __LINE__, __MODULE__, __FUNCTION__, __PRETTY_FUNCTION__, __FILE_FULL_PATH__ to loc.
      */
@@ -1304,16 +1278,6 @@  extern (C++) abstract class Expression : ASTNode
         return true;
     }
 
-    /************************************************
-     * Destructors are attached to VarDeclarations.
-     * Hence, if expression returns a temp that needs a destructor,
-     * make sure and create a VarDeclaration for that temp.
-     */
-    Expression addDtorHook(Scope* sc)
-    {
-        return this;
-    }
-
     /******************************
      * Take address of expression.
      */
@@ -1349,16 +1313,23 @@  extern (C++) abstract class Expression : ASTNode
         return Expression_optimize(this, result, keepLvalue);
     }
 
-    // Entry point for CTFE.
-    // A compile-time result is required. Give an error if not possible
-    final Expression ctfeInterpret()
-    {
-        return .ctfeInterpret(this);
-    }
-
     final int isConst()
     {
-        return .isConst(this);
+        //printf("Expression::isConst(): %s\n", e.toChars());
+        switch (op)
+        {
+        case EXP.int64:
+        case EXP.float64:
+        case EXP.complex80:
+            return 1;
+        case EXP.null_:
+            return 0;
+        case EXP.symbolOffset:
+            return 2;
+        default:
+            return 0;
+        }
+        assert(0);
     }
 
     /******
@@ -2110,13 +2081,19 @@  extern (C++) class ThisExp : Expression
         return typeof(return)(true);
     }
 
-    override bool isLvalue()
+    override final bool isLvalue()
     {
-        return true;
+        // Class `this` should be an rvalue; struct `this` should be an lvalue.
+        return type.toBasetype().ty != Tclass;
     }
 
-    override Expression toLvalue(Scope* sc, Expression e)
+    override final Expression toLvalue(Scope* sc, Expression e)
     {
+        if (type.toBasetype().ty == Tclass)
+        {
+            // Class `this` is an rvalue; struct `this` is an lvalue.
+            return Expression.toLvalue(sc, e);
+        }
         return this;
     }
 
@@ -2136,18 +2113,6 @@  extern (C++) final class SuperExp : ThisExp
         super(loc, EXP.super_);
     }
 
-    override bool isLvalue()
-    {
-        // Class `super` should be an rvalue
-        return false;
-    }
-
-    override Expression toLvalue(Scope* sc, Expression e)
-    {
-        // Class `super` is an rvalue
-        return Expression.toLvalue(sc, e);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -2187,12 +2152,13 @@  extern (C++) final class NullExp : Expression
 
     override StringExp toStringExp()
     {
-        if (implicitConvTo(Type.tstring))
+        if (this.type.implicitConvTo(Type.tstring))
         {
             auto se = new StringExp(loc, (cast(char*)mem.xcalloc(1, 1))[0 .. 0]);
             se.type = Type.tstring;
             return se;
         }
+
         return null;
     }
 
@@ -2417,23 +2383,6 @@  extern (C++) final class StringExp : Expression
         return this;
     }
 
-    /****************************************
-     * Convert string to char[].
-     */
-    StringExp toUTF8(Scope* sc)
-    {
-        if (sz != 1)
-        {
-            // Convert to UTF-8 string
-            committed = false;
-            Expression e = castTo(sc, Type.tchar.arrayOf());
-            e = e.optimize(WANTvalue);
-            auto se = e.isStringExp();
-            assert(se.sz == 1);
-            return se;
-        }
-        return this;
-    }
 
     /**
      * Compare two `StringExp` by length, then value
@@ -3101,34 +3050,6 @@  extern (C++) final class StructLiteralExp : Expression
         return -1;
     }
 
-    override Expression addDtorHook(Scope* sc)
-    {
-        /* If struct requires a destructor, rewrite as:
-         *    (S tmp = S()),tmp
-         * so that the destructor can be hung on tmp.
-         */
-        if (sd.dtor && sc.func)
-        {
-            /* Make an identifier for the temporary of the form:
-             *   __sl%s%d, where %s is the struct name
-             */
-            char[10] buf = void;
-            const prefix = "__sl";
-            const ident = sd.ident.toString;
-            const fullLen = prefix.length + ident.length;
-            const len = fullLen < buf.length ? fullLen : buf.length;
-            buf[0 .. prefix.length] = prefix;
-            buf[prefix.length .. len] = ident[0 .. len - prefix.length];
-
-            auto tmp = copyToTemp(0, buf[0 .. len], this);
-            Expression ae = new DeclarationExp(loc, tmp);
-            Expression e = new CommaExp(loc, ae, new VarExp(loc, tmp));
-            e = e.expressionSemantic(sc);
-            return e;
-        }
-        return this;
-    }
-
     override Expression toLvalue(Scope* sc, Expression e)
     {
         if (sc.flags & SCOPE.Cfile)
@@ -3658,173 +3579,6 @@  extern (C++) final class FuncExp : Expression
             return new FuncExp(loc, fd);
     }
 
-    extern (D) MATCH matchType(Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
-    {
-        MATCH cannotInfer()
-        {
-            eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
-            return MATCH.nomatch;
-        }
-
-        //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
-        if (presult)
-            *presult = null;
-
-        TypeFunction tof = null;
-        if (to.ty == Tdelegate)
-        {
-            if (tok == TOK.function_)
-            {
-                eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
-                return MATCH.nomatch;
-            }
-            tof = cast(TypeFunction)to.nextOf();
-        }
-        else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
-        {
-            if (tok == TOK.delegate_)
-            {
-                eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
-                return MATCH.nomatch;
-            }
-        }
-
-        if (td)
-        {
-            if (!tof)
-            {
-                return cannotInfer();
-            }
-
-            // Parameter types inference from 'tof'
-            assert(td._scope);
-            TypeFunction tf = fd.type.isTypeFunction();
-            //printf("\ttof = %s\n", tof.toChars());
-            //printf("\ttf  = %s\n", tf.toChars());
-            const dim = tf.parameterList.length;
-
-            if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
-                return cannotInfer();
-
-            auto tiargs = new Objects();
-            tiargs.reserve(td.parameters.length);
-
-            foreach (tp; *td.parameters)
-            {
-                size_t u = 0;
-                foreach (i, p; tf.parameterList)
-                {
-                    if (auto ti = p.type.isTypeIdentifier())
-                        if (ti && ti.ident == tp.ident)
-                            break;
-
-                    ++u;
-                }
-                assert(u < dim);
-                Parameter pto = tof.parameterList[u];
-                Type t = pto.type;
-                if (t.ty == Terror)
-                    return cannotInfer();
-                tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
-                tiargs.push(t);
-            }
-
-            // Set target of return type inference
-            if (!tf.next && tof.next)
-                fd.treq = to;
-
-            auto ti = new TemplateInstance(loc, td, tiargs);
-            Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
-
-            // Reset inference target for the later re-semantic
-            fd.treq = null;
-
-            if (ex.op == EXP.error)
-                return MATCH.nomatch;
-            if (auto ef = ex.isFuncExp())
-                return ef.matchType(to, sc, presult, eSink);
-            else
-                return cannotInfer();
-        }
-
-        if (!tof || !tof.next)
-            return MATCH.nomatch;
-
-        assert(type && type != Type.tvoid);
-        if (fd.type.ty == Terror)
-            return MATCH.nomatch;
-        auto tfx = fd.type.isTypeFunction();
-        bool convertMatch = (type.ty != to.ty);
-
-        if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
-        {
-            /* If return type is inferred and covariant return,
-             * tweak return statements to required return type.
-             *
-             * interface I {}
-             * class C : Object, I{}
-             *
-             * I delegate() dg = delegate() { return new class C(); }
-             */
-            convertMatch = true;
-
-            auto tfy = new TypeFunction(tfx.parameterList, tof.next,
-                        tfx.linkage, STC.undefined_);
-            tfy.mod = tfx.mod;
-            tfy.trust = tfx.trust;
-            tfy.isnothrow = tfx.isnothrow;
-            tfy.isnogc = tfx.isnogc;
-            tfy.purity = tfx.purity;
-            tfy.isproperty = tfx.isproperty;
-            tfy.isref = tfx.isref;
-            tfy.isInOutParam = tfx.isInOutParam;
-            tfy.isInOutQual = tfx.isInOutQual;
-            tfy.deco = tfy.merge().deco;
-
-            tfx = tfy;
-        }
-        Type tx;
-        if (tok == TOK.delegate_ ||
-            tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
-        {
-            // Allow conversion from implicit function pointer to delegate
-            tx = new TypeDelegate(tfx);
-            tx.deco = tx.merge().deco;
-        }
-        else
-        {
-            assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
-            tx = tfx.pointerTo();
-        }
-        //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
-
-        MATCH m = tx.implicitConvTo(to);
-        if (m > MATCH.nomatch)
-        {
-            // MATCH.exact:      exact type match
-            // MATCH.constant:      covairiant type match (eg. attributes difference)
-            // MATCH.convert:    context conversion
-            m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
-
-            if (presult)
-            {
-                (*presult) = cast(FuncExp)copy();
-                (*presult).type = to;
-
-                // https://issues.dlang.org/show_bug.cgi?id=12508
-                // Tweak function body for covariant returns.
-                (*presult).fd.modifyReturns(sc, tof.next);
-            }
-        }
-        else if (!cast(ErrorSinkNull)eSink)
-        {
-            auto ts = toAutoQualChars(tx, to);
-            eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
-                toChars(), ts[0], ts[1]);
-        }
-        return m;
-    }
-
     override const(char)* toChars() const
     {
         return fd.toChars();
@@ -4133,153 +3887,6 @@  extern (C++) abstract class BinExp : Expression
         return ErrorExp.get();
     }
 
-    extern (D) final Expression checkOpAssignTypes(Scope* sc)
-    {
-        // At that point t1 and t2 are the merged types. type is the original type of the lhs.
-        Type t1 = e1.type;
-        Type t2 = e2.type;
-
-        // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
-        // See https://issues.dlang.org/show_bug.cgi?id=3841.
-        // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
-        if (op == EXP.addAssign || op == EXP.minAssign ||
-            op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
-            op == EXP.powAssign)
-        {
-            if ((type.isintegral() && t2.isfloating()))
-            {
-                warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
-            }
-        }
-
-        // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
-        if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
-        {
-            // Any multiplication by an imaginary or complex number yields a complex result.
-            // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
-            const(char)* opstr = EXPtoString(op).ptr;
-            if (t1.isreal() && t2.iscomplex())
-            {
-                error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
-                return ErrorExp.get();
-            }
-            else if (t1.isimaginary() && t2.iscomplex())
-            {
-                error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
-                return ErrorExp.get();
-            }
-            else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
-            {
-                error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
-                return ErrorExp.get();
-            }
-        }
-
-        // generate an error if this is a nonsensical += or -=, eg real += imaginary
-        if (op == EXP.addAssign || op == EXP.minAssign)
-        {
-            // Addition or subtraction of a real and an imaginary is a complex result.
-            // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
-            if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
-            {
-                error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
-                return ErrorExp.get();
-            }
-            if (type.isreal() || type.isimaginary())
-            {
-                assert(global.errors || t2.isfloating());
-                e2 = e2.castTo(sc, t1);
-            }
-        }
-        if (op == EXP.mulAssign)
-        {
-            if (t2.isfloating())
-            {
-                if (t1.isreal())
-                {
-                    if (t2.isimaginary() || t2.iscomplex())
-                    {
-                        e2 = e2.castTo(sc, t1);
-                    }
-                }
-                else if (t1.isimaginary())
-                {
-                    if (t2.isimaginary() || t2.iscomplex())
-                    {
-                        switch (t1.ty)
-                        {
-                        case Timaginary32:
-                            t2 = Type.tfloat32;
-                            break;
-
-                        case Timaginary64:
-                            t2 = Type.tfloat64;
-                            break;
-
-                        case Timaginary80:
-                            t2 = Type.tfloat80;
-                            break;
-
-                        default:
-                            assert(0);
-                        }
-                        e2 = e2.castTo(sc, t2);
-                    }
-                }
-            }
-        }
-        else if (op == EXP.divAssign)
-        {
-            if (t2.isimaginary())
-            {
-                if (t1.isreal())
-                {
-                    // x/iv = i(-x/v)
-                    // Therefore, the result is 0
-                    e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
-                    e2.type = t1;
-                    Expression e = new AssignExp(loc, e1, e2);
-                    e.type = t1;
-                    return e;
-                }
-                else if (t1.isimaginary())
-                {
-                    Type t3;
-                    switch (t1.ty)
-                    {
-                    case Timaginary32:
-                        t3 = Type.tfloat32;
-                        break;
-
-                    case Timaginary64:
-                        t3 = Type.tfloat64;
-                        break;
-
-                    case Timaginary80:
-                        t3 = Type.tfloat80;
-                        break;
-
-                    default:
-                        assert(0);
-                    }
-                    e2 = e2.castTo(sc, t3);
-                    Expression e = new AssignExp(loc, e1, e2);
-                    e.type = t1;
-                    return e;
-                }
-            }
-        }
-        else if (op == EXP.modAssign)
-        {
-            if (t2.iscomplex())
-            {
-                error(loc, "cannot perform modulo complex arithmetic");
-                return ErrorExp.get();
-            }
-        }
-        return this;
-    }
-
     extern (D) final bool checkIntegralBin()
     {
         bool r1 = e1.checkIntegral();
@@ -4294,13 +3901,6 @@  extern (C++) abstract class BinExp : Expression
         return (r1 || r2);
     }
 
-    extern (D) final bool checkSharedAccessBin(Scope* sc)
-    {
-        const r1 = e1.checkSharedAccess(sc);
-        const r2 = e2.checkSharedAccess(sc);
-        return (r1 || r2);
-    }
-
     /*********************
      * Mark the operands as will never be dereferenced,
      * which is useful info for @safe checks.
@@ -4315,54 +3915,6 @@  extern (C++) abstract class BinExp : Expression
 
     }
 
-    extern (D) final Expression reorderSettingAAElem(Scope* sc)
-    {
-        BinExp be = this;
-
-        auto ie = be.e1.isIndexExp();
-        if (!ie)
-            return be;
-        if (ie.e1.type.toBasetype().ty != Taarray)
-            return be;
-
-        /* Fix evaluation order of setting AA element
-         * https://issues.dlang.org/show_bug.cgi?id=3825
-         * Rewrite:
-         *     aa[k1][k2][k3] op= val;
-         * as:
-         *     auto ref __aatmp = aa;
-         *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
-         *     auto ref __aaval = val;
-         *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
-         */
-
-        Expression e0;
-        while (1)
-        {
-            Expression de;
-            ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
-            e0 = Expression.combine(de, e0);
-
-            auto ie1 = ie.e1.isIndexExp();
-            if (!ie1 ||
-                ie1.e1.type.toBasetype().ty != Taarray)
-            {
-                break;
-            }
-            ie = ie1;
-        }
-        assert(ie.e1.type.toBasetype().ty == Taarray);
-
-        Expression de;
-        ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
-        e0 = Expression.combine(de, e0);
-
-        be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
-
-        //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
-        return Expression.combine(e0, be);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -4941,38 +4493,6 @@  extern (C++) final class CallExp : UnaExp
         return Expression.toLvalue(sc, e);
     }
 
-    override Expression addDtorHook(Scope* sc)
-    {
-        /* Only need to add dtor hook if it's a type that needs destruction.
-         * Use same logic as VarDeclaration::callScopeDtor()
-         */
-
-        if (auto tf = e1.type.isTypeFunction())
-        {
-            if (tf.isref)
-                return this;
-        }
-
-        Type tv = type.baseElemOf();
-        if (auto ts = tv.isTypeStruct())
-        {
-            StructDeclaration sd = ts.sym;
-            if (sd.dtor)
-            {
-                /* Type needs destruction, so declare a tmp
-                 * which the back end will recognize and call dtor on
-                 */
-                auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), this);
-                auto de = new DeclarationExp(loc, tmp);
-                auto ve = new VarExp(loc, tmp);
-                Expression e = new CommaExp(loc, de, ve);
-                e = e.expressionSemantic(sc);
-                return e;
-            }
-        }
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -5248,13 +4768,6 @@  extern (C++) final class CastExp : UnaExp
         return Expression.toLvalue(sc, e);
     }
 
-    override Expression addDtorHook(Scope* sc)
-    {
-        if (to.toBasetype().ty == Tvoid)        // look past the cast(void)
-            e1 = e1.addDtorHook(sc);
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -5522,12 +5035,6 @@  extern (C++) final class CommaExp : BinExp
         return e2.toBool();
     }
 
-    override Expression addDtorHook(Scope* sc)
-    {
-        e2 = e2.addDtorHook(sc);
-        return this;
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -6785,7 +6292,6 @@  extern (C++) final class ObjcClassReferenceExp : Expression
     {
         super(loc, EXP.objcClassReference);
         this.classDeclaration = classDeclaration;
-        type = objc.getRuntimeMetaclass(classDeclaration).getType();
     }
 
     override void accept(Visitor v)
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index cfd5198ce79..f7f6b0b63ff 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -45,7 +45,12 @@  typedef union tree_node Symbol;
 struct Symbol;          // back end symbol
 #endif
 
+// Entry point for CTFE.
+// A compile-time result is required. Give an error if not possible
+Expression *ctfeInterpret(Expression *e);
 void expandTuples(Expressions *exps, Identifiers *names = nullptr);
+StringExp *toUTF8(StringExp *se, Scope *sc);
+MATCH implicitConvTo(Expression *e, Type *t);
 
 typedef unsigned char OwnedBy;
 enum
@@ -96,19 +101,14 @@  public:
     virtual bool isLvalue();
     virtual Expression *toLvalue(Scope *sc, Expression *e);
     virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
-    MATCH implicitConvTo(Type *t);
     virtual Expression *resolveLoc(const Loc &loc, Scope *sc);
     virtual bool checkType();
     virtual bool checkValue();
-    virtual Expression *addDtorHook(Scope *sc);
     Expression *addressOf();
     Expression *deref();
 
     Expression *optimize(int result, bool keepLvalue = false);
 
-    // Entry point for CTFE.
-    // A compile-time result is required. Give an error if not possible
-    Expression *ctfeInterpret();
     int isConst();
     virtual bool isIdentical(const Expression *e) const;
     virtual Optional<bool> toBool();
@@ -331,8 +331,8 @@  public:
 
     ThisExp *syntaxCopy() override;
     Optional<bool> toBool() override;
-    bool isLvalue() override;
-    Expression *toLvalue(Scope *sc, Expression *e) override;
+    bool isLvalue() override final;
+    Expression *toLvalue(Scope *sc, Expression *e) override final;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -340,8 +340,6 @@  public:
 class SuperExp final : public ThisExp
 {
 public:
-    bool isLvalue() override;
-    Expression* toLvalue(Scope* sc, Expression* e) final override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
@@ -370,7 +368,6 @@  public:
     bool equals(const RootObject * const o) const override;
     char32_t getCodeUnit(d_size_t i) const;
     StringExp *toStringExp() override;
-    StringExp *toUTF8(Scope *sc);
     Optional<bool> toBool() override;
     bool isLvalue() override;
     Expression *toLvalue(Scope *sc, Expression *e) override;
@@ -472,7 +469,6 @@  public:
     static StructLiteralExp *create(const Loc &loc, StructDeclaration *sd, void *elements, Type *stype = NULL);
     bool equals(const RootObject * const o) const override;
     StructLiteralExp *syntaxCopy() override;
-    Expression *addDtorHook(Scope *sc) override;
     Expression *toLvalue(Scope *sc, Expression *e) override;
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -826,7 +822,6 @@  public:
     CallExp *syntaxCopy() override;
     bool isLvalue() override;
     Expression *toLvalue(Scope *sc, Expression *e) override;
-    Expression *addDtorHook(Scope *sc) override;
 
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -1005,7 +1000,6 @@  public:
     Expression *toLvalue(Scope *sc, Expression *e) override;
     Expression *modifiableLvalue(Scope *sc, Expression *e) override;
     Optional<bool> toBool() override;
-    Expression *addDtorHook(Scope *sc) override;
     void accept(Visitor *v) override { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index ac8e5715b28..1ddb2b1ea08 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -41,6 +41,7 @@  import dmd.dstruct;
 import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
+import dmd.errorsink;
 import dmd.escape;
 import dmd.expression;
 import dmd.file_manager;
@@ -59,6 +60,7 @@  import dmd.location;
 import dmd.mtype;
 import dmd.mustuse;
 import dmd.nspace;
+import dmd.objc;
 import dmd.opover;
 import dmd.optimize;
 import dmd.parse;
@@ -231,6 +233,226 @@  StringExp semanticString(Scope *sc, Expression exp, const char* s)
     return se;
 }
 
+/****************************************
+ * Convert string to char[].
+ */
+StringExp toUTF8(StringExp se, Scope* sc)
+{
+    if (se.sz != 1)
+    {
+        // Convert to UTF-8 string
+        se.committed = false;
+        Expression e = castTo(se, sc, Type.tchar.arrayOf());
+        e = e.optimize(WANTvalue);
+        auto result = e.isStringExp();
+        assert(result.sz == 1);
+        return result;
+    }
+    return se;
+}
+
+private Expression reorderSettingAAElem(BinExp exp, Scope* sc)
+{
+    BinExp be = exp;
+
+    auto ie = be.e1.isIndexExp();
+    if (!ie)
+        return be;
+    if (ie.e1.type.toBasetype().ty != Taarray)
+        return be;
+
+    /* Fix evaluation order of setting AA element
+     * https://issues.dlang.org/show_bug.cgi?id=3825
+     * Rewrite:
+     *     aa[k1][k2][k3] op= val;
+     * as:
+     *     auto ref __aatmp = aa;
+     *     auto ref __aakey3 = k1, __aakey2 = k2, __aakey1 = k3;
+     *     auto ref __aaval = val;
+     *     __aatmp[__aakey3][__aakey2][__aakey1] op= __aaval;  // assignment
+     */
+
+    Expression e0;
+    while (1)
+    {
+        Expression de;
+        ie.e2 = extractSideEffect(sc, "__aakey", de, ie.e2);
+        e0 = Expression.combine(de, e0);
+
+        auto ie1 = ie.e1.isIndexExp();
+        if (!ie1 ||
+            ie1.e1.type.toBasetype().ty != Taarray)
+        {
+            break;
+        }
+        ie = ie1;
+    }
+    assert(ie.e1.type.toBasetype().ty == Taarray);
+
+    Expression de;
+    ie.e1 = extractSideEffect(sc, "__aatmp", de, ie.e1);
+    e0 = Expression.combine(de, e0);
+
+    be.e2 = extractSideEffect(sc, "__aaval", e0, be.e2, true);
+
+    //printf("-e0 = %s, be = %s\n", e0.toChars(), be.toChars());
+    return Expression.combine(e0, be);
+}
+
+
+private Expression checkOpAssignTypes(BinExp binExp, Scope* sc)
+{
+    auto e1 = binExp.e1;
+    auto e2 = binExp.e2;
+    auto op = binExp.op;
+    auto type = binExp.type;
+    auto loc = binExp.loc;
+
+    // At that point t1 and t2 are the merged types. type is the original type of the lhs.
+    Type t1 = e1.type;
+    Type t2 = e2.type;
+
+    // T opAssign floating yields a floating. Prevent truncating conversions (float to int).
+    // See https://issues.dlang.org/show_bug.cgi?id=3841.
+    // Should we also prevent double to float (type.isfloating() && type.size() < t2.size()) ?
+    if (op == EXP.addAssign || op == EXP.minAssign ||
+        op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign ||
+        op == EXP.powAssign)
+    {
+        if ((type.isintegral() && t2.isfloating()))
+        {
+            warning(loc, "`%s %s %s` is performing truncating conversion", type.toChars(), EXPtoString(op).ptr, t2.toChars());
+        }
+    }
+
+    // generate an error if this is a nonsensical *=,/=, or %=, eg real *= imaginary
+    if (op == EXP.mulAssign || op == EXP.divAssign || op == EXP.modAssign)
+    {
+        // Any multiplication by an imaginary or complex number yields a complex result.
+        // r *= c, i*=c, r*=i, i*=i are all forbidden operations.
+        const(char)* opstr = EXPtoString(op).ptr;
+        if (t1.isreal() && t2.iscomplex())
+        {
+            error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.re`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+            return ErrorExp.get();
+        }
+        else if (t1.isimaginary() && t2.iscomplex())
+        {
+            error(loc, "`%s %s %s` is undefined. Did you mean `%s %s %s.im`?", t1.toChars(), opstr, t2.toChars(), t1.toChars(), opstr, t2.toChars());
+            return ErrorExp.get();
+        }
+        else if ((t1.isreal() || t1.isimaginary()) && t2.isimaginary())
+        {
+            error(loc, "`%s %s %s` is an undefined operation", t1.toChars(), opstr, t2.toChars());
+            return ErrorExp.get();
+        }
+    }
+
+    // generate an error if this is a nonsensical += or -=, eg real += imaginary
+    if (op == EXP.addAssign || op == EXP.minAssign)
+    {
+        // Addition or subtraction of a real and an imaginary is a complex result.
+        // Thus, r+=i, r+=c, i+=r, i+=c are all forbidden operations.
+        if ((t1.isreal() && (t2.isimaginary() || t2.iscomplex())) || (t1.isimaginary() && (t2.isreal() || t2.iscomplex())))
+        {
+            error(loc, "`%s %s %s` is undefined (result is complex)", t1.toChars(), EXPtoString(op).ptr, t2.toChars());
+            return ErrorExp.get();
+        }
+        if (type.isreal() || type.isimaginary())
+        {
+            assert(global.errors || t2.isfloating());
+            e2 = e2.castTo(sc, t1);
+        }
+    }
+    if (op == EXP.mulAssign)
+    {
+        if (t2.isfloating())
+        {
+            if (t1.isreal())
+            {
+                if (t2.isimaginary() || t2.iscomplex())
+                {
+                    e2 = e2.castTo(sc, t1);
+                }
+            }
+            else if (t1.isimaginary())
+            {
+                if (t2.isimaginary() || t2.iscomplex())
+                {
+                    switch (t1.ty)
+                    {
+                    case Timaginary32:
+                        t2 = Type.tfloat32;
+                        break;
+
+                    case Timaginary64:
+                        t2 = Type.tfloat64;
+                        break;
+
+                    case Timaginary80:
+                        t2 = Type.tfloat80;
+                        break;
+
+                    default:
+                        assert(0);
+                    }
+                    e2 = e2.castTo(sc, t2);
+                }
+            }
+        }
+    }
+    else if (op == EXP.divAssign)
+    {
+        if (t2.isimaginary())
+        {
+            if (t1.isreal())
+            {
+                // x/iv = i(-x/v)
+                // Therefore, the result is 0
+                e2 = new CommaExp(loc, e2, new RealExp(loc, CTFloat.zero, t1));
+                e2.type = t1;
+                Expression e = new AssignExp(loc, e1, e2);
+                e.type = t1;
+                return e;
+            }
+            else if (t1.isimaginary())
+            {
+                Type t3;
+                switch (t1.ty)
+                {
+                case Timaginary32:
+                    t3 = Type.tfloat32;
+                    break;
+
+                case Timaginary64:
+                    t3 = Type.tfloat64;
+                    break;
+
+                case Timaginary80:
+                    t3 = Type.tfloat80;
+                    break;
+
+                default:
+                    assert(0);
+                }
+                e2 = e2.castTo(sc, t3);
+                Expression e = new AssignExp(loc, e1, e2);
+                e.type = t1;
+                return e;
+            }
+        }
+    }
+    else if (op == EXP.modAssign)
+    {
+        if (t2.iscomplex())
+        {
+            error(loc, "cannot perform modulo complex arithmetic");
+            return ErrorExp.get();
+        }
+    }
+    return binExp;
+}
+
 private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue)
 {
     Expression e0;
@@ -1364,7 +1586,10 @@  L1:
              var.isFuncDeclaration && var.isFuncDeclaration.isStatic &&
              var.isFuncDeclaration.objc.selector)
     {
-        return new ObjcClassReferenceExp(e1.loc, ad.isClassDeclaration());
+        auto cls = ad.isClassDeclaration();
+        auto classObj = new ObjcClassReferenceExp(e1.loc, cls);
+        classObj.type = objc.getRuntimeMetaclass(cls).getType();
+        return classObj;
     }
 
     /* Access of a member which is a template parameter in dual-scope scenario
@@ -2471,7 +2696,8 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
             //printf("type: %s\n", arg.type.toChars());
             //printf("param: %s\n", p.toChars());
 
-            const pStc = tf.parameterStorageClass(tthis, p);
+            const indirect = (fd is null) || (fd.isVirtual() && !fd.isFinal());
+            const pStc = tf.parameterStorageClass(tthis, p, fd ? &fd.outerVars : null, indirect);
 
             if (firstArg && (pStc & STC.return_))
             {
@@ -5176,7 +5402,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     }
                     else
                         assert(0);
-                    e = new CallExp(exp.loc, e, exp.arguments);
+                    e = new CallExp(exp.loc, e, exp.arguments, exp.names);
                     e = e.expressionSemantic(sc);
                     result = e;
                     return;
@@ -13890,6 +14116,186 @@  Lerr:
     return errorExp();
 }
 
+MATCH matchType(FuncExp funcExp, Type to, Scope* sc, FuncExp* presult, ErrorSink eSink)
+{
+    auto loc = funcExp.loc;
+    auto tok = funcExp.tok;
+    auto td = funcExp.td;
+    auto fd = funcExp.fd;
+    auto type = funcExp.type;
+
+    MATCH cannotInfer()
+    {
+        eSink.error(loc, "cannot infer parameter types from `%s`", to.toChars());
+        return MATCH.nomatch;
+    }
+
+    //printf("FuncExp::matchType('%s'), to=%s\n", type ? type.toChars() : "null", to.toChars());
+    if (presult)
+        *presult = null;
+
+    TypeFunction tof = null;
+    if (to.ty == Tdelegate)
+    {
+        if (tok == TOK.function_)
+        {
+            eSink.error(loc, "cannot match function literal to delegate type `%s`", to.toChars());
+            return MATCH.nomatch;
+        }
+        tof = cast(TypeFunction)to.nextOf();
+    }
+    else if (to.ty == Tpointer && (tof = to.nextOf().isTypeFunction()) !is null)
+    {
+        if (tok == TOK.delegate_)
+        {
+            eSink.error(loc, "cannot match delegate literal to function pointer type `%s`", to.toChars());
+            return MATCH.nomatch;
+        }
+    }
+
+    if (td)
+    {
+        if (!tof)
+        {
+            return cannotInfer();
+        }
+
+        // Parameter types inference from 'tof'
+        assert(td._scope);
+        TypeFunction tf = fd.type.isTypeFunction();
+        //printf("\ttof = %s\n", tof.toChars());
+        //printf("\ttf  = %s\n", tf.toChars());
+        const dim = tf.parameterList.length;
+
+        if (tof.parameterList.length != dim || tof.parameterList.varargs != tf.parameterList.varargs)
+            return cannotInfer();
+
+        auto tiargs = new Objects();
+        tiargs.reserve(td.parameters.length);
+
+        foreach (tp; *td.parameters)
+        {
+            size_t u = 0;
+            foreach (i, p; tf.parameterList)
+            {
+                if (auto ti = p.type.isTypeIdentifier())
+                    if (ti && ti.ident == tp.ident)
+                        break;
+
+                ++u;
+            }
+            assert(u < dim);
+            Parameter pto = tof.parameterList[u];
+            Type t = pto.type;
+            if (t.ty == Terror)
+                return cannotInfer();
+            tf.parameterList[u].storageClass = tof.parameterList[u].storageClass;
+            tiargs.push(t);
+        }
+
+        // Set target of return type inference
+        if (!tf.next && tof.next)
+            fd.treq = to;
+
+        auto ti = new TemplateInstance(loc, td, tiargs);
+        Expression ex = (new ScopeExp(loc, ti)).expressionSemantic(td._scope);
+
+        // Reset inference target for the later re-semantic
+        fd.treq = null;
+
+        if (ex.op == EXP.error)
+            return MATCH.nomatch;
+        if (auto ef = ex.isFuncExp())
+            return ef.matchType(to, sc, presult, eSink);
+        else
+            return cannotInfer();
+    }
+
+    if (!tof || !tof.next)
+        return MATCH.nomatch;
+
+    assert(type && type != Type.tvoid);
+    if (fd.type.ty == Terror)
+        return MATCH.nomatch;
+    auto tfx = fd.type.isTypeFunction();
+    bool convertMatch = (type.ty != to.ty);
+
+    if (fd.inferRetType && tfx.next.implicitConvTo(tof.next) == MATCH.convert)
+    {
+        /* If return type is inferred and covariant return,
+         * tweak return statements to required return type.
+         *
+         * interface I {}
+         * class C : Object, I{}
+         *
+         * I delegate() dg = delegate() { return new class C(); }
+         */
+        convertMatch = true;
+
+        auto tfy = new TypeFunction(tfx.parameterList, tof.next,
+                    tfx.linkage, STC.undefined_);
+        tfy.mod = tfx.mod;
+        tfy.trust = tfx.trust;
+        tfy.isnothrow = tfx.isnothrow;
+        tfy.isnogc = tfx.isnogc;
+        tfy.purity = tfx.purity;
+        tfy.isproperty = tfx.isproperty;
+        tfy.isref = tfx.isref;
+        tfy.isInOutParam = tfx.isInOutParam;
+        tfy.isInOutQual = tfx.isInOutQual;
+        tfy.deco = tfy.merge().deco;
+
+        tfx = tfy;
+    }
+    Type tx;
+    if (tok == TOK.delegate_ ||
+        tok == TOK.reserved && (type.ty == Tdelegate || type.ty == Tpointer && to.ty == Tdelegate))
+    {
+        // Allow conversion from implicit function pointer to delegate
+        tx = new TypeDelegate(tfx);
+        tx.deco = tx.merge().deco;
+    }
+    else
+    {
+        assert(tok == TOK.function_ || tok == TOK.reserved && type.ty == Tpointer || fd.errors);
+        tx = tfx.pointerTo();
+    }
+    //printf("\ttx = %s, to = %s\n", tx.toChars(), to.toChars());
+
+    MATCH m = tx.implicitConvTo(to);
+    if (m > MATCH.nomatch)
+    {
+        // MATCH.exact:      exact type match
+        // MATCH.constant:      covairiant type match (eg. attributes difference)
+        // MATCH.convert:    context conversion
+        m = convertMatch ? MATCH.convert : tx.equals(to) ? MATCH.exact : MATCH.constant;
+
+        if (presult)
+        {
+            (*presult) = cast(FuncExp)funcExp.copy();
+            (*presult).type = to;
+
+            // https://issues.dlang.org/show_bug.cgi?id=12508
+            // Tweak function body for covariant returns.
+            (*presult).fd.modifyReturns(sc, tof.next);
+        }
+    }
+    else if (!cast(ErrorSinkNull)eSink)
+    {
+        auto ts = toAutoQualChars(tx, to);
+        eSink.error(loc, "cannot implicitly convert expression `%s` of type `%s` to `%s`",
+            funcExp.toChars(), ts[0], ts[1]);
+    }
+    return m;
+}
+
+private bool checkSharedAccessBin(BinExp binExp, Scope* sc)
+{
+    const r1 = binExp.e1.checkSharedAccess(sc);
+    const r2 = binExp.e2.checkSharedAccess(sc);
+    return (r1 || r2);
+}
+
 /***************************************
  * If expression is shared, check that we can access it.
  * Give error message if not.
@@ -14060,7 +14466,106 @@  bool checkSharedAccess(Expression e, Scope* sc, bool returnRef = false)
     return check(e, returnRef);
 }
 
+/************************************************
+ * Destructors are attached to VarDeclarations.
+ * Hence, if expression returns a temp that needs a destructor,
+ * make sure and create a VarDeclaration for that temp.
+ */
+Expression addDtorHook(Expression e, Scope* sc)
+{
+    Expression visit(Expression exp)
+    {
+        return exp;
+    }
+
+    Expression visitStructLiteral(StructLiteralExp exp)
+    {
+        auto sd = exp.sd;
+        /* If struct requires a destructor, rewrite as:
+         *    (S tmp = S()),tmp
+         * so that the destructor can be hung on tmp.
+         */
+        if (sd.dtor && sc.func)
+        {
+            /* Make an identifier for the temporary of the form:
+             *   __sl%s%d, where %s is the struct name
+             */
+            char[10] buf = void;
+            const prefix = "__sl";
+            const ident = sd.ident.toString;
+            const fullLen = prefix.length + ident.length;
+            const len = fullLen < buf.length ? fullLen : buf.length;
+            buf[0 .. prefix.length] = prefix;
+            buf[prefix.length .. len] = ident[0 .. len - prefix.length];
+
+            auto tmp = copyToTemp(0, buf[0 .. len], exp);
+            Expression ae = new DeclarationExp(exp.loc, tmp);
+            Expression e = new CommaExp(exp.loc, ae, new VarExp(exp.loc, tmp));
+            e = e.expressionSemantic(sc);
+            return e;
+        }
+
+        return exp;
+    }
+
+    Expression visitCall(CallExp exp)
+    {
+        auto e1 = exp.e1;
+        auto type = exp.type;
+        /* Only need to add dtor hook if it's a type that needs destruction.
+         * Use same logic as VarDeclaration::callScopeDtor()
+         */
+
+        if (auto tf = e1.type.isTypeFunction())
+        {
+            if (tf.isref)
+                return exp;
+        }
 
+        Type tv = type.baseElemOf();
+        if (auto ts = tv.isTypeStruct())
+        {
+            StructDeclaration sd = ts.sym;
+            if (sd.dtor)
+            {
+                /* Type needs destruction, so declare a tmp
+                 * which the back end will recognize and call dtor on
+                 */
+                auto tmp = copyToTemp(0, Id.__tmpfordtor.toString(), exp);
+                auto de = new DeclarationExp(exp.loc, tmp);
+                auto ve = new VarExp(exp.loc, tmp);
+                Expression e = new CommaExp(exp.loc, de, ve);
+                e = e.expressionSemantic(sc);
+                return e;
+            }
+        }
+
+        return exp;
+    }
+
+    Expression visitCast(CastExp exp)
+    {
+        if (exp.to.toBasetype().ty == Tvoid)        // look past the cast(void)
+            exp.e1 = exp.e1.addDtorHook(sc);
+        return exp;
+    }
+
+    Expression visitComma(CommaExp exp)
+    {
+        exp.e2 = exp.e2.addDtorHook(sc);
+        return exp;
+    }
+
+    switch(e.op)
+    {
+        default: return visit(e);
+
+        case EXP.structLiteral:    return visitStructLiteral(e.isStructLiteralExp());
+        case EXP.call:             return visitCall(e.isCallExp());
+        case EXP.cast_:            return visitCast(e.isCastExp());
+        case EXP.comma:            return visitComma(e.isCommaExp());
+    }
+}
 
 /****************************************************
  * Determine if `exp`, which gets its address taken, can do so safely.
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 99848d80643..edf113e2160 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -25,6 +25,7 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.blockexit;
 import dmd.gluelayer;
+import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.delegatize;
diff --git a/gcc/d/dmd/globals.h b/gcc/d/dmd/globals.h
index 5c21be186d8..4284f858466 100644
--- a/gcc/d/dmd/globals.h
+++ b/gcc/d/dmd/globals.h
@@ -274,7 +274,6 @@  struct CompileEnv
     DString timestamp;
     d_bool previewIn;
     d_bool ddocOutput;
-    d_bool shortenedMethods;
 };
 
 struct Global
diff --git a/gcc/d/dmd/gluelayer.d b/gcc/d/dmd/gluelayer.d
index 1793700463c..756c0e523f9 100644
--- a/gcc/d/dmd/gluelayer.d
+++ b/gcc/d/dmd/gluelayer.d
@@ -39,9 +39,6 @@  version (NoBackend)
             return null;
         }
 
-        // toir
-        void toObjFile(Dsymbol ds, bool multiobj)   {}
-
         extern(C++) abstract class ObjcGlue
         {
             static void initialize() {}
@@ -59,7 +56,6 @@  else version (IN_GCC)
     extern (C++)
     {
         Statement asmSemantic(AsmStatement s, Scope* sc);
-        void toObjFile(Dsymbol ds, bool multiobj);
     }
 
     // stubs
@@ -76,5 +72,4 @@  else
     public import dmd.backend.code_x86 : code;
     public import dmd.iasm : asmSemantic;
     public import dmd.objc_glue : ObjcGlue;
-    public import dmd.toobj : toObjFile;
 }
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 28c7c2bb52e..632c0d0a682 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -20,6 +20,7 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.dcast;
 import dmd.declaration;
+import dmd.dinterpret;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 882f2eac06c..a1214b2623e 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -50,7 +50,6 @@  struct CompileEnv
 
     bool previewIn;          /// `in` means `[ref] scope const`, accepts rvalues
     bool ddocOutput;         /// collect embedded documentation comments
-    bool shortenedMethods = true;   /// allow => in normal function declarations
     bool masm;               /// use MASM inline asm syntax
 }
 
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 6af140f7491..8860f143715 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -24,6 +24,7 @@  import dmd.astenums;
 import dmd.ast_node;
 import dmd.gluelayer;
 import dmd.dclass;
+import dmd.dcast;
 import dmd.declaration;
 import dmd.denum;
 import dmd.dmangle;
@@ -4404,10 +4405,13 @@  extern (C++) final class TypeFunction : TypeNext
      * Params:
      *  tthis = type of `this` parameter, null if none
      *  p = parameter to this function
+     *  outerVars = context variables p could escape into, if any
+     *  indirect = is this for an indirect or virtual function call?
      * Returns:
      *  storage class with STC.scope_ or STC.return_ OR'd in
      */
-    StorageClass parameterStorageClass(Type tthis, Parameter p)
+    StorageClass parameterStorageClass(Type tthis, Parameter p, VarDeclarations* outerVars = null,
+        bool indirect = false)
     {
         //printf("parameterStorageClass(p: %s)\n", p.toChars());
         auto stc = p.storageClass;
@@ -4441,6 +4445,15 @@  extern (C++) final class TypeFunction : TypeNext
         // See if p can escape via any of the other parameters
         if (purity == PURE.weak)
         {
+            /*
+             * Indirect calls may escape p through a nested context
+             * See:
+             *   https://issues.dlang.org/show_bug.cgi?id=24212
+             *   https://issues.dlang.org/show_bug.cgi?id=24213
+             */
+            if (indirect)
+                return stc;
+
             // Check escaping through parameters
             foreach (i, fparam; parameterList)
             {
@@ -4478,6 +4491,16 @@  extern (C++) final class TypeFunction : TypeNext
                         return stc;
                 }
             }
+
+            // Check escaping through nested context
+            if (outerVars && this.isMutable())
+            {
+                foreach (VarDeclaration v; *outerVars)
+                {
+                    if (v.hasPointers())
+                        return stc;
+                }
+            }
         }
 
         // Check escaping through return value
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index e72d9187ca4..675e944050b 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -610,7 +610,7 @@  public:
     void purityLevel();
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
-    StorageClass parameterStorageClass(Parameter *p);
+    StorageClass parameterStorageClass(Type* tthis, Parameter *p, VarDeclarations* outerVars = nullptr, bool indirect = false);
     Type *addStorageClass(StorageClass stc) override;
 
     Type *substWildTo(unsigned mod) override;
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index d108cffd392..0065b016f83 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -16,6 +16,7 @@  import core.stdc.stdio;
 import dmd.astenums;
 import dmd.constfold;
 import dmd.ctfeexpr;
+import dmd.dcast;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 9a13d5c254e..51e522d71e4 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1223,11 +1223,15 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
             }
             else if (added & STC.ref_)
             {
-                // accept for legacy compatibility
-                //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
+                // accept using `in ref` for legacy compatibility
             }
             else
-                error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
+            {
+                version (IN_GCC)
+                    error("attribute `scope` cannot be applied with `in`, use `-fpreview=in` instead");
+                else
+                    error("attribute `scope` cannot be applied with `in`, use `-preview=in` instead");
+            }
             return orig;
         }
 
@@ -1244,11 +1248,15 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
             }
             else if (orig & STC.ref_)
             {
-                // accept for legacy compatibility
-                //deprecation("using `in ref` is deprecated, use `-preview=in` and `in` instead");
+                // accept using `in ref` for legacy compatibility
             }
             else
-                error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
+            {
+                version (IN_GCC)
+                    error("attribute `in` cannot be added after `scope`: remove `scope` and use `-fpreview=in`");
+                else
+                    error("attribute `in` cannot be added after `scope`: remove `scope` and use `-preview=in`");
+            }
             return orig;
         }
 
@@ -5203,8 +5211,6 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         case TOK.goesTo:
             if (requireDo)
                 error("missing `do { ... }` after `in` or `out`");
-            if (!compileEnv.shortenedMethods)
-                error("=> shortened method not enabled, compile with compiler switch `-preview=shortenedMethods`");
             const returnloc = token.loc;
             nextToken();
             f.fbody = new AST.ReturnStatement(returnloc, parseExpression());
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index 2f1839cdac1..0b0ca916db2 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -412,7 +412,12 @@  private extern(C++) final class Semantic3Visitor : Visitor
                     if (!global.params.useTypeInfo || !Type.dtypeinfo || !Type.typeinfotypelist)
                     {
                         if (!global.params.useTypeInfo)
-                            .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars);
+                        {
+                            version (IN_GCC)
+                                .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with `-fno-rtti`", funcdecl.kind, funcdecl.toPrettyChars);
+                            else
+                                .error(funcdecl.loc, "%s `%s` D-style variadic functions cannot be used with -betterC", funcdecl.kind, funcdecl.toPrettyChars);
+                        }
                         else if (!Type.typeinfotypelist)
                             .error(funcdecl.loc, "%s `%s` `object.TypeInfo_Tuple` could not be found, but is implicitly used in D-style variadic functions", funcdecl.kind, funcdecl.toPrettyChars);
                         else
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 962ef625f5b..d43d915e2e3 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -3483,7 +3483,10 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             // https://issues.dlang.org/show_bug.cgi?id=23159
             if (!global.params.useExceptions)
             {
-                error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok));
+                version (IN_GCC)
+                    error(oss.loc, "`%s` cannot be used with `-fno-exceptions`", Token.toChars(oss.tok));
+                else
+                    error(oss.loc, "`%s` cannot be used with -betterC", Token.toChars(oss.tok));
                 return setError();
             }
 
diff --git a/gcc/d/dmd/staticcond.d b/gcc/d/dmd/staticcond.d
index 45e777375a0..923f1a99e80 100644
--- a/gcc/d/dmd/staticcond.d
+++ b/gcc/d/dmd/staticcond.d
@@ -12,6 +12,7 @@ 
 module dmd.staticcond;
 
 import dmd.arraytypes;
+import dmd.dinterpret;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
diff --git a/gcc/d/dmd/templateparamsem.d b/gcc/d/dmd/templateparamsem.d
index de40c1f2bb2..7762363c8d6 100644
--- a/gcc/d/dmd/templateparamsem.d
+++ b/gcc/d/dmd/templateparamsem.d
@@ -12,6 +12,7 @@ 
 module dmd.templateparamsem;
 
 import dmd.arraytypes;
+import dmd.dinterpret;
 import dmd.dsymbol;
 import dmd.dscope;
 import dmd.dtemplate;
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 254900e6030..ca2af79dde4 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -24,6 +24,7 @@  import dmd.canthrow;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dimport;
+import dmd.dinterpret;
 import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index fe54e293750..bbe11f63d4b 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -27,6 +27,7 @@  import dmd.dclass;
 import dmd.declaration;
 import dmd.denum;
 import dmd.dimport;
+import dmd.dinterpret;
 import dmd.dmangle;
 import dmd.dmodule;
 import dmd.dscope;
@@ -4305,6 +4306,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
                 && d.isFuncDeclaration().objc.selector)
             {
                 auto classRef = new ObjcClassReferenceExp(e.loc, mt.sym);
+                classRef.type = objc.getRuntimeMetaclass(mt.sym).getType();
                 return new DotVarExp(e.loc, classRef, d).expressionSemantic(sc);
             }
             else if (d.needThis() && sc.intypeof != 1)
diff --git a/gcc/d/dmd/typinf.d b/gcc/d/dmd/typinf.d
index 6e05695d6c8..485ca3ff66c 100644
--- a/gcc/d/dmd/typinf.d
+++ b/gcc/d/dmd/typinf.d
@@ -4,7 +4,7 @@ 
  * Copyright:   Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
- * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typeinf.d, _typeinf.d)
+ * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/typinf.d, _typinf.d)
  * Documentation:  https://dlang.org/phobos/dmd_typinf.html
  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/typinf.d
  */
@@ -20,10 +20,8 @@  import dmd.dstruct;
 import dmd.errors;
 import dmd.expression;
 import dmd.globals;
-import dmd.gluelayer;
 import dmd.location;
 import dmd.mtype;
-import dmd.visitor;
 import core.stdc.stdio;
 
 /****************************************************
@@ -34,9 +32,10 @@  import core.stdc.stdio;
  *      loc   = the location for reporting line numbers in errors
  *      torig = the type to generate the `TypeInfo` object for
  *      sc    = the scope
- *      genObjCode = if true, object code will be generated for the obtained TypeInfo
+ * Returns:
+ *      true if `TypeInfo` was generated and needs compiling to object file
  */
-extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc, bool genObjCode = true)
+extern (C++) bool genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope* sc)
 {
     // printf("genTypeInfo() %s\n", torig.toChars());
 
@@ -67,6 +66,7 @@  extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
     }
 
     Type t = torig.merge2(); // do this since not all Type's are merge'd
+    bool needsCodegen = false;
     if (!t.vtinfo)
     {
         if (t.isShared()) // does both 'shared' and 'shared const'
@@ -84,25 +84,13 @@  extern (C++) void genTypeInfo(Expression e, const ref Loc loc, Type torig, Scope
         // ClassInfos are generated as part of ClassDeclaration codegen
         const isUnqualifiedClassInfo = (t.ty == Tclass && !t.mod);
 
-        // generate a COMDAT for other TypeInfos not available as builtins in
-        // druntime
-        if (!isUnqualifiedClassInfo && !builtinTypeInfo(t) && genObjCode)
-        {
-            if (sc) // if in semantic() pass
-            {
-                // Find module that will go all the way to an object file
-                Module m = sc._module.importedFrom;
-                m.members.push(t.vtinfo);
-            }
-            else // if in obj generation pass
-            {
-                toObjFile(t.vtinfo, global.params.multiobj);
-            }
-        }
+        if (!isUnqualifiedClassInfo && !builtinTypeInfo(t))
+            needsCodegen = true;
     }
     if (!torig.vtinfo)
         torig.vtinfo = t.vtinfo; // Types aren't merged, but we can share the vtinfo's
     assert(torig.vtinfo);
+    return needsCodegen;
 }
 
 /****************************************************
@@ -158,7 +146,7 @@  private TypeInfoDeclaration getTypeInfoDeclaration(Type t)
  *      true if any part of type t is speculative.
  *      if t is null, returns false.
  */
-bool isSpeculativeType(Type t)
+extern (C++) bool isSpeculativeType(Type t)
 {
     static bool visitVector(TypeVector t)
     {
diff --git a/gcc/d/dmd/typinf.h b/gcc/d/dmd/typinf.h
new file mode 100644
index 00000000000..76f623a0a3e
--- /dev/null
+++ b/gcc/d/dmd/typinf.h
@@ -0,0 +1,22 @@ 
+
+/* Compiler implementation of the D programming language
+ * Copyright (C) 1999-2023 by The D Language Foundation, All Rights Reserved
+ * written by Walter Bright
+ * https://www.digitalmars.com
+ * Distributed under the Boost Software License, Version 1.0.
+ * https://www.boost.org/LICENSE_1_0.txt
+ * https://github.com/dlang/dmd/blob/master/src/dmd/typinf.h
+ */
+
+#pragma once
+
+#include "globals.h"
+
+class Expression;
+class Type;
+struct Scope;
+
+bool genTypeInfo(Expression *e, const Loc &loc, Type *torig, Scope *sc);
+Type *getTypeInfoType(const Loc &loc, Type *t, Scope *sc, bool genObjCode = true);
+bool isSpeculativeType(Type *t);
+bool builtinTypeInfo(Type *t);
diff --git a/gcc/testsuite/gdc.test/compilable/dbitfield.d b/gcc/testsuite/gdc.test/compilable/dbitfield.d
index e2883fdd095..7187c37410e 100644
--- a/gcc/testsuite/gdc.test/compilable/dbitfield.d
+++ b/gcc/testsuite/gdc.test/compilable/dbitfield.d
@@ -86,3 +86,16 @@  int testu()
 }
 
 static assert(testu() == 1);
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=24193
+
+union U24193 {
+    struct S {
+        int aa,bb;
+    }
+    S ss;
+    int tt:8;
+}
+
+static assert(U24193.sizeof == 8);
diff --git a/gcc/testsuite/gdc.test/compilable/deprecate14283.d b/gcc/testsuite/gdc.test/compilable/deprecate14283.d
index fc51cf3f0b6..e91db649cee 100644
--- a/gcc/testsuite/gdc.test/compilable/deprecate14283.d
+++ b/gcc/testsuite/gdc.test/compilable/deprecate14283.d
@@ -1,12 +1,12 @@ 
-// REQUIRED_ARGS:
+// REQUIRED_ARGS: -dw
 // PERMUTE_ARGS:
 class C
 {
     void bug()
     {
-        autoref!(true, C)(this);  // 'auto ref' becomes ref parameter
-        autoref!(false, Object)(super); // 'auto ref' becomes non-ref parameter
+        autoref(this);  // 'auto ref' becomes non-ref parameter
+        autoref(super); // 'auto ref' becomes non-ref parameter
     }
 }
 
-void autoref(bool result, T)(auto ref T t) { static assert(__traits(isRef, t) == result); }
+void autoref(T)(auto ref T t) { static assert(__traits(isRef, t) == false); }
diff --git a/gcc/testsuite/gdc.test/compilable/named_arguments.d b/gcc/testsuite/gdc.test/compilable/named_arguments.d
index f287ccdea95..25d84e6b83e 100644
--- a/gcc/testsuite/gdc.test/compilable/named_arguments.d
+++ b/gcc/testsuite/gdc.test/compilable/named_arguments.d
@@ -20,9 +20,21 @@  string fun2(string x = "x", string y, string z = "z")
 
 static assert(fun2(y: "y") == "xyz");
 
-// The assumption that first parameter having a default implies all parameters have a default is no longer valid,
-// so this struct constructor shouldn't be mistaken for a default constructor.
-struct SD { this(int x = 1, int y) { } }
+struct SD
+{
+	int x;
+	int y;
+
+	// The assumption that first parameter having a default implies all parameters have a default is no longer valid,
+	// so this struct constructor shouldn't be mistaken for a default constructor.
+	this(int x = 10, int y)
+	{
+		this.x = x;
+		this.y = y;
+	}
+}
+
+static assert(SD(y: 20) == SD(10, 20));
 
 // UFCS
 static assert("x".fun("y", w: "w") == "xyZw");
diff --git a/gcc/testsuite/gdc.test/compilable/test20039.d b/gcc/testsuite/gdc.test/compilable/test20039.d
index d912139d803..5b6e9afeacc 100644
--- a/gcc/testsuite/gdc.test/compilable/test20039.d
+++ b/gcc/testsuite/gdc.test/compilable/test20039.d
@@ -1,5 +1,5 @@ 
 void foo()() { }
-class bar { }
+void bar(int) { }
 
 alias bug = foo;
 alias bug = bar;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b23686.d b/gcc/testsuite/gdc.test/fail_compilation/b23686.d
new file mode 100644
index 00000000000..4c2a5bd026d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/b23686.d
@@ -0,0 +1,42 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/b23686.d(107): Error: undefined identifier `eFN1`, did you mean template `eFN0()()`?
+fail_compilation/b23686.d(107): Error: `mixin(_error_)` does not give a valid type
+fail_compilation/b23686.d(115):        while looking for match for `eload!(int, 1)`
+fail_compilation/b23686.d(121): Error: undefined identifier `FNwtf`
+fail_compilation/b23686.d(121): Error: `mixin(_error_)` does not give a valid type
+fail_compilation/b23686.d(126):        while looking for match for `load!"wtf"`
+---
+*/
+module b23686;
+
+#line 100
+
+//-------------------
+
+void eFN0()()
+{
+}
+
+void eload(I, I name,  alias T = mixin("eFN" ~ name.stringof))()
+{
+    T!()();
+}
+
+void test2()
+{
+    eload!(int,0)();
+    eload!(int,1)();
+}
+
+//-------------------
+
+void FNfoo() {}
+void load(string name, alias T = mixin("FN" ~ name))() {}
+
+void test1()
+{
+    load!"foo"();
+    load!"wtf"();
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
index 517b328e8d6..f6b49d6bd13 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
@@ -1,13 +1,13 @@ 
 /*
 TEST_OUTPUT:
 ---
+fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue
 fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified
 fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue
 ---
 */
 
-
-
 class NoGo4596
 {
     void fun()
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
index 077fa75ac77..ac520d79997 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13116.d(14): Error: returning `this` escapes a reference to parameter `this`
+fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified
 fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24208.d b/gcc/testsuite/gdc.test/fail_compilation/fail24208.d
new file mode 100644
index 00000000000..149c1386f5d
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail24208.d
@@ -0,0 +1,20 @@ 
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24208.d(19): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `escape`
+fail_compilation/fail24208.d(15):        which is not `scope` because of `escaped = p`
+---
++/
+void test() @safe
+{
+    int* escaped;
+
+    void escape(int* p) @safe
+    {
+        escaped = p;
+    }
+
+    int n;
+    escape(&n);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24212.d b/gcc/testsuite/gdc.test/fail_compilation/fail24212.d
new file mode 100644
index 00000000000..767951dafb4
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail24212.d
@@ -0,0 +1,30 @@ 
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24212.d(29): Error: reference to local variable `n` assigned to non-scope parameter `p` calling `fun`
+---
++/
+class Base
+{
+    @safe pure nothrow
+    void fun(int* p) {}
+}
+
+void test() @safe
+{
+    int* escaped;
+
+    class Escaper : Base
+    {
+        @safe pure nothrow
+        override void fun(int* p)
+        {
+            escaped = p;
+        }
+    }
+
+    int n;
+    Base base = new Escaper;
+    base.fun(&n);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24213.d b/gcc/testsuite/gdc.test/fail_compilation/fail24213.d
new file mode 100644
index 00000000000..e2af6fd1b92
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail24213.d
@@ -0,0 +1,17 @@ 
+/+
+REQUIRED_ARGS: -preview=dip1000
+TEST_OUTPUT:
+---
+fail_compilation/fail24213.d(16): Error: reference to local variable `n` assigned to non-scope parameter `p`
+---
++/
+alias Dg = void delegate(int* p) @safe pure nothrow;
+
+void main() @safe
+{
+    int* escaped;
+
+    int n;
+    Dg dg = delegate void (int* p) { escaped = p; };
+    dg(&n);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice23865.d b/gcc/testsuite/gdc.test/fail_compilation/ice23865.d
new file mode 100644
index 00000000000..44886dfb8a3
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice23865.d
@@ -0,0 +1,32 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ice23865.d(64): Error: alias `ice23865.AssignableRange.back` conflicts with alias `ice23865.AssignableRange.back` at fail_compilation/ice23865.d(58)
+---
+*/
+module ice23865;
+
+#line 50
+
+class AssignableRange
+{
+      int element;
+      int front()
+      {
+          return element;
+      }
+      alias back = front;
+
+      void front(int newValue)
+      {
+          element = newValue;
+      }
+      alias back = element;
+}
+
+void test()
+{
+      AssignableRange a = new AssignableRange();
+
+      a.back;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice24188.d b/gcc/testsuite/gdc.test/fail_compilation/ice24188.d
new file mode 100644
index 00000000000..50c06641455
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice24188.d
@@ -0,0 +1,14 @@ 
+/*
+REQUIRED_ARGS: fail_compilation/ice24188_a/ice24188_c.d
+TEST_OUTPUT:
+---
+fail_compilation/ice24188.d(9): Error: module `ice24188_c` from file fail_compilation/ice24188_a/ice24188_c.d must be imported with 'import ice24188_c;'
+---
+*/
+auto b() {
+    import fail_compilation.ice24188_a.ice24188_c : D;
+
+    struct A {
+        D e;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d b/gcc/testsuite/gdc.test/fail_compilation/ice24188_a/ice24188_c.d
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test18480.d b/gcc/testsuite/gdc.test/fail_compilation/test18480.d
index 49f306ba988..848cd388303 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test18480.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test18480.d
@@ -3,6 +3,7 @@ 
 TEST_OUTPUT:
 ---
 fail_compilation/imports/test18480a.d(2): Error: `alias TestTemplate = TestTemplate;` cannot alias itself, use a qualified name to create an overload set
+fail_compilation/imports/test18480a.d(2): Error: alias `test18480a.TestTemplate` conflicts with alias `test18480a.TestTemplate` at fail_compilation/imports/test18480a.d(1)
 ---
 https://issues.dlang.org/show_bug.cgi?id=18480
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24157.d b/gcc/testsuite/gdc.test/fail_compilation/test24157.d
new file mode 100644
index 00000000000..5022014a9a1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24157.d
@@ -0,0 +1,28 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=24157
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24157.d(23): Error: `p.self()` is not an lvalue and cannot be modified
+fail_compilation/test24157.d(27): Error: `p.unshared()` is not an lvalue and cannot be modified
+---
+*/
+
+class Promise {
+    auto ref self() {
+        return this;
+    }
+
+    auto ref unshared() shared {
+        return cast() this;
+    }
+}
+
+
+void testThis(Promise p) {
+    auto ptr = &p.self(); // must not return a ref to the Promise class ref
+}
+
+void testCastThis(shared Promise p) {
+    auto ptr = &p.unshared(); // ditto
+}
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 2a0baf09a4b..235db4b2ef1 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-e48bc0987dfec35bc76a3015ee3e85906ce86dfd
+643b1261bba0757d97efa3ff1f63e461271eb000
 
 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/Makefile.am b/libphobos/libdruntime/Makefile.am
index f57c640f363..23205fd3301 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -261,7 +261,8 @@  DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
 
 DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
-	core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \
+	core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
+	core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
 	core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
 	core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
 	core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
@@ -269,7 +270,8 @@  DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
 	core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
 	core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
-	core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \
+	core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
+	core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
 	core/sys/freebsd/unistd.d
 
 DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
@@ -278,6 +280,7 @@  DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
 	core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \
 	core/sys/linux/input.d core/sys/linux/input_event_codes.d \
 	core/sys/linux/io_uring.d core/sys/linux/link.d \
+	core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \
 	core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \
 	core/sys/linux/perf_event.d core/sys/linux/sched.d \
 	core/sys/linux/stdio.d core/sys/linux/string.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 363a4a09aa1..410245d71ca 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -327,6 +327,7 @@  am__objects_11 = core/sys/bionic/err.lo core/sys/bionic/fcntl.lo \
 @DRUNTIME_OS_ANDROID_TRUE@am__objects_12 = $(am__objects_11)
 am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
 	core/sys/freebsd/err.lo core/sys/freebsd/execinfo.lo \
+	core/sys/freebsd/ifaddrs.lo core/sys/freebsd/net/if_dl.lo \
 	core/sys/freebsd/netinet/in_.lo core/sys/freebsd/pthread_np.lo \
 	core/sys/freebsd/stdlib.lo core/sys/freebsd/string.lo \
 	core/sys/freebsd/sys/_bitset.lo \
@@ -336,7 +337,8 @@  am__objects_13 = core/sys/freebsd/config.lo core/sys/freebsd/dlfcn.lo \
 	core/sys/freebsd/sys/elf_common.lo \
 	core/sys/freebsd/sys/event.lo core/sys/freebsd/sys/link_elf.lo \
 	core/sys/freebsd/sys/mman.lo core/sys/freebsd/sys/mount.lo \
-	core/sys/freebsd/sys/sysctl.lo core/sys/freebsd/time.lo \
+	core/sys/freebsd/sys/socket.lo core/sys/freebsd/sys/sysctl.lo \
+	core/sys/freebsd/sys/types.lo core/sys/freebsd/time.lo \
 	core/sys/freebsd/unistd.lo
 @DRUNTIME_OS_FREEBSD_TRUE@am__objects_14 = $(am__objects_13)
 am__objects_15 = core/sys/netbsd/dlfcn.lo core/sys/netbsd/err.lo \
@@ -366,6 +368,8 @@  am__objects_19 = core/sys/linux/config.lo core/sys/linux/dlfcn.lo \
 	core/sys/linux/fs.lo core/sys/linux/ifaddrs.lo \
 	core/sys/linux/input.lo core/sys/linux/input_event_codes.lo \
 	core/sys/linux/io_uring.lo core/sys/linux/link.lo \
+	core/sys/linux/linux/if_arp.lo \
+	core/sys/linux/linux/if_packet.lo \
 	core/sys/linux/netinet/in_.lo core/sys/linux/netinet/tcp.lo \
 	core/sys/linux/perf_event.lo core/sys/linux/sched.lo \
 	core/sys/linux/stdio.lo core/sys/linux/string.lo \
@@ -931,7 +935,8 @@  DRUNTIME_DSOURCES_DRAGONFLYBSD = core/sys/dragonflybsd/dlfcn.d \
 DRUNTIME_DSOURCES_ELF = core/sys/elf/package.d
 DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/dlfcn.d core/sys/freebsd/err.d \
-	core/sys/freebsd/execinfo.d core/sys/freebsd/netinet/in_.d \
+	core/sys/freebsd/execinfo.d core/sys/freebsd/ifaddrs.d \
+	core/sys/freebsd/net/if_dl.d core/sys/freebsd/netinet/in_.d \
 	core/sys/freebsd/pthread_np.d core/sys/freebsd/stdlib.d \
 	core/sys/freebsd/string.d core/sys/freebsd/sys/_bitset.d \
 	core/sys/freebsd/sys/_cpuset.d core/sys/freebsd/sys/cdefs.d \
@@ -939,7 +944,8 @@  DRUNTIME_DSOURCES_FREEBSD = core/sys/freebsd/config.d \
 	core/sys/freebsd/sys/elf64.d core/sys/freebsd/sys/elf_common.d \
 	core/sys/freebsd/sys/event.d core/sys/freebsd/sys/link_elf.d \
 	core/sys/freebsd/sys/mman.d core/sys/freebsd/sys/mount.d \
-	core/sys/freebsd/sys/sysctl.d core/sys/freebsd/time.d \
+	core/sys/freebsd/sys/socket.d core/sys/freebsd/sys/sysctl.d \
+	core/sys/freebsd/sys/types.d core/sys/freebsd/time.d \
 	core/sys/freebsd/unistd.d
 
 DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
@@ -948,6 +954,7 @@  DRUNTIME_DSOURCES_LINUX = core/sys/linux/config.d \
 	core/sys/linux/fcntl.d core/sys/linux/fs.d core/sys/linux/ifaddrs.d \
 	core/sys/linux/input.d core/sys/linux/input_event_codes.d \
 	core/sys/linux/io_uring.d core/sys/linux/link.d \
+	core/sys/linux/linux/if_arp.d core/sys/linux/linux/if_packet.d \
 	core/sys/linux/netinet/in_.d core/sys/linux/netinet/tcp.d \
 	core/sys/linux/perf_event.d core/sys/linux/sched.d \
 	core/sys/linux/stdio.d core/sys/linux/string.d \
@@ -1593,6 +1600,11 @@  core/sys/freebsd/config.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/freebsd/dlfcn.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/freebsd/err.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/freebsd/execinfo.lo: core/sys/freebsd/$(am__dirstamp)
+core/sys/freebsd/ifaddrs.lo: core/sys/freebsd/$(am__dirstamp)
+core/sys/freebsd/net/$(am__dirstamp):
+	@$(MKDIR_P) core/sys/freebsd/net
+	@: > core/sys/freebsd/net/$(am__dirstamp)
+core/sys/freebsd/net/if_dl.lo: core/sys/freebsd/net/$(am__dirstamp)
 core/sys/freebsd/netinet/$(am__dirstamp):
 	@$(MKDIR_P) core/sys/freebsd/netinet
 	@: > core/sys/freebsd/netinet/$(am__dirstamp)
@@ -1617,7 +1629,9 @@  core/sys/freebsd/sys/link_elf.lo:  \
 	core/sys/freebsd/sys/$(am__dirstamp)
 core/sys/freebsd/sys/mman.lo: core/sys/freebsd/sys/$(am__dirstamp)
 core/sys/freebsd/sys/mount.lo: core/sys/freebsd/sys/$(am__dirstamp)
+core/sys/freebsd/sys/socket.lo: core/sys/freebsd/sys/$(am__dirstamp)
 core/sys/freebsd/sys/sysctl.lo: core/sys/freebsd/sys/$(am__dirstamp)
+core/sys/freebsd/sys/types.lo: core/sys/freebsd/sys/$(am__dirstamp)
 core/sys/freebsd/time.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/freebsd/unistd.lo: core/sys/freebsd/$(am__dirstamp)
 core/sys/netbsd/$(am__dirstamp):
@@ -1685,6 +1699,12 @@  core/sys/linux/input.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/input_event_codes.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/io_uring.lo: core/sys/linux/$(am__dirstamp)
 core/sys/linux/link.lo: core/sys/linux/$(am__dirstamp)
+core/sys/linux/linux/$(am__dirstamp):
+	@$(MKDIR_P) core/sys/linux/linux
+	@: > core/sys/linux/linux/$(am__dirstamp)
+core/sys/linux/linux/if_arp.lo: core/sys/linux/linux/$(am__dirstamp)
+core/sys/linux/linux/if_packet.lo:  \
+	core/sys/linux/linux/$(am__dirstamp)
 core/sys/linux/netinet/$(am__dirstamp):
 	@$(MKDIR_P) core/sys/linux/netinet
 	@: > core/sys/linux/netinet/$(am__dirstamp)
@@ -2055,12 +2075,16 @@  mostlyclean-compile:
 	-rm -f core/sys/elf/*.lo
 	-rm -f core/sys/freebsd/*.$(OBJEXT)
 	-rm -f core/sys/freebsd/*.lo
+	-rm -f core/sys/freebsd/net/*.$(OBJEXT)
+	-rm -f core/sys/freebsd/net/*.lo
 	-rm -f core/sys/freebsd/netinet/*.$(OBJEXT)
 	-rm -f core/sys/freebsd/netinet/*.lo
 	-rm -f core/sys/freebsd/sys/*.$(OBJEXT)
 	-rm -f core/sys/freebsd/sys/*.lo
 	-rm -f core/sys/linux/*.$(OBJEXT)
 	-rm -f core/sys/linux/*.lo
+	-rm -f core/sys/linux/linux/*.$(OBJEXT)
+	-rm -f core/sys/linux/linux/*.lo
 	-rm -f core/sys/linux/netinet/*.$(OBJEXT)
 	-rm -f core/sys/linux/netinet/*.lo
 	-rm -f core/sys/linux/sys/*.$(OBJEXT)
@@ -2231,9 +2255,11 @@  clean-libtool:
 	-rm -rf core/sys/dragonflybsd/sys/.libs core/sys/dragonflybsd/sys/_libs
 	-rm -rf core/sys/elf/.libs core/sys/elf/_libs
 	-rm -rf core/sys/freebsd/.libs core/sys/freebsd/_libs
+	-rm -rf core/sys/freebsd/net/.libs core/sys/freebsd/net/_libs
 	-rm -rf core/sys/freebsd/netinet/.libs core/sys/freebsd/netinet/_libs
 	-rm -rf core/sys/freebsd/sys/.libs core/sys/freebsd/sys/_libs
 	-rm -rf core/sys/linux/.libs core/sys/linux/_libs
+	-rm -rf core/sys/linux/linux/.libs core/sys/linux/linux/_libs
 	-rm -rf core/sys/linux/netinet/.libs core/sys/linux/netinet/_libs
 	-rm -rf core/sys/linux/sys/.libs core/sys/linux/sys/_libs
 	-rm -rf core/sys/netbsd/.libs core/sys/netbsd/_libs
@@ -2394,9 +2420,11 @@  distclean-generic:
 	-rm -f core/sys/dragonflybsd/sys/$(am__dirstamp)
 	-rm -f core/sys/elf/$(am__dirstamp)
 	-rm -f core/sys/freebsd/$(am__dirstamp)
+	-rm -f core/sys/freebsd/net/$(am__dirstamp)
 	-rm -f core/sys/freebsd/netinet/$(am__dirstamp)
 	-rm -f core/sys/freebsd/sys/$(am__dirstamp)
 	-rm -f core/sys/linux/$(am__dirstamp)
+	-rm -f core/sys/linux/linux/$(am__dirstamp)
 	-rm -f core/sys/linux/netinet/$(am__dirstamp)
 	-rm -f core/sys/linux/sys/$(am__dirstamp)
 	-rm -f core/sys/netbsd/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/sys/linux/linux/if_arp.d b/libphobos/libdruntime/core/sys/linux/linux/if_arp.d
new file mode 100644
index 00000000000..dea0ab57a17
--- /dev/null
+++ b/libphobos/libdruntime/core/sys/linux/linux/if_arp.d
@@ -0,0 +1,136 @@ 
+//Written in the D programming language
+
+/++
+    D header file for Linux's linux/if_arp.h.
+
+    Copyright: Copyright 2023
+    License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+    Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
+ +/
+module core.sys.linux.linux.if_arp;
+
+version (linux):
+extern(C):
+@nogc:
+nothrow:
+
+import core.sys.posix.net.if_ : IF_NAMESIZE;
+import core.sys.posix.sys.socket : sockaddr;
+
+enum : ushort
+{
+    ARPHRD_NETROM     = 0,
+    ARPHRD_ETHER      = 1,
+    ARPHRD_EETHER     = 2,
+    ARPHRD_AX25       = 3,
+    ARPHRD_PRONET     = 4,
+    ARPHRD_CHAOS      = 5,
+    ARPHRD_IEEE802    = 6,
+    ARPHRD_ARCNET     = 7,
+    ARPHRD_APPLETLK   = 8,
+    ARPHRD_DLCI       =15,
+    ARPHRD_ATM        =19,
+    ARPHRD_METRICOM   = 23,
+    ARPHRD_IEEE1394   = 24,
+    ARPHRD_EUI64      = 27,
+    ARPHRD_INFINIBAND = 32,
+
+    ARPHRD_SLIP    = 256,
+    ARPHRD_CSLIP   = 257,
+    ARPHRD_SLIP6   = 258,
+    ARPHRD_CSLIP6  = 259,
+    ARPHRD_RSRVD   = 260,
+    ARPHRD_ADAPT   = 264,
+    ARPHRD_ROSE    = 270,
+    ARPHRD_X25     = 271,
+    ARPHRD_HWX25   = 272,
+    ARPHRD_CAN     = 280,
+    ARPHRD_MCTP    = 290,
+    ARPHRD_PPP     = 512,
+    ARPHRD_CISCO   = 513,
+    ARPHRD_HDLC    = ARPHRD_CISCO,
+    ARPHRD_LAPB    = 516,
+    ARPHRD_DDCMP   = 517,
+    ARPHRD_RAWHDLC = 518,
+    ARPHRD_RAWIP   = 519,
+
+    ARPHRD_TUNNEL   = 768,
+    ARPHRD_TUNNEL6  = 769,
+    ARPHRD_FRAD     = 770,
+    ARPHRD_SKIP     = 771,
+    ARPHRD_LOOPBACK = 772,
+    ARPHRD_LOCALTLK = 773,
+    ARPHRD_FDDI     = 774,
+    ARPHRD_BIF      = 775,
+    ARPHRD_SIT      = 776,
+    ARPHRD_IPDDP    = 777,
+    ARPHRD_IPGRE    = 778,
+    ARPHRD_PIMREG   = 779,
+    ARPHRD_HIPPI    = 780,
+    ARPHRD_ASH      = 781,
+    ARPHRD_ECONET   = 782,
+    ARPHRD_IRDA     = 783,
+
+    ARPHRD_FCPP     = 784,
+    ARPHRD_FCAL     = 785,
+    ARPHRD_FCPL     = 786,
+    ARPHRD_FCFABRIC = 787,
+
+    ARPHRD_IEEE802_TR         = 800,
+    ARPHRD_IEEE80211          = 801,
+    ARPHRD_IEEE80211_PRISM    = 802,
+    ARPHRD_IEEE80211_RADIOTAP = 803,
+    ARPHRD_IEEE802154         = 804,
+    ARPHRD_IEEE802154_MONITOR = 805,
+
+    ARPHRD_PHONET      = 820,
+    ARPHRD_PHONET_PIPE = 821,
+    ARPHRD_CAIF        = 822,
+    ARPHRD_IP6GRE      = 823,
+    ARPHRD_NETLINK     = 824,
+    ARPHRD_6LOWPAN     = 825,
+    ARPHRD_VSOCKMON    = 826,
+
+    ARPHRD_VOID = 0xFFFF,
+    ARPHRD_NONE = 0xFFFE,
+}
+
+enum : ushort
+{
+    ARPOP_REQUEST   = 1,
+    ARPOP_REPLY     = 2,
+    ARPOP_RREQUEST  = 3,
+    ARPOP_RREPLY    = 4,
+    ARPOP_InREQUEST = 8,
+    ARPOP_InREPLY   = 9,
+    ARPOP_NAK       = 10,
+}
+
+struct arpreq
+{
+    sockaddr          arp_pa;
+    sockaddr          arp_ha;
+    int               arp_flags;
+    sockaddr          arp_netmask;
+    char[IF_NAMESIZE] arp_dev;
+}
+
+enum
+{
+    ATF_COM         = 0x02,
+    ATF_PERM        = 0x04,
+    ATF_PUBL        = 0x08,
+    ATF_USETRAILERS = 0x10,
+    ATF_NETMASK     = 0x20,
+
+    ATF_DONTPUB     = 0x40,
+}
+
+struct arphdr
+{
+    ushort ar_hrd;
+    ushort ar_pro;
+    ubyte  ar_hln;
+    ubyte  ar_pln;
+    ushort ar_op;
+}
diff --git a/libphobos/libdruntime/core/sys/linux/linux/if_packet.d b/libphobos/libdruntime/core/sys/linux/linux/if_packet.d
new file mode 100644
index 00000000000..b50b6a33914
--- /dev/null
+++ b/libphobos/libdruntime/core/sys/linux/linux/if_packet.d
@@ -0,0 +1,315 @@ 
+//Written in the D programming language
+
+/++
+    D header file for Linux's linux/if_packet.h.
+
+    Copyright: Copyright 2023
+    License:   $(HTTP www.boost.org/LICENSE_1_0.txt, Boost License 1.0).
+    Authors:   $(HTTP jmdavisprog.com, Jonathan M Davis)
+ +/
+module core.sys.linux.linux.if_packet;
+
+version (linux):
+extern(C):
+@nogc:
+nothrow:
+
+import core.stdc.config : c_ulong;
+import core.sys.posix.sys.socket : sa_family_t;
+
+struct sockaddr_pkt
+{
+    sa_family_t spkt_family;
+    ubyte[14]   spkt_device;
+    ushort      spkt_protocol;
+}
+
+struct sockaddr_ll
+{
+    sa_family_t sll_family;
+    ushort      sll_protocol;
+    int         sll_ifindex;
+    ushort      sll_hatype;
+    ubyte       sll_pkttype;
+    ubyte       sll_halen;
+    ubyte[8]    sll_addr;
+}
+
+enum : ubyte
+{
+    PACKET_HOST      = 0,
+    PACKET_BROADCAST = 1,
+    PACKET_MULTICAST = 2,
+    PACKET_OTHERHOST = 3,
+    PACKET_OUTGOING  = 4,
+    PACKET_LOOPBACK  = 5,
+    PACKET_USER      = 6,
+    PACKET_KERNEL    = 7,
+}
+
+enum
+{
+    PACKET_ADD_MEMBERSHIP  = 1,
+    PACKET_DROP_MEMBERSHIP = 2,
+    PACKET_RECV_OUTPUT     = 3,
+
+    PACKET_RX_RING         = 5,
+    PACKET_STATISTICS      = 6,
+    PACKET_COPY_THRESH     = 7,
+    PACKET_AUXDATA         = 8,
+    PACKET_ORIGDEV         = 9,
+    PACKET_VERSION         = 10,
+    PACKET_HDRLEN          = 11,
+    PACKET_RESERVE         = 12,
+    PACKET_TX_RING         = 13,
+    PACKET_LOSS            = 14,
+    PACKET_VNET_HDR        = 15,
+    PACKET_TX_TIMESTAMP    = 16,
+    PACKET_TIMESTAMP       = 17,
+    PACKET_FANOUT          = 18,
+    PACKET_TX_HAS_OFF      = 19,
+    PACKET_QDISC_BYPASS    = 20,
+    PACKET_ROLLOVER_STATS  = 21,
+    PACKET_FANOUT_DATA     = 22,
+    PACKET_IGNORE_OUTGOING = 23,
+    PACKET_VNET_HDR_SZ     = 24,
+
+    PACKET_FANOUT_HASH     = 0,
+    PACKET_FANOUT_LB       = 1,
+    PACKET_FANOUT_CPU      = 2,
+    PACKET_FANOUT_ROLLOVER = 3,
+    PACKET_FANOUT_RND      = 4,
+    PACKET_FANOUT_QM       = 5,
+    PACKET_FANOUT_CBPF     = 6,
+    PACKET_FANOUT_EBPF     = 7,
+
+    PACKET_FANOUT_FLAG_ROLLOVER        = 0x1000,
+    PACKET_FANOUT_FLAG_UNIQUEID        = 0x2000,
+    PACKET_FANOUT_FLAG_IGNORE_OUTGOING = 0x4000,
+    PACKET_FANOUT_FLAG_DEFRAG          = 0x8000,
+}
+
+struct tpacket_stats
+{
+    uint tp_packets;
+    uint tp_drops;
+}
+
+struct tpacket_stats_v3
+{
+    uint tp_packets;
+    uint tp_drops;
+    uint tp_freeze_q_cnt;
+}
+
+struct tpacket_rollover_stats
+{
+    align(8):
+    ulong tp_all;
+    ulong tp_huge;
+    ulong tp_failed;
+}
+
+union tpacket_stats_u
+{
+    tpacket_stats    stats1;
+    tpacket_stats_v3 stats3;
+}
+
+struct tpacket_auxdata
+{
+    uint   tp_status;
+    uint   tp_len;
+    uint   tp_snaplen;
+    ushort tp_mac;
+    ushort tp_net;
+    ushort tp_vlan_tci;
+    ushort tp_vlan_tpid;
+}
+
+enum : uint
+{
+    TP_STATUS_KERNEL          = 0,
+    TP_STATUS_USER            = 1 << 0,
+    TP_STATUS_COPY            = 1 << 1,
+    TP_STATUS_LOSING          = 1 << 2,
+    TP_STATUS_CSUMNOTREADY    = 1 << 3,
+    TP_STATUS_VLAN_VALID      = 1 << 4,
+    TP_STATUS_BLK_TMO         = 1 << 5,
+    TP_STATUS_VLAN_TPID_VALID = 1 << 6,
+    TP_STATUS_CSUM_VALID      = 1 << 7,
+    TP_STATUS_GSO_TCP         = 1 << 8,
+}
+
+enum : uint
+{
+    TP_STATUS_AVAILABLE    = 0,
+    TP_STATUS_SEND_REQUEST = 1 << 0,
+    TP_STATUS_SENDING      = 1 << 1,
+    TP_STATUS_WRONG_FORMAT = 1 << 2,
+}
+
+enum : uint
+{
+    TP_STATUS_TS_SOFTWARE     = 1 << 29,
+    TP_STATUS_TS_RAW_HARDWARE = 1U << 31,
+}
+
+enum uint TP_FT_REQ_FILL_RXHASH = 0x1;
+
+struct tpacket_hdr
+{
+    c_ulong tp_status;
+    uint    tp_len;
+    uint    tp_snaplen;
+    ushort  tp_mac;
+    ushort  tp_net;
+    uint    tp_sec;
+    uint    tp_usec;
+}
+
+enum TPACKET_ALIGNMENT = 16;
+size_t TPACKET_ALIGN(size_t x) { return (x + TPACKET_ALIGNMENT - 1) &~ (TPACKET_ALIGNMENT - 1); }
+enum TPACKET_HDRLEN = TPACKET_ALIGN(tpacket_hdr.sizeof) + sockaddr_ll.sizeof;
+
+struct tpacket2_hdr
+{
+    uint     tp_status;
+    uint     tp_len;
+    uint     tp_snaplen;
+    ushort   tp_mac;
+    ushort   tp_net;
+    uint     tp_sec;
+    uint     tp_nsec;
+    ushort   tp_vlan_tci;
+    ushort   tp_vlan_tpid;
+    ubyte[4] tp_padding;
+}
+
+struct tpacket_hdr_variant1
+{
+    uint   tp_rxhash;
+    uint   tp_vlan_tci;
+    ushort tp_vlan_tpid;
+    ushort tp_padding;
+}
+
+struct tpacket3_hdr
+{
+    uint   tp_next_offset;
+    uint   tp_sec;
+    uint   tp_nsec;
+    uint   tp_snaplen;
+    uint   tp_len;
+    uint   tp_status;
+    ushort tp_mac;
+    ushort tp_net;
+
+    union
+    {
+        tpacket_hdr_variant1 hv1;
+    }
+
+    ubyte[8] tp_padding;
+}
+
+struct tpacket_bd_ts
+{
+    uint ts_sec;
+
+    union
+    {
+        uint ts_usec;
+        uint ts_nsec;
+    }
+}
+
+struct tpacket_hdr_v1
+{
+    uint block_status;
+    uint num_pkts;
+    uint offset_to_first_pkt;
+    uint blk_len;
+    align(8) ulong seq_num;
+    tpacket_bd_ts ts_first_pkt;
+    tpacket_bd_ts ts_last_pkt;
+}
+
+union tpacket_bd_header_u
+{
+    tpacket_hdr_v1 bh1;
+}
+
+struct tpacket_block_desc
+{
+    uint version_;
+    uint offset_to_priv;
+    tpacket_bd_header_u hdr;
+}
+
+enum TPACKET2_HDRLEN = TPACKET_ALIGN(tpacket2_hdr.sizeof) + sockaddr_ll.sizeof;
+enum TPACKET3_HDRLEN = TPACKET_ALIGN(tpacket3_hdr.sizeof) + sockaddr_ll.sizeof;
+
+enum tpacket_versions
+{
+    TPACKET_V1,
+    TPACKET_V2,
+    TPACKET_V3
+}
+
+struct tpacket_req
+{
+    uint tp_block_size;
+    uint tp_block_nr;
+    uint tp_frame_size;
+    uint tp_frame_nr;
+}
+
+struct tpacket_req3
+{
+    uint tp_block_size;
+    uint tp_block_nr;
+    uint tp_frame_size;
+    uint tp_frame_nr;
+    uint tp_retire_blk_tov;
+    uint tp_sizeof_priv;
+    uint tp_feature_req_word;
+}
+
+union tpacket_req_u
+{
+    tpacket_req  req;
+    tpacket_req3 req3;
+}
+
+struct packet_mreq
+{
+    int      mr_ifindex;
+    ushort   mr_type;
+    ushort   mr_alen;
+    ubyte[8] mr_address;
+}
+
+struct fanout_args
+{
+    version(LittleEndian)
+    {
+        ushort id;
+        ushort type_flags;
+    }
+    else
+    {
+        ushort type_flags;
+        ushort id;
+    }
+
+    uint max_num_members;
+}
+
+enum
+{
+    PACKET_MR_MULTICAST = 0,
+    PACKET_MR_PROMISC   = 1,
+    PACKET_MR_ALLMULTI  = 2,
+    PACKET_MR_UNICAST   = 3,
+}
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index a7bf856d747..8c536ce71a5 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-2458e8f82e3004197d8a66239a6b72e17264bb26
+1c98326e787e504d9045004e593273ec99b13121
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/parallelism.d b/libphobos/src/std/parallelism.d
index 3fe8cd61fe0..fadb4c1759d 100644
--- a/libphobos/src/std/parallelism.d
+++ b/libphobos/src/std/parallelism.d
@@ -418,8 +418,8 @@  Bugs:  Changes to `ref` and `out` arguments are not propagated to the
 */
 struct Task(alias fun, Args...)
 {
-    AbstractTask base = {runTask : &impl};
-    alias base this;
+    private AbstractTask base = {runTask : &impl};
+    private alias base this;
 
     private @property AbstractTask* basePtr()
     {
diff --git a/libphobos/src/std/range/primitives.d b/libphobos/src/std/range/primitives.d
index 1a3fb06cf99..89cfa07cc1f 100644
--- a/libphobos/src/std/range/primitives.d
+++ b/libphobos/src/std/range/primitives.d
@@ -165,21 +165,24 @@  See_Also:
 
 Params:
     R = type to be tested
-    E = the type of the elements of the range if not `void`
+    E = if present, the elements of the range must be
+        $(DDSUBLINK spec/const3, implicit_qualifier_conversions, qualifier-convertible)
+        to this type
 
 Returns:
     `true` if R is an input range (possibly with element type `E`), `false` if not
  */
-enum bool isInputRange(R, E = void) =
+enum bool isInputRange(R) =
     is(typeof(R.init) == R)
     && is(typeof((R r) { return r.empty; } (R.init)) == bool)
     && (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front)))
     && !is(typeof((R r) { return r.front; } (R.init)) == void)
-    && is(typeof((R r) => r.popFront))
-    && (is(E == void) ||
-        is(ElementType!R == E) ||
-        is(const(ElementType!R) == E) ||
-        (is(const(ElementType!R) == immutable E) && is(const(E) == E)));
+    && is(typeof((R r) => r.popFront));
+
+/// ditto
+enum bool isInputRange(R, E) =
+    .isInputRange!R && isQualifierConvertible!(ElementType!R, E);
+
 ///
 @safe unittest
 {
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index aa69aacfd10..2e7a4f6a30b 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -132,6 +132,7 @@ 
  *           $(LREF PointerTarget)
  *           $(LREF Signed)
  *           $(LREF Unconst)
+ *           $(LREF Unshared)
  *           $(LREF Unqual)
  *           $(LREF Unsigned)
  *           $(LREF ValueType)
@@ -7848,6 +7849,46 @@  else
     static assert(is(Unconst!ImmIntArr == immutable(int)[]));
 }
 
+/++
+    Removes `shared` qualifier, if any, from type `T`.
+
+    Note that while `immutable` is implicitly `shared`, it is unaffected by
+    Unshared. Only explict `shared` is removed.
+  +/
+template Unshared(T)
+{
+    static if (is(T == shared U, U))
+        alias Unshared = U;
+    else
+        alias Unshared = T;
+}
+
+///
+@safe unittest
+{
+    static assert(is(Unshared!int == int));
+    static assert(is(Unshared!(const int) == const int));
+    static assert(is(Unshared!(immutable int) == immutable int));
+
+    static assert(is(Unshared!(shared int) == int));
+    static assert(is(Unshared!(shared(const int)) == const int));
+
+    static assert(is(Unshared!(shared(int[])) == shared(int)[]));
+}
+
+@safe unittest
+{
+    static assert(is(Unshared!(                   int) == int));
+    static assert(is(Unshared!(             const int) == const int));
+    static assert(is(Unshared!(       inout       int) == inout int));
+    static assert(is(Unshared!(       inout const int) == inout const int));
+    static assert(is(Unshared!(shared             int) == int));
+    static assert(is(Unshared!(shared       const int) == const int));
+    static assert(is(Unshared!(shared inout       int) == inout int));
+    static assert(is(Unshared!(shared inout const int) == inout const int));
+    static assert(is(Unshared!(         immutable int) == immutable int));
+}
+
 version (StdDdoc)
 {
     /**