diff mbox series

[committed] d: Merge upstream dmd eb7bee331, druntime 27834edb, phobos ac296f80c.

Message ID 20220421194703.1247797-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd eb7bee331, druntime 27834edb, phobos ac296f80c. | expand

Commit Message

Iain Buclaw April 21, 2022, 7:47 p.m. UTC
Hi,

This patch merges the D front-end with upstream dmd eb7bee331, and
the standard library with druntime 27834edb and phobos ac296f80c.

D front-end changes:

    - Import dmd v2.100.0-beta.1.
    - Print deprecation messages for scope violations unless
      `-frevert=dip1000' is used.
    - Fixed a missed case of switch case fallthrough not being caught by
      the compiler.

D runtime changes:

    - Import druntime v2.100.0-beta.1.

Phobos changes:

    - Import phobos v2.100.0-beta.1.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd eb7bee331.
	* dmd/VERSION: Update version to v2.100.0-beta.1.
	* d-lang.cc (d_handle_option): Handle OPT_frevert_dip1000.
	* lang.opt (frevert=dip1000): New option.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 27834edb.
	* src/MERGE: Merge upstream phobos ac296f80c.
	* src/Makefile.am (PHOBOS_DSOURCES): Add std/int128.d.
	* src/Makefile.in: Regenerate.
---
 gcc/d/d-lang.cc                               |   5 +
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/VERSION                             |   2 +-
 gcc/d/dmd/aggregate.d                         |  22 ++
 gcc/d/dmd/astenums.d                          |   1 +
 gcc/d/dmd/blockexit.d                         |  15 +-
 gcc/d/dmd/clone.d                             |   6 +-
 gcc/d/dmd/cparse.d                            |  22 +-
 gcc/d/dmd/declaration.d                       |  18 +-
 gcc/d/dmd/dmodule.d                           |   6 +-
 gcc/d/dmd/dsymbol.d                           |   4 +-
 gcc/d/dmd/dsymbolsem.d                        |   9 +-
 gcc/d/dmd/errors.d                            |  16 +-
 gcc/d/dmd/escape.d                            |  61 ++-
 gcc/d/dmd/expression.d                        |  11 +-
 gcc/d/dmd/expression.h                        |   2 -
 gcc/d/dmd/expressionsem.d                     |  29 +-
 gcc/d/dmd/initsem.d                           |   8 +-
 gcc/d/dmd/lexer.d                             |  55 ++-
 gcc/d/dmd/mtype.d                             |  92 ++---
 gcc/d/dmd/mtype.h                             |   2 +-
 gcc/d/dmd/optimize.d                          |  13 +-
 gcc/d/dmd/parse.d                             |  98 +++--
 gcc/d/dmd/statement.d                         |   8 +
 gcc/d/dmd/transitivevisitor.d                 |   4 +-
 gcc/d/dmd/typesem.d                           |  11 +-
 gcc/d/dmd/utils.d                             |   2 +-
 gcc/d/lang.opt                                |   4 +
 .../gdc.test/compilable/betterCarray.d        |   7 +
 gcc/testsuite/gdc.test/compilable/test18216.d |  40 ++
 gcc/testsuite/gdc.test/compilable/test22635.d |  13 +
 .../gdc.test/fail_compilation/diag11198.d     |  12 +-
 .../gdc.test/fail_compilation/fail22202.d     |  22 ++
 .../gdc.test/fail_compilation/fail23036.d     |  22 ++
 .../gdc.test/fail_compilation/fail_scope.d    |  30 +-
 .../gdc.test/fail_compilation/retscope6.d     |  48 ++-
 .../gdc.test/fail_compilation/test22999.d     |  27 ++
 .../gdc.test/fail_compilation/test23017.d     |  20 +
 gcc/testsuite/gdc.test/runnable/testscope.d   |  16 -
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/core/exception.d        |  84 ++--
 libphobos/libdruntime/object.d                |   4 +-
 libphobos/libdruntime/rt/aaA.d                |   4 +-
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/Makefile.am                     |   2 +-
 libphobos/src/Makefile.in                     |   4 +-
 libphobos/src/std/base64.d                    |  20 +-
 libphobos/src/std/int128.d                    | 374 ++++++++++++++++++
 libphobos/src/std/path.d                      |   2 +-
 libphobos/src/std/traits.d                    |  21 +-
 50 files changed, 1002 insertions(+), 302 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/compilable/test18216.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test22635.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22202.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail23036.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test22999.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test23017.d
 create mode 100644 libphobos/src/std/int128.d
diff mbox series

Patch

diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 69571628336..9adcabdf7cf 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -637,12 +637,17 @@  d_handle_option (size_t scode, const char *arg, HOST_WIDE_INT value,
       break;
 
     case OPT_frevert_all:
+      global.params.useDIP1000 = FeatureState::disabled;
       global.params.useDIP25 = FeatureState::disabled;
       global.params.dtorFields = FeatureState::disabled;
       global.params.fix16997 = !value;
       global.params.markdown = !value;
       break;
 
+    case OPT_frevert_dip1000:
+      global.params.useDIP1000 = FeatureState::disabled;
+      break;
+
     case OPT_frevert_dip25:
       global.params.useDIP25 = FeatureState::disabled;
       break;
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index f36d65e7d84..2bc9b95b5e2 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-4d1bfcf142928cf1c097b0a2689485c1b14f4f53
+eb7bee331a13026eeb4dcbf9d43d5d4e744a4d26
 
 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/VERSION b/gcc/d/dmd/VERSION
index 28a360921ab..2450fd55ef8 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.099.1
+v2.100.0-beta.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index 8895aa5e2bd..f4b5e8af7ff 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -57,6 +57,28 @@  enum ClassKind : ubyte
     c,
 }
 
+/**
+ * Give a nice string for a class kind for error messages
+ * Params:
+ *     c = class kind
+ * Returns:
+ *     0-terminated string for `c`
+ */
+const(char)* toChars(ClassKind c)
+{
+    final switch (c)
+    {
+        case ClassKind.d:
+            return "D";
+        case ClassKind.cpp:
+            return "C++";
+        case ClassKind.objc:
+            return "Objective-C";
+        case ClassKind.c:
+            return "C";
+    }
+}
+
 /**
  * If an aggregate has a pargma(mangle, ...) this holds the information
  * to mangle.
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 1a2cf8b0641..bf196934aed 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -28,6 +28,7 @@  enum Baseok : ubyte
 
 enum MODFlags : int
 {
+    none         = 0,    // default (mutable)
     const_       = 1,    // type is const
     immutable_   = 4,    // type is immutable
     shared_      = 2,    // type is shared
diff --git a/gcc/d/dmd/blockexit.d b/gcc/d/dmd/blockexit.d
index afd7ac052ad..22c9dde5f7e 100644
--- a/gcc/d/dmd/blockexit.d
+++ b/gcc/d/dmd/blockexit.d
@@ -139,16 +139,21 @@  int blockExit(Statement s, FuncDeclaration func, bool mustNotThrow)
                             // Allow if last case/default was empty
                             CaseStatement sc = slast.isCaseStatement();
                             DefaultStatement sd = slast.isDefaultStatement();
-                            if (sc && (!sc.statement.hasCode() || sc.statement.isCaseStatement() || sc.statement.isErrorStatement()))
-                            {
-                            }
-                            else if (sd && (!sd.statement.hasCode() || sd.statement.isCaseStatement() || sd.statement.isErrorStatement()))
+                            auto sl = (sc ? sc.statement : (sd ? sd.statement : null));
+
+                            if (sl && (!sl.hasCode() || sl.isErrorStatement()))
                             {
                             }
                             else if (func.getModule().filetype != FileType.c)
                             {
                                 const(char)* gototype = s.isCaseStatement() ? "case" : "default";
-                                s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
+                                // @@@DEPRECATED_2.110@@@ https://issues.dlang.org/show_bug.cgi?id=22999
+                                // Deprecated in 2.100
+                                // Make an error in 2.110
+                                if (sl && sl.isCaseStatement())
+                                    s.deprecation("switch case fallthrough - use 'goto %s;' if intended", gototype);
+                                else
+                                    s.error("switch case fallthrough - use 'goto %s;' if intended", gototype);
                             }
                         }
                     }
diff --git a/gcc/d/dmd/clone.d b/gcc/d/dmd/clone.d
index 2ed0dc7bdd1..9c8c1c316bf 100644
--- a/gcc/d/dmd/clone.d
+++ b/gcc/d/dmd/clone.d
@@ -912,8 +912,8 @@  void buildDtors(AggregateDeclaration ad, Scope* sc)
                 ex = new DotVarExp(loc, ex, v);
 
                 // This is a hack so we can call destructors on const/immutable objects.
-                // Do it as a type 'paint'.
-                ex = new CastExp(loc, ex, v.type.mutableOf());
+                // Do it as a type 'paint', `cast()`
+                ex = new CastExp(loc, ex, MODFlags.none);
                 if (stc & STC.safe)
                     stc = (stc & ~STC.safe) | STC.trusted;
 
@@ -1588,7 +1588,7 @@  private bool needCopyCtor(StructDeclaration sd, out bool hasCpCtor)
 
         auto tf = ctorDecl.type.toTypeFunction();
         const dim = tf.parameterList.length;
-        if (dim == 1)
+        if (dim == 1 || (dim > 1 && tf.parameterList[1].defaultArg))
         {
             auto param = tf.parameterList[0];
             if (param.type.mutableOf().unSharedOf() == sd.type.mutableOf().unSharedOf())
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index bb12aa7c995..53bf26ec927 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -259,6 +259,7 @@  final class CParser(AST) : Parser!AST
         case TOK.plusPlus:
         case TOK.minusMinus:
         case TOK.sizeof_:
+        case TOK._Generic:
         Lexp:
             auto exp = cparseExpression();
             if (token.value == TOK.identifier && exp.op == EXP.identifier)
@@ -2399,15 +2400,13 @@  final class CParser(AST) : Parser!AST
                 if (idx.length > 2 && idx[0] == '_' && idx[1] == '_')  // leading double underscore
                     importBuiltins = true;  // probably one of those compiler extensions
                 t = null;
-                if (scw & SCW.xtypedef)
-                {
-                    /* Punch through to what the typedef is, to support things like:
-                     *  typedef T* T;
-                     */
-                    auto pt = lookupTypedef(previd);
-                    if (pt && *pt)      // if previd is a known typedef
-                        t = *pt;
-                }
+
+                /* Punch through to what the typedef is, to support things like:
+                 *  typedef T* T;
+                 */
+                auto pt = lookupTypedef(previd);
+                if (pt && *pt)      // if previd is a known typedef
+                    t = *pt;
 
                 if (!t)
                     t = new AST.TypeIdentifier(loc, previd);
@@ -2745,6 +2744,11 @@  final class CParser(AST) : Parser!AST
         Specifier specifier;
         specifier.packalign.setDefault();
         auto tspec = cparseSpecifierQualifierList(LVL.global, specifier);
+        if (tspec && specifier.mod & MOD.xconst)
+        {
+            tspec = toConst(tspec);
+            specifier.mod = MOD.xnone;      // 'used' it
+        }
         Identifier id;
         return cparseDeclarator(DTR.xabstract, tspec, id, specifier);
     }
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 45eb582745a..a533d30ca80 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -379,7 +379,7 @@  extern (C++) abstract class Declaration : Dsymbol
 
         if (e1 && e1.op == EXP.this_ && isField())
         {
-            VarDeclaration vthis = (cast(ThisExp)e1).var;
+            VarDeclaration vthis = e1.isThisExp().var;
             for (Scope* scx = sc; scx; scx = scx.enclosing)
             {
                 if (scx.func == vthis.parent && (scx.flags & SCOPE.contract))
@@ -656,9 +656,8 @@  extern (C++) final class TupleDeclaration : Declaration
             if (o.dyncast() == DYNCAST.expression)
             {
                 Expression e = cast(Expression)o;
-                if (e.op == EXP.dSymbol)
+                if (DsymbolExp ve = e.isDsymbolExp())
                 {
-                    DsymbolExp ve = cast(DsymbolExp)e;
                     Declaration d = ve.s.isDeclaration();
                     if (d && d.needThis())
                     {
@@ -1143,7 +1142,7 @@  extern (C++) class VarDeclaration : Declaration
                 assert(o.dyncast() == DYNCAST.expression);
                 Expression e = cast(Expression)o;
                 assert(e.op == EXP.dSymbol);
-                DsymbolExp se = cast(DsymbolExp)e;
+                DsymbolExp se = e.isDsymbolExp();
                 se.s.setFieldOffset(ad, fieldState, isunion);
             }
             return;
@@ -1441,16 +1440,17 @@  extern (C++) class VarDeclaration : Declaration
                 const sdsz = sd.type.size();
                 assert(sdsz != SIZE_INVALID && sdsz != 0);
                 const n = sz / sdsz;
-                e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t), new IntegerExp(loc, n, Type.tsize_t));
+                SliceExp se = new SliceExp(loc, e, new IntegerExp(loc, 0, Type.tsize_t),
+                    new IntegerExp(loc, n, Type.tsize_t));
 
                 // Prevent redundant bounds check
-                (cast(SliceExp)e).upperIsInBounds = true;
-                (cast(SliceExp)e).lowerIsLessThanUpper = true;
+                se.upperIsInBounds = true;
+                se.lowerIsLessThanUpper = true;
 
                 // This is a hack so we can call destructors on const/immutable objects.
-                e.type = sd.type.arrayOf();
+                se.type = sd.type.arrayOf();
 
-                e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), e);
+                e = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se);
             }
             return e;
         }
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index e9c4c954efd..2d9f6510ba5 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -1133,8 +1133,10 @@  extern (C++) final class Module : Package
         // If it isn't there, some compiler rewrites, like
         //    classinst == classinst -> .object.opEquals(classinst, classinst)
         // would fail inside object.d.
-        if (members.dim == 0 || (*members)[0].ident != Id.object ||
-            (*members)[0].isImport() is null)
+        if (filetype != FileType.c &&
+            (members.dim == 0 ||
+             (*members)[0].ident != Id.object ||
+             (*members)[0].isImport() is null))
         {
             auto im = new Import(Loc.initial, null, Id.object, null, 0);
             members.shift(im);
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 2021e2afd8e..74eaa1d8d7a 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -838,7 +838,8 @@  extern (C++) class Dsymbol : ASTNode
         }
         if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
         {
-            if (ident == Id.__sizeof || ident == Id.__xalignof || ident == Id._mangleof)
+            if (ident == Id.__sizeof ||
+                !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
             {
                 error("`.%s` property cannot be redefined", ident.toChars());
                 errors = true;
@@ -2523,6 +2524,7 @@  Dsymbol handleSymbolRedeclarations(ref Scope sc, Dsymbol s, Dsymbol s2, ScopeDsy
 
         if (i1)                         // vd is the definition
         {
+            vd2.storage_class |= STC.extern_;  // so toObjFile() won't emit it
             sds.symtab.update(vd);      // replace vd2 with the definition
             return vd;
         }
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 1ccaab56da6..5415401e0e4 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -2874,7 +2874,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             sc = sc.endCTFE();
             resolved = resolved.ctfeInterpret();
             StringExp name = resolved.toStringExp();
-            TupleExp tup = name ? null : resolved.toTupleExp();
+            TupleExp tup = name ? null : resolved.isTupleExp();
             if (!tup && !name)
             {
                 error(ns.loc, "expected string expression for namespace name, got `%s`", ns.identExp.toChars());
@@ -4621,7 +4621,8 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         buildOpAssign(sd, sc2);
         buildOpEquals(sd, sc2);
 
-        if (global.params.useTypeInfo && Type.dtypeinfo)  // these functions are used for TypeInfo
+        if (!(sc2.flags & SCOPE.Cfile) &&
+            global.params.useTypeInfo && Type.dtypeinfo)  // these functions are used for TypeInfo
         {
             sd.xeq = buildXopEquals(sd, sc2);
             sd.xcmp = buildXopCmp(sd, sc2);
@@ -5023,6 +5024,10 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     cldec.com = true;
                 if (cldec.baseClass.isCPPclass())
                     cldec.classKind = ClassKind.cpp;
+                if (cldec.classKind != cldec.baseClass.classKind)
+                    cldec.error("with %s linkage cannot inherit from class `%s` with %s linkage",
+                        cldec.classKind.toChars(), cldec.baseClass.toChars(), cldec.baseClass.classKind.toChars());
+
                 if (cldec.baseClass.stack)
                     cldec.stack = true;
                 cldec.enclosing = cldec.baseClass.enclosing;
diff --git a/gcc/d/dmd/errors.d b/gcc/d/dmd/errors.d
index 114bd44e32c..62e86a1163c 100644
--- a/gcc/d/dmd/errors.d
+++ b/gcc/d/dmd/errors.d
@@ -434,8 +434,20 @@  else
     pragma(printf) extern (C++) void vdeprecationSupplemental(const ref Loc loc, const(char)* format, va_list ap);
 
 /**
- * Call this after printing out fatal error messages to clean up and exit
- * the compiler.
+ * The type of the fatal error handler
+ * Returns: true if error handling is done, false to do exit(EXIT_FAILURE)
+ */
+alias FatalErrorHandler = bool delegate();
+
+/**
+ * The fatal error handler.
+ * If non-null it will be called for every fatal() call issued by the compiler.
+ */
+__gshared FatalErrorHandler fatalErrorHandler;
+
+/**
+ * Call this after printing out fatal error messages to clean up and exit the
+ * compiler. You can also set a fatalErrorHandler to override this behaviour.
  */
 extern (C++) void fatal();
 
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 78b9a07f3a3..44c3757248b 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -316,24 +316,27 @@  bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Parameter par, Exp
      */
     void unsafeAssign(VarDeclaration v, const char* desc)
     {
-        if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+        if (setUnsafeDIP1000(sc.func))
         {
             if (!gag)
             {
                 if (assertmsg)
                 {
-                    error(arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
+                    previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                                    (arg.loc, "%s `%s` assigned to non-scope parameter calling `assert()`",
                         desc, v.toChars());
                 }
                 else
                 {
-                    error(arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
+                    previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                                    (arg.loc, "%s `%s` assigned to non-scope parameter `%s` calling %s",
                         desc, v.toChars(),
                         par ? par.toChars() : "this",
                         fdc ? fdc.toPrettyChars() : "indirectly");
                 }
             }
-            result = true;
+            if (global.params.useDIP1000 == FeatureState.enabled)
+                result = true;
         }
     }
 
@@ -774,7 +777,7 @@  bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
         if (v.isDataseg())
             continue;
 
-        if (global.params.useDIP1000 == FeatureState.enabled)
+        if (global.params.useDIP1000 != FeatureState.disabled)
         {
             if (va && va.isScope() && !v.isReference())
             {
@@ -782,12 +785,18 @@  bool checkAssignEscape(Scope* sc, Expression e, bool gag, bool byRef)
                 {
                     va.doNotInferReturn = true;
                 }
-                else if (fd.setUnsafe())
+                else if (setUnsafeDIP1000(fd))
                 {
                     if (!gag)
-                        error(ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
-                    result = true;
-                    continue;
+                        previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                            (ae.loc, "address of local variable `%s` assigned to return scope `%s`", v.toChars(), va.toChars());
+
+
+                    if (global.params.useDIP1000 == FeatureState.enabled)
+                    {
+                        result = true;
+                        continue;
+                    }
                 }
             }
         }
@@ -976,12 +985,11 @@  bool checkThrowEscape(Scope* sc, Expression e, bool gag)
         if (v.isScope() && !v.iscatchvar)       // special case: allow catch var to be rethrown
                                                 // despite being `scope`
         {
+            if (!gag)
+                previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                                (e.loc, "scope variable `%s` may not be thrown", v.toChars());
             if (global.params.useDIP1000 == FeatureState.enabled) // https://issues.dlang.org/show_bug.cgi?id=17029
-            {
-                if (!gag)
-                    error(e.loc, "scope variable `%s` may not be thrown", v.toChars());
                 result = true;
-            }
             continue;
         }
         else
@@ -1042,13 +1050,16 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
                  */
                 !(p.parent == sc.func))
             {
-                if (global.params.useDIP1000 == FeatureState.enabled   // https://issues.dlang.org/show_bug.cgi?id=17029
-                    && sc.func.setUnsafe())     // https://issues.dlang.org/show_bug.cgi?id=20868
+                if (setUnsafeDIP1000(sc.func))     // https://issues.dlang.org/show_bug.cgi?id=20868
                 {
+                    // Only look for errors if in module listed on command line
                     if (!gag)
-                        error(e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
-                    result = true;
+                        previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                                        (e.loc, "scope variable `%s` may not be copied into allocated memory", v.toChars());
+                    if (global.params.useDIP1000 == FeatureState.enabled)
+                        result = true;
                 }
+
                 continue;
             }
         }
@@ -1258,11 +1269,13 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                )
             {
                 // https://issues.dlang.org/show_bug.cgi?id=17029
-                if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
+                if (setUnsafeDIP1000(sc.func))
                 {
                     if (!gag)
-                        error(e.loc, "scope variable `%s` may not be returned", v.toChars());
-                    result = true;
+                        previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)
+                                        (e.loc, "scope variable `%s` may not be returned", v.toChars());
+                    if (global.params.useDIP1000 == FeatureState.enabled)
+                        result = true;
                 }
                 continue;
             }
@@ -2341,3 +2354,11 @@  private void addMaybe(VarDeclaration va, VarDeclaration v)
         va.maybes = new VarDeclarations();
     va.maybes.push(v);
 }
+
+
+private bool setUnsafeDIP1000(FuncDeclaration f)
+{
+    return global.params.useDIP1000 == FeatureState.enabled
+        ? f.setUnsafe()
+        : f.isSafeBypassingInference();
+}
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 24030eb42d0..107e85b0793 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -967,11 +967,6 @@  extern (C++) abstract class Expression : ASTNode
         return null;
     }
 
-    TupleExp toTupleExp()
-    {
-        return null;
-    }
-
     /***************************************
      * Return !=0 if expression is an lvalue.
      */
@@ -1746,6 +1741,7 @@  extern (C++) abstract class Expression : ASTNode
         inout(ModuleInitExp)     isModuleInitExp() { return op == EXP.moduleString ? cast(typeof(return))this : null; }
         inout(FuncInitExp)       isFuncInitExp() { return op == EXP.functionString ? cast(typeof(return))this : null; }
         inout(PrettyFuncInitExp) isPrettyFuncInitExp() { return op == EXP.prettyFunction ? cast(typeof(return))this : null; }
+        inout(ObjcClassReferenceExp) isObjcClassReferenceExp() { return op == EXP.objcClassReference ? cast(typeof(return))this : null; }
         inout(ClassReferenceExp) isClassReferenceExp() { return op == EXP.classReference ? cast(typeof(return))this : null; }
         inout(ThrownExceptionExp) isThrownExceptionExp() { return op == EXP.thrownException ? cast(typeof(return))this : null; }
 
@@ -2888,11 +2884,6 @@  extern (C++) final class TupleExp : Expression
         return new TupleExp(loc, exps);
     }
 
-    override TupleExp toTupleExp()
-    {
-        return this;
-    }
-
     override TupleExp syntaxCopy()
     {
         return new TupleExp(loc, e0 ? e0.syntaxCopy() : null, arraySyntaxCopy(exps));
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 9522b23a3b1..a0d63e0023d 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -103,7 +103,6 @@  public:
     virtual real_t toImaginary();
     virtual complex_t toComplex();
     virtual StringExp *toStringExp();
-    virtual TupleExp *toTupleExp();
     virtual bool isLvalue();
     virtual Expression *toLvalue(Scope *sc, Expression *e);
     virtual Expression *modifiableLvalue(Scope *sc, Expression *e);
@@ -406,7 +405,6 @@  public:
     Expressions *exps;
 
     static TupleExp *create(const Loc &loc, Expressions *exps);
-    TupleExp *toTupleExp();
     TupleExp *syntaxCopy();
     bool equals(const RootObject *o) const;
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 64cd7ab849c..22a1f45f4e8 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -2028,7 +2028,9 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
             //printf("type: %s\n", arg.type.toChars());
             //printf("param: %s\n", p.toChars());
 
-            if (firstArg && p.storageClass & STC.return_)
+            const pStc = tf.parameterStorageClass(tthis, p);
+
+            if (firstArg && (pStc & STC.return_))
             {
                 /* Argument value can be assigned to firstArg.
                  * Check arg to see if it matters.
@@ -2036,7 +2038,9 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
                 if (global.params.useDIP1000 == FeatureState.enabled)
                     err |= checkParamArgumentReturn(sc, firstArg, arg, p, false);
             }
-            else if (tf.parameterEscapes(tthis, p))
+            // Allow 'lazy' to imply 'scope' - lazy parameters can be passed along
+            // as lazy parameters to the next function, but that isn't escaping.
+            else if (!(pStc & (STC.scope_ | STC.lazy_)))
             {
                 /* Argument value can escape from the called function.
                  * Check arg to see if it matters.
@@ -2044,7 +2048,7 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
                 if (global.params.useDIP1000 == FeatureState.enabled)
                     err |= checkParamArgumentEscape(sc, fd, p, arg, false, false);
             }
-            else if (!(p.storageClass & STC.return_))
+            else if (!(pStc & STC.return_))
             {
                 /* Argument value cannot escape from the called function.
                  */
@@ -3229,7 +3233,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
         Type t = cle.type.typeSemantic(cle.loc, sc);
         auto init = initializerSemantic(cle.initializer, sc, t, INITnointerpret);
-        auto e = initializerToExpression(init, t);
+        auto e = initializerToExpression(init, t, (sc.flags & SCOPE.Cfile) != 0);
         if (!e)
         {
             error(cle.loc, "cannot convert initializer `%s` to expression", init.toChars());
@@ -12195,7 +12199,7 @@  Expression semanticX(DotIdExp exp, Scope* sc)
     if (Expression ex = unaSemantic(exp, sc))
         return ex;
 
-    if (exp.ident == Id._mangleof)
+    if (!(sc.flags & SCOPE.Cfile) && exp.ident == Id._mangleof)
     {
         // symbol.mangleof
 
@@ -12304,6 +12308,8 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
 
     //{ static int z; fflush(stdout); if (++z == 10) *(char*)0=0; }
 
+    const cfile = (sc.flags & SCOPE.Cfile) != 0;
+
     /* Special case: rewrite this.id and super.id
      * to be classtype.id and baseclasstype.id
      * if we have no this pointer.
@@ -12555,7 +12561,16 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
             exp.error("undefined identifier `%s` in %s `%s`", exp.ident.toChars(), ie.sds.kind(), ie.sds.toPrettyChars());
         return ErrorExp.get();
     }
-    else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum && exp.ident != Id._init && exp.ident != Id.__sizeof && exp.ident != Id.__xalignof && exp.ident != Id.offsetof && exp.ident != Id._mangleof && exp.ident != Id.stringof)
+    else if (t1b.ty == Tpointer && exp.e1.type.ty != Tenum &&
+             !(
+               exp.ident == Id.__sizeof ||
+               exp.ident == Id.__xalignof ||
+               !cfile &&
+                (exp.ident == Id._mangleof ||
+                 exp.ident == Id.offsetof ||
+                 exp.ident == Id._init ||
+                 exp.ident == Id.stringof)
+              ))
     {
         Type t1bn = t1b.nextOf();
         if (flag)
@@ -12590,7 +12605,7 @@  Expression semanticY(DotIdExp exp, Scope* sc, int flag)
         Expression e = new IntegerExp(exp.loc, actualAlignment, Type.tsize_t);
         return e;
     }
-    else if (sc.flags & SCOPE.Cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
+    else if (cfile && exp.ident == Id.__sizeof && exp.e1.isStringExp())
     {
         // Sizeof string literal includes the terminating 0
         auto se = exp.e1.isStringExp();
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 616712b463d..c84a9f69ffa 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -695,7 +695,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 assert(sc);
                 auto tm = vd.type.addMod(ts.mod);
                 auto iz = di.initializer.initializerSemantic(sc, tm, needInterpret);
-                auto ex = iz.initializerToExpression();
+                auto ex = iz.initializerToExpression(null, true);
                 if (ex.op == EXP.error)
                 {
                     errors = true;
@@ -1100,6 +1100,8 @@  Initializer inferType(Initializer init, Scope* sc)
  */
 extern (C++) Expression initializerToExpression(Initializer init, Type itype = null, const bool isCfile = false)
 {
+    //printf("initializerToExpression() isCfile: %d\n", isCfile);
+
     Expression visitVoid(VoidInitializer)
     {
         return null;
@@ -1197,7 +1199,7 @@  extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
             assert(j < edim);
             if (Initializer iz = init.value[i])
             {
-                if (Expression ex = iz.initializerToExpression())
+                if (Expression ex = iz.initializerToExpression(null, isCfile))
                 {
                     (*elements)[j] = ex;
                     ++j;
@@ -1285,7 +1287,7 @@  extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
 
     Expression visitC(CInitializer i)
     {
-        //printf("CInitializer.initializerToExpression()\n");
+        //printf("CInitializer.initializerToExpression(null, true)\n");
         return null;
     }
 
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index b778bc82d77..5945da32259 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -1236,28 +1236,47 @@  class Lexer
             {
                 uint v = 0;
                 int n = 0;
-                while (1)
+                if (Ccompile && ndigits == 2)
                 {
-                    if (isdigit(cast(char)c))
-                        c -= '0';
-                    else if (islower(c))
-                        c -= 'a' - 10;
-                    else
-                        c -= 'A' - 10;
-                    v = v * 16 + c;
-                    c = *++p;
-                    if (++n == ndigits)
-                        break;
-                    if (!ishex(cast(char)c))
+                    /* C11 6.4.4.4-7 one to infinity hex digits
+                     */
+                    do
                     {
-                        .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
-                        break;
-                    }
+                        if (isdigit(cast(char)c))
+                            c -= '0';
+                        else if (islower(c))
+                            c -= 'a' - 10;
+                        else
+                            c -= 'A' - 10;
+                        v = v * 16 + c;
+                        c = *++p;
+                    } while (ishex(cast(char)c));
                 }
-                if (ndigits != 2 && !utf_isValidDchar(v))
+                else
                 {
-                    .error(loc, "invalid UTF character \\U%08x", v);
-                    v = '?'; // recover with valid UTF character
+                    while (1)
+                    {
+                        if (isdigit(cast(char)c))
+                            c -= '0';
+                        else if (islower(c))
+                            c -= 'a' - 10;
+                        else
+                            c -= 'A' - 10;
+                        v = v * 16 + c;
+                        c = *++p;
+                        if (++n == ndigits)
+                            break;
+                        if (!ishex(cast(char)c))
+                        {
+                            .error(loc, "escape hex sequence has %d hex digits instead of %d", n, ndigits);
+                            break;
+                        }
+                    }
+                    if (ndigits != 2 && !utf_isValidDchar(v))
+                    {
+                        .error(loc, "invalid UTF character \\U%08x", v);
+                        v = '?'; // recover with valid UTF character
+                    }
                 }
                 c = v;
             }
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 50dd20b70b9..13df0d71f3f 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -4360,29 +4360,6 @@  extern (C++) final class TypeFunction : TypeNext
         return linkage == LINK.d && parameterList.varargs == VarArg.variadic;
     }
 
-    /***************************
-     * Examine function signature for parameter p and see if
-     * the value of p can 'escape' the scope of the function.
-     * This is useful to minimize the needed annotations for the parameters.
-     * Params:
-     *  tthis = type of `this` parameter, null if none
-     *  p = parameter to this function
-     * Returns:
-     *  true if escapes via assignment to global or through a parameter
-     */
-    bool parameterEscapes(Type tthis, Parameter p)
-    {
-        /* Scope parameters do not escape.
-         * Allow 'lazy' to imply 'scope' -
-         * lazy parameters can be passed along
-         * as lazy parameters to the next function, but that isn't
-         * escaping.
-         */
-        if (parameterStorageClass(tthis, p) & (STC.scope_ | STC.lazy_))
-            return false;
-        return true;
-    }
-
     /************************************
      * Take the specified storage class for p,
      * and use the function signature to infer whether
@@ -4410,7 +4387,7 @@  extern (C++) final class TypeFunction : TypeNext
 
         /* If haven't inferred the return type yet, can't infer storage classes
          */
-        if (!nextOf())
+        if (!nextOf() || !isnothrow())
             return stc;
 
         purityLevel();
@@ -4461,37 +4438,12 @@  extern (C++) final class TypeFunction : TypeNext
             }
         }
 
-        /* Inferring STC.return_ here has false positives
-         * for pure functions, producing spurious error messages
-         * about escaping references.
-         * Give up on it for now.
-         */
-        version (none)
-        {
-            stc |= STC.scope_;
-
-            Type tret = nextOf().toBasetype();
-            if (isref || tret.hasPointers())
-            {
-                /* The result has references, so p could be escaping
-                 * that way.
-                 */
-                stc |= STC.return_;
-            }
-        }
+        // Check escaping through return value
+        Type tret = nextOf().toBasetype();
+        if (isref || tret.hasPointers())
+            return stc | STC.scope_ | STC.return_ | STC.returnScope;
         else
-        {
-            // Check escaping through return value
-            Type tret = nextOf().toBasetype();
-            if (isref || tret.hasPointers() || !isnothrow())
-            {
-                return stc;
-            }
-
-            stc |= STC.scope_;
-        }
-
-        return stc;
+            return stc | STC.scope_;
     }
 
     override Type addStorageClass(StorageClass stc)
@@ -4791,14 +4743,40 @@  extern (C++) final class TypeFunction : TypeNext
                                 m = MATCH.exact;
                             else
                             {
-                                m = MATCH.nomatch;
                                 if (pMessage)
                                 {
+                                    /* https://issues.dlang.org/show_bug.cgi?id=22202
+                                     *
+                                     * If a function was deduced by semantic on the CallExp,
+                                     * it means that resolveFuncCall completed succesfully.
+                                     * Therefore, there exists a callable copy constructor,
+                                     * however, it cannot be called because scope constraints
+                                     * such as purity, safety or nogc.
+                                     */
                                     OutBuffer buf;
-                                    buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
-                                           argStruct.toChars(), targ.toChars(), tprm.toChars());
+                                    auto callExp = e.isCallExp();
+                                    if (auto f = callExp.f)
+                                    {
+                                        char[] s;
+                                        if (!f.isPure && sc.func.setImpure())
+                                            s ~= "pure ";
+                                        if (!f.isSafe() && !f.isTrusted() && sc.func.setUnsafe())
+                                            s ~= "@safe ";
+                                        if (!f.isNogc && sc.func.setGC())
+                                            s ~= "nogc ";
+                                        s[$-1] = '\0';
+                                        buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+
+                                    }
+                                    else
+                                    {
+                                        buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+                                               argStruct.toChars(), targ.toChars(), tprm.toChars());
+                                    }
+
                                     *pMessage = buf.extractChars();
                                 }
+                                m = MATCH.nomatch;
                                 goto Nomatch;
                             }
                         }
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index e0b6339bf23..6ba47dfa34e 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -109,6 +109,7 @@  enum class TY : uint8_t
  */
 enum MODFlags
 {
+    MODnone      = 0, // default (mutable)
     MODconst     = 1, // type is const
     MODimmutable = 4, // type is immutable
     MODshared    = 2, // type is shared
@@ -608,7 +609,6 @@  public:
     void purityLevel();
     bool hasLazyParameters();
     bool isDstyleVariadic() const;
-    bool parameterEscapes(Parameter *p);
     StorageClass parameterStorageClass(Parameter *p);
     Type *addStorageClass(StorageClass stc);
 
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 3b8b1b6fa6c..3cc36b49e01 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -593,7 +593,7 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                     return;
                 }
             }
-            // Convert &((a.b)[n]) to (&a.b)+n
+            // Convert &((a.b)[index]) to (&a.b)+index*elementsize
             else if (ae.e2.isIntegerExp() && ae.e1.isDotVarExp())
             {
                 sinteger_t index = ae.e2.toInteger();
@@ -614,9 +614,18 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                         }
                     }
 
+                    import core.checkedint : mulu;
+                    bool overflow;
+                    const offset = mulu(index, ts.nextOf().size(e.loc), overflow); // index*elementsize
+                    if (overflow)
+                    {
+                        e.error("array offset overflow");
+                        return error();
+                    }
+
                     auto pe = new AddrExp(e.loc, ve);
                     pe.type = e.type;
-                    ret = new AddExp(e.loc, pe, ae.e2);
+                    ret = new AddExp(e.loc, pe, new IntegerExp(e.loc, offset, Type.tsize_t));
                     ret.type = e.type;
                     return;
                 }
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 7b1b63cba82..4b9c0f2119f 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -987,23 +987,9 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 nextToken();
                 if (token.value == TOK.assign)
                 {
-                    nextToken();
-                    if (token.value == TOK.identifier)
-                        s = new AST.DebugSymbol(token.loc, token.ident);
-                    else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
-                        s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
-                    else
-                    {
-                        error("identifier or integer expected, not `%s`", token.toChars());
-                        s = null;
-                    }
-                    nextToken();
-                    if (token.value != TOK.semicolon)
-                        error("semicolon expected");
-                    nextToken();
+                    s = parseDebugSpecification();
                     break;
                 }
-
                 condition = parseDebugCondition();
                 goto Lcondition;
 
@@ -1012,20 +998,7 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 nextToken();
                 if (token.value == TOK.assign)
                 {
-                    nextToken();
-                    if (token.value == TOK.identifier)
-                        s = new AST.VersionSymbol(token.loc, token.ident);
-                    else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
-                        s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
-                    else
-                    {
-                        error("identifier or integer expected, not `%s`", token.toChars());
-                        s = null;
-                    }
-                    nextToken();
-                    if (token.value != TOK.semicolon)
-                        error("semicolon expected");
-                    nextToken();
+                    s = parseVersionSpecification();
                     break;
                 }
                 condition = parseVersionCondition();
@@ -2197,6 +2170,26 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         return qualified;
     }
 
+    private AST.DebugSymbol parseDebugSpecification()
+    {
+        AST.DebugSymbol s;
+        nextToken();
+        if (token.value == TOK.identifier)
+            s = new AST.DebugSymbol(token.loc, token.ident);
+        else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+            s = new AST.DebugSymbol(token.loc, cast(uint)token.unsvalue);
+        else
+        {
+            error("identifier or integer expected, not `%s`", token.toChars());
+            s = null;
+        }
+        nextToken();
+        if (token.value != TOK.semicolon)
+            error("semicolon expected");
+        nextToken();
+        return s;
+    }
+
     /**************************************
      * Parse a debug conditional
      */
@@ -2223,6 +2216,29 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         return new AST.DebugCondition(loc, mod, level, id);
     }
 
+    /**************************************
+     * Parse a version specification
+     */
+    private AST.VersionSymbol parseVersionSpecification()
+    {
+        AST.VersionSymbol s;
+        nextToken();
+        if (token.value == TOK.identifier)
+            s = new AST.VersionSymbol(token.loc, token.ident);
+        else if (token.value == TOK.int32Literal || token.value == TOK.int64Literal)
+            s = new AST.VersionSymbol(token.loc, cast(uint)token.unsvalue);
+        else
+        {
+            error("identifier or integer expected, not `%s`", token.toChars());
+            s = null;
+        }
+        nextToken();
+        if (token.value != TOK.semicolon)
+            error("semicolon expected");
+        nextToken();
+        return s;
+    }
+
     /**************************************
      * Parse a version conditional
      */
@@ -6053,10 +6069,14 @@  LagainStc:
             nextToken();
             if (token.value == TOK.assign)
             {
-                error("debug conditions can only be declared at module scope");
-                nextToken();
-                nextToken();
-                goto Lerror;
+                if (auto ds = parseDebugSpecification())
+                {
+                    if (ds.ident)
+                        ds.error("declaration must be at module level");
+                    else
+                        ds.error("level declaration must be at module level");
+                }
+                break;
             }
             cond = parseDebugCondition();
             goto Lcondition;
@@ -6065,10 +6085,14 @@  LagainStc:
             nextToken();
             if (token.value == TOK.assign)
             {
-                error("version conditions can only be declared at module scope");
-                nextToken();
-                nextToken();
-                goto Lerror;
+                if (auto vs = parseVersionSpecification())
+                {
+                    if (vs.ident)
+                        vs.error("declaration must be at module level");
+                    else
+                        vs.error("level declaration must be at module level");
+                }
+                break;
             }
             cond = parseVersionCondition();
             goto Lcondition;
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index ae03b8a4c52..71713249009 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -315,6 +315,14 @@  extern (C++) abstract class Statement : ASTNode
             override void visit(ImportStatement s)
             {
             }
+
+            override void visit(CaseStatement s)
+            {
+            }
+
+            override void visit(DefaultStatement s)
+            {
+            }
         }
 
         scope HasCode hc = new HasCode();
diff --git a/gcc/d/dmd/transitivevisitor.d b/gcc/d/dmd/transitivevisitor.d
index 615c49fd623..0acad6ae14a 100644
--- a/gcc/d/dmd/transitivevisitor.d
+++ b/gcc/d/dmd/transitivevisitor.d
@@ -17,7 +17,9 @@  import core.stdc.stdio;
 extern(C++) class ParseTimeTransitiveVisitor(AST) : PermissiveVisitor!AST
 {
     alias visit = PermissiveVisitor!AST.visit;
-    mixin ParseVisitMethods!AST;
+
+    mixin ParseVisitMethods!AST __methods;
+    alias visit = __methods.visit;
 }
 
 /* This mixin implements the AST traversal logic for parse time AST nodes. The same code
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index b26741242f9..f63b17752ed 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1843,7 +1843,7 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
                 mtype.sym = e.isScopeExp().sds;
                 break;
             case EXP.tuple:
-                TupleExp te = e.toTupleExp();
+                TupleExp te = e.isTupleExp();
                 Objects* elems = new Objects(te.exps.dim);
                 foreach (i; 0 .. elems.dim)
                 {
@@ -2306,7 +2306,8 @@  extern (C++) Type merge(Type type)
         case Tident:
         case Tinstance:
         case Tmixin:
-            return type;
+        case Ttag:
+            return type;        // don't merge placeholder types
 
         case Tsarray:
             // prevents generating the mangle if the array dim is not yet known
@@ -3904,7 +3905,7 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
         assert(e.op != EXP.dot);
 
         // https://issues.dlang.org/show_bug.cgi?id=14010
-        if (ident == Id._mangleof)
+        if (!(sc.flags & SCOPE.Cfile) && ident == Id._mangleof)
         {
             return mt.getProperty(sc, e.loc, ident, flag & 1);
         }
@@ -4656,7 +4657,7 @@  extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
     {
         static if (LOGDEFAULTINIT)
         {
-            printf("TypeBasic::defaultInit() '%s'\n", mt.toChars());
+            printf("TypeBasic::defaultInit() '%s' isCfile: %d\n", mt.toChars(), isCfile);
         }
         dinteger_t value = 0;
 
@@ -4714,7 +4715,7 @@  extern (C++) Expression defaultInit(Type mt, const ref Loc loc, const bool isCfi
     {
         static if (LOGDEFAULTINIT)
         {
-            printf("TypeSArray::defaultInit() '%s'\n", mt.toChars());
+            printf("TypeSArray::defaultInit() '%s' isCfile %d\n", mt.toChars(), isCfile);
         }
         if (mt.next.ty == Tvoid)
             return mt.tuns8.defaultInit(loc, isCfile);
diff --git a/gcc/d/dmd/utils.d b/gcc/d/dmd/utils.d
index cdfe3cb61aa..7f3fb64842d 100644
--- a/gcc/d/dmd/utils.d
+++ b/gcc/d/dmd/utils.d
@@ -84,7 +84,7 @@  extern (D) void writeFile(Loc loc, const(char)[] filename, const void[] data)
     ensurePathToNameExists(Loc.initial, filename);
     if (!File.update(filename, data))
     {
-        error(loc, "Error writing file '%*.s'", cast(int) filename.length, filename.ptr);
+        error(loc, "Error writing file '%.*s'", cast(int) filename.length, filename.ptr);
         fatal();
     }
 }
diff --git a/gcc/d/lang.opt b/gcc/d/lang.opt
index 51e8e5c7e00..b4b81523c14 100644
--- a/gcc/d/lang.opt
+++ b/gcc/d/lang.opt
@@ -396,6 +396,10 @@  frevert=all
 D RejectNegative
 Turn off all revertable D language features.
 
+frevert=dip1000
+D RejectNegative
+Revert DIP1000: Scoped pointers.
+
 frevert=dip25
 D RejectNegative
 Revert DIP25: Sealed references.
diff --git a/gcc/testsuite/gdc.test/compilable/betterCarray.d b/gcc/testsuite/gdc.test/compilable/betterCarray.d
index 3e9a881c3d6..72dcc6b5ee3 100644
--- a/gcc/testsuite/gdc.test/compilable/betterCarray.d
+++ b/gcc/testsuite/gdc.test/compilable/betterCarray.d
@@ -26,3 +26,10 @@  void issue19234()
     A[10] b;
     b[] = a[];
 }
+
+/**********************************************/
+// https://issues.dlang.org/show_bug.cgi?id=22922
+void issue22922()
+{
+    int[] x = [];
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test18216.d b/gcc/testsuite/gdc.test/compilable/test18216.d
new file mode 100644
index 00000000000..43f5629a3c7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test18216.d
@@ -0,0 +1,40 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=18216
+
+struct Node
+{
+    mixin Type!();
+    Pointer left;
+}
+
+mixin template Type()
+{
+    alias Base = typeof(this);
+
+    static struct Proxy
+    {
+        struct Node
+        {
+            Base m_payload;
+        }
+        static immutable default_value = Base.init; // just remove this will work
+    }
+
+    alias pNode = shared(Proxy.Node)*;
+
+    static struct Pointer
+    {
+        Base*   _ptr;
+        auto ptr()
+        {
+            return cast(pNode) _ptr;
+        }
+
+        void opAssign(ref Pointer other) {} // just remove this will work
+
+        alias getThis this; // just remove this will work
+        ref auto getThis() return
+        {
+            return ptr.m_payload;
+        }
+    }
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test22635.d b/gcc/testsuite/gdc.test/compilable/test22635.d
new file mode 100644
index 00000000000..c2abc837956
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test22635.d
@@ -0,0 +1,13 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22635
+// opCast prevent calling destructor for const this
+
+struct Foo
+{
+    bool opCast(T : bool)() const { assert(0); }
+    ~this() {}
+}
+
+struct Bar
+{
+    const Foo foo;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d
index ebefa4dc6af..279d62a5496 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag11198.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag11198.d
@@ -1,8 +1,12 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag11198.d(11): Error: version conditions can only be declared at module scope
-fail_compilation/diag11198.d(12): Error: debug conditions can only be declared at module scope
+fail_compilation/diag11198.d(15): Error: version `blah` declaration must be at module level
+fail_compilation/diag11198.d(16): Error: debug `blah` declaration must be at module level
+fail_compilation/diag11198.d(17): Error: version `1` level declaration must be at module level
+fail_compilation/diag11198.d(18): Error: debug `2` level declaration must be at module level
+fail_compilation/diag11198.d(19): Error: identifier or integer expected, not `""`
+fail_compilation/diag11198.d(20): Error: identifier or integer expected, not `""`
 ---
 */
 
@@ -10,4 +14,8 @@  void main()
 {
     version = blah;
     debug = blah;
+    version = 1;
+    debug = 2;
+    version = "";
+    debug = "";
 }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22202.d b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d
new file mode 100644
index 00000000000..167d3624879
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22202.d
@@ -0,0 +1,22 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22202
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail22202.d(21): Error: function `fail22202.fun(SystemCopy _param_0)` is not callable using argument types `(SystemCopy)`
+fail_compilation/fail22202.d(21):        `inout ref inout(SystemCopy)(ref inout(SystemCopy) other)` copy constructor cannot be called from a `pure @safe nogc` context
+---
+*/
+
+struct SystemCopy
+{
+    this(ref inout SystemCopy other) inout {}
+}
+
+void fun(SystemCopy) @safe pure @nogc {}
+
+void main() @safe pure @nogc
+{
+    SystemCopy s;
+    fun(s);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail23036.d b/gcc/testsuite/gdc.test/fail_compilation/fail23036.d
new file mode 100644
index 00000000000..8920586c67a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail23036.d
@@ -0,0 +1,22 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=23036
+
+/*
+TEST_OUTPUT:
+---
+fail_compilation/fail23036.d(12): Error: `struct S` may not define both a rvalue constructor and a copy constructor
+fail_compilation/fail23036.d(15):        rvalue constructor defined here
+fail_compilation/fail23036.d(14):        copy constructor defined here
+---
+*/
+
+struct S
+{
+    this(ref S) {}
+    this(S, int a = 2) {}
+}
+
+void main()
+{
+    S a;
+    S b = a;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
index 41a8c2d85e3..07c3766d490 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
@@ -2,6 +2,13 @@ 
 REQUIRED_ARGS:
 TEST_OUTPUT:
 ---
+fail_compilation/fail_scope.d(29): Deprecation: scope variable `da` may not be returned
+fail_compilation/fail_scope.d(31): Deprecation: scope variable `o` may not be returned
+fail_compilation/fail_scope.d(32): Deprecation: scope variable `dg` may not be returned
+fail_compilation/fail_scope.d(34): Deprecation: scope variable `da` may not be returned
+fail_compilation/fail_scope.d(36): Deprecation: scope variable `o` may not be returned
+fail_compilation/fail_scope.d(37): Deprecation: scope variable `dg` may not be returned
+fail_compilation/fail_scope.d(39): Deprecation: scope variable `p` may not be returned
 fail_compilation/fail_scope.d(44): Error: returning `cast(char[])string` escapes a reference to local variable `string`
 fail_compilation/fail_scope.d(62): Error: returning `s.bar()` escapes a reference to local variable `s`
 fail_compilation/fail_scope.d(73): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
@@ -15,26 +22,19 @@  fail_compilation/fail_scope.d(107): Deprecation: escaping reference to outer loc
 fail_compilation/fail_scope.d(126): Error: returning `s.bar()` escapes a reference to local variable `s`
 fail_compilation/fail_scope.d(136): Error: returning `foo16226(i)` escapes a reference to local variable `i`
 ---
-//fail_compilation/fail_scope.d(30): Error: scope variable `da` may not be returned
-//fail_compilation/fail_scope.d(32): Error: scope variable `o` may not be returned
-//fail_compilation/fail_scope.d(33): Error: scope variable `dg` may not be returned
-//fail_compilation/fail_scope.d(35): Error: scope variable `da` may not be returned
-//fail_compilation/fail_scope.d(37): Error: scope variable `o` may not be returned
-//fail_compilation/fail_scope.d(38): Error: scope variable `dg` may not be returned
-//fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned
 */
 
 alias int delegate() dg_t;
 
-int[]  checkEscapeScope1(scope int[]  da) { return da; }
-int[3] checkEscapeScope2(scope int[3] sa) { return sa; }
-Object checkEscapeScope3(scope Object o)  { return o;  }
-dg_t   checkEscapeScope4(scope dg_t   dg) { return dg; }
+int[]  checkEscapeScope1(scope int[]  da) @safe { return da; }
+int[3] checkEscapeScope2(scope int[3] sa) @safe { return sa; }
+Object checkEscapeScope3(scope Object o)  @safe { return o;  }
+dg_t   checkEscapeScope4(scope dg_t   dg) @safe { return dg; }
 
-int[]  checkEscapeScope1() { scope int[]  da = [];           return da; }
-int[3] checkEscapeScope2() { scope int[3] sa = [1,2,3];      return sa; }
-Object checkEscapeScope3() { scope Object  o = new Object;   return o;  }   // same with fail7294.d
-dg_t   checkEscapeScope4() { scope dg_t   dg = () => 1;      return dg; }
+int[]  checkEscapeScope1() @safe { scope int[]  da = [];           return da; }
+int[3] checkEscapeScope2() @safe { scope int[3] sa = [1,2,3];      return sa; }
+Object checkEscapeScope3() @safe { scope Object  o = new Object;   return o;  }   // same with fail7294.d
+dg_t   checkEscapeScope4() @safe { scope dg_t   dg = () => 1;      return dg; }
 
 int* test(scope int* p) @safe { return p; }
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
index 7e68bfc4702..6d5807b641a 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/retscope6.d
@@ -201,8 +201,8 @@  void hmac(scope ubyte[] secret)
 
 /* TEST_OUTPUT:
 ---
-fail_compilation/retscope6.d(12011): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_m_20150
-fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assigned to non-scope parameter `r` calling retscope6.escape_c_20150
+fail_compilation/retscope6.d(12011): Error: returning `escape_m_20150(& x)` escapes a reference to local variable `x`
+fail_compilation/retscope6.d(12022): Error: returning `escape_c_20150(& x)` escapes a reference to local variable `x`
 ---
 */
 
@@ -210,23 +210,23 @@  fail_compilation/retscope6.d(12022): Error: reference to local variable `x` assi
 
 // https://issues.dlang.org/show_bug.cgi?id=20150
 
-int* escape_m_20150(int* r) @safe pure
+int* escape_m_20150(int* r) @safe pure nothrow
 {
     return r;
 }
 
-int* f_m_20150() @safe
+int* f_m_20150() @safe nothrow
 {
     int x = 42;
     return escape_m_20150(&x);
 }
 
-const(int)* escape_c_20150(const int* r) @safe pure
+const(int)* escape_c_20150(const int* r) @safe pure nothrow
 {
     return r;
 }
 
-const(int)* f_c_20150() @safe
+const(int)* f_c_20150() @safe nothrow
 {
     int x = 42;
     return escape_c_20150(&x);
@@ -251,3 +251,39 @@  void escape_throw_20150() @safe
     immutable(char)[4] str;
     f_throw(str[]);
 }
+
+/* TEST_OUTPUT:
+---
+fail_compilation/retscope6.d(14019): Error: scope variable `scopePtr` assigned to non-scope parameter `x` calling retscope6.noInfer23021
+fail_compilation/retscope6.d(14022): Error: scope variable `scopePtr` may not be returned
+---
+*/
+
+#line 14000
+// https://issues.dlang.org/show_bug.cgi?id=23021
+
+ref int infer23021(ref int* x) @safe pure nothrow
+{
+    return *x;
+}
+
+ref int noInfer23021(ref int* x, const(int)** escapeHole = null) @safe pure nothrow
+{
+    *escapeHole = x;
+    return *x;
+}
+
+ref int escape23021() @safe
+{
+    scope int* scopePtr;
+    int* nonScopePtr = null;
+
+    // don't infer scope
+    cast(void) noInfer23021(scopePtr); // error
+
+    // ensure we infer return scope
+    return infer23021(scopePtr); // error
+
+    // ensure we do not infer return ref
+    return infer23021(nonScopePtr); // no error
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22999.d b/gcc/testsuite/gdc.test/fail_compilation/test22999.d
new file mode 100644
index 00000000000..99dfe70378b
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22999.d
@@ -0,0 +1,27 @@ 
+/*
+REQUIRED_ARGS: -de
+TEST_OUTPUT:
+---
+fail_compilation/test22999.d(18): Deprecation: switch case fallthrough - use 'goto default;' if intended
+fail_compilation/test22999.d(25): Deprecation: switch case fallthrough - use 'goto case;' if intended
+---
+*/
+
+// no switch fallthrough error with multi-valued case
+// https://issues.dlang.org/show_bug.cgi?id=22999
+void main()
+{
+    int i;
+    switch (0)
+    {
+        case 0, 1: i = 20;
+        default: assert(0);
+    }
+
+    switch (0)
+    {
+        default:
+        case 0, 1: i = 20;
+        case 2, 3: i = 30;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test23017.d b/gcc/testsuite/gdc.test/fail_compilation/test23017.d
new file mode 100644
index 00000000000..743789a6b52
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test23017.d
@@ -0,0 +1,20 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test23017.d(16): Error: class `test23017.CppChildA` with C++ linkage cannot inherit from class `DClass` with D linkage
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=23017
+// C++ class may not derive from D class
+extern(D) class DClass {}
+extern(C++) class CppClass
+{
+    void foo();
+}
+
+extern(C++) class CppChildA : DClass {} // error
+extern(C++) class CppChildB : CppClass {}
+
+extern(D) class DChildA : DClass {}
+extern(D) class DChildB : CppClass {} // automatically made extern(C++)
diff --git a/gcc/testsuite/gdc.test/runnable/testscope.d b/gcc/testsuite/gdc.test/runnable/testscope.d
index 32d66b58c76..0ca04df188d 100644
--- a/gcc/testsuite/gdc.test/runnable/testscope.d
+++ b/gcc/testsuite/gdc.test/runnable/testscope.d
@@ -242,22 +242,6 @@  void test7435() {
 
 /********************************************/
 
-char[] dup12()(char[] a) // although inferred pure, don't infer a is 'return'
-{
-    char[] res;
-    foreach (ref e; a)
-    {}
-    return res;
-}
-
-char[] foo12()
-{
-    char[10] buf;
-    return dup12(buf);
-}
-
-/********************************************/
-
 void test7049() @safe
 {
     int count = 0;
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 5e2566c9ceb..e08d9cdc0fd 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-9ba9a6ae2b8f6811cb85107cb56701df04f36ac6
+27834edb5e1613e3abd43e09880c36d9fc961938
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.
diff --git a/libphobos/libdruntime/core/exception.d b/libphobos/libdruntime/core/exception.d
index a6928660773..81aa43b27d0 100644
--- a/libphobos/libdruntime/core/exception.d
+++ b/libphobos/libdruntime/core/exception.d
@@ -19,29 +19,6 @@  void __switch_errorT()(string file = __FILE__, size_t line = __LINE__) @trusted
         assert(0, "No appropriate switch clause found");
 }
 
-version (D_BetterC)
-{
-    // When compiling with -betterC we use template functions so if they are
-    // used the bodies are copied into the user's program so there is no need
-    // for the D runtime during linking.
-
-    // In the future we might want to convert all functions in this module to
-    // templates even for ordinary builds instead of providing them as an
-    // extern(C) library.
-
-    void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
-    {
-        assert(0, "Memory allocation failed");
-    }
-    alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
-
-    void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
-    {
-        assert(0, "Invalid memory operation");
-    }
-}
-else:
-
 /**
  * Thrown on a range error.
  */
@@ -218,17 +195,17 @@  private void rangeMsgPut(ref char[] r, scope const(char)[] e) @nogc nothrow pure
  */
 class AssertError : Error
 {
-    @safe pure nothrow this( string file, size_t line )
+    @safe pure nothrow @nogc this( string file, size_t line )
     {
         this(cast(Throwable)null, file, line);
     }
 
-    @safe pure nothrow this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
+    @safe pure nothrow @nogc this( Throwable next, string file = __FILE__, size_t line = __LINE__ )
     {
         this( "Assertion failure", file, line, next);
     }
 
-    @safe pure nothrow this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
+    @safe pure nothrow @nogc this( string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null )
     {
         super( msg, file, line, next );
     }
@@ -692,26 +669,49 @@  extern (C) void onFinalizeError( TypeInfo info, Throwable e, string file = __FIL
     throw staticError!FinalizeError(info, e, file, line);
 }
 
-/**
- * A callback for out of memory errors in D.  An $(LREF OutOfMemoryError) will be
- * thrown.
- *
- * Throws:
- *  $(LREF OutOfMemoryError).
- */
-extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+version (D_BetterC)
 {
-    // NOTE: Since an out of memory condition exists, no allocation must occur
-    //       while generating this object.
-    throw staticError!OutOfMemoryError();
-}
+    // When compiling with -betterC we use template functions so if they are
+    // used the bodies are copied into the user's program so there is no need
+    // for the D runtime during linking.
 
-extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
-{
-    // suppress stacktrace until they are @nogc
-    throw staticError!OutOfMemoryError(false);
+    // In the future we might want to convert all functions in this module to
+    // templates even for ordinary builds instead of providing them as an
+    // extern(C) library.
+
+    void onOutOfMemoryError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
+    {
+        assert(0, "Memory allocation failed");
+    }
+    alias onOutOfMemoryErrorNoGC = onOutOfMemoryError;
+
+    void onInvalidMemoryOperationError()(void* pretend_sideffect = null) @nogc nothrow pure @trusted
+    {
+        assert(0, "Invalid memory operation");
+    }
 }
+else
+{
+    /**
+     * A callback for out of memory errors in D.  An $(LREF OutOfMemoryError) will be
+     * thrown.
+     *
+     * Throws:
+     *  $(LREF OutOfMemoryError).
+     */
+    extern (C) void onOutOfMemoryError(void* pretend_sideffect = null) @trusted pure nothrow @nogc /* dmd @@@BUG11461@@@ */
+    {
+        // NOTE: Since an out of memory condition exists, no allocation must occur
+        //       while generating this object.
+        throw staticError!OutOfMemoryError();
+    }
 
+    extern (C) void onOutOfMemoryErrorNoGC() @trusted nothrow @nogc
+    {
+        // suppress stacktrace until they are @nogc
+        throw staticError!OutOfMemoryError(false);
+    }
+}
 
 /**
  * A callback for invalid memory operations in D.  An
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index a15616c6e0f..e58afa2f985 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -2830,8 +2830,8 @@  extern (C)
 
     private struct AA { void* impl; }
     // size_t _aaLen(in AA aa) pure nothrow @nogc;
-    private void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
-    private void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
+    private void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey) pure nothrow;
+    private void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti, const size_t valsz, const scope void* pkey, out bool found) pure nothrow;
     // inout(void)* _aaGetRvalueX(inout AA aa, in TypeInfo keyti, in size_t valsz, in void* pkey);
     inout(void[]) _aaValues(inout AA aa, const size_t keysz, const size_t valsz, const TypeInfo tiValueArray) pure nothrow;
     inout(void[]) _aaKeys(inout AA aa, const size_t keysz, const TypeInfo tiKeyArray) pure nothrow;
diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d
index 0c38622a879..ab93f191634 100644
--- a/libphobos/libdruntime/rt/aaA.d
+++ b/libphobos/libdruntime/rt/aaA.d
@@ -504,7 +504,7 @@  extern (C) size_t _aaLen(scope const AA aa) pure nothrow @nogc
  *      If key was not in the aa, a mutable pointer to newly inserted value which
  *      is set to all zeros
  */
-extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti,
+extern (C) void* _aaGetY(scope AA* paa, const TypeInfo_AssociativeArray ti,
     const size_t valsz, scope const void* pkey)
 {
     bool found;
@@ -525,7 +525,7 @@  extern (C) void* _aaGetY(AA* paa, const TypeInfo_AssociativeArray ti,
  *      If key was not in the aa, a mutable pointer to newly inserted value which
  *      is set to all zeros
  */
-extern (C) void* _aaGetX(AA* paa, const TypeInfo_AssociativeArray ti,
+extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti,
     const size_t valsz, scope const void* pkey, out bool found)
 {
     // lazily alloc implementation
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 0feb0b01ef5..3218ace50a0 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-c0cc5e917db105301dd1199b4b3c854626526407
+ac296f80cda437483b743f953dc69cb1271c82df
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/Makefile.am b/libphobos/src/Makefile.am
index 75f83974e99..da7a2004ff8 100644
--- a/libphobos/src/Makefile.am
+++ b/libphobos/src/Makefile.am
@@ -130,7 +130,7 @@  PHOBOS_DSOURCES = etc/c/curl.d etc/c/zlib.d std/algorithm/comparison.d \
 	std/experimental/typecons.d std/file.d std/format/internal/floats.d \
 	std/format/internal/read.d std/format/internal/write.d \
 	std/format/package.d std/format/read.d std/format/spec.d \
-	std/format/write.d std/functional.d std/getopt.d \
+	std/format/write.d std/functional.d std/getopt.d std/int128.d \
 	std/internal/attributes.d std/internal/cstring.d \
 	std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
 	std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
diff --git a/libphobos/src/Makefile.in b/libphobos/src/Makefile.in
index f2395e2caf7..6f58fee01ac 100644
--- a/libphobos/src/Makefile.in
+++ b/libphobos/src/Makefile.in
@@ -228,6 +228,7 @@  am__dirstamp = $(am__leading_dot)dirstamp
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/spec.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/write.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/functional.lo std/getopt.lo \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/int128.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/attributes.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/cstring.lo \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/math/biguintcore.lo \
@@ -591,7 +592,7 @@  libgphobos_la_LINK = $(LIBTOOL) --tag=D $(libgphobos_la_LIBTOOLFLAGS) \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/experimental/typecons.d std/file.d std/format/internal/floats.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/internal/read.d std/format/internal/write.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/package.d std/format/read.d std/format/spec.d \
-@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/write.d std/functional.d std/getopt.d \
+@ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/format/write.d std/functional.d std/getopt.d std/int128.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/attributes.d std/internal/cstring.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/math/biguintcore.d std/internal/math/biguintnoasm.d \
 @ENABLE_LIBDRUNTIME_ONLY_FALSE@	std/internal/math/errorfunction.d std/internal/math/gammafunction.d \
@@ -846,6 +847,7 @@  std/format/spec.lo: std/format/$(am__dirstamp)
 std/format/write.lo: std/format/$(am__dirstamp)
 std/functional.lo: std/$(am__dirstamp)
 std/getopt.lo: std/$(am__dirstamp)
+std/int128.lo: std/$(am__dirstamp)
 std/internal/$(am__dirstamp):
 	@$(MKDIR_P) std/internal
 	@: > std/internal/$(am__dirstamp)
diff --git a/libphobos/src/std/base64.d b/libphobos/src/std/base64.d
index 866f7005060..d971dba1c71 100644
--- a/libphobos/src/std/base64.d
+++ b/libphobos/src/std/base64.d
@@ -63,7 +63,7 @@  import std.range.primitives : empty, front, isInputRange, isOutputRange,
 import std.traits : isArray;
 
 // Make sure module header code examples work correctly.
-@safe unittest
+pure @safe unittest
 {
     ubyte[] data = [0x14, 0xfb, 0x9c, 0x03, 0xd9, 0x7e];
 
@@ -82,7 +82,7 @@  import std.traits : isArray;
 alias Base64 = Base64Impl!('+', '/');
 
 ///
-@safe unittest
+pure @safe unittest
 {
     ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
     assert(Base64.encode(data) == "g9cwegE/");
@@ -98,7 +98,7 @@  alias Base64 = Base64Impl!('+', '/');
 alias Base64URL = Base64Impl!('-', '_');
 
 ///
-@safe unittest
+pure @safe unittest
 {
     ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
     assert(Base64URL.encode(data) == "g9cwegE_");
@@ -114,7 +114,7 @@  alias Base64URL = Base64Impl!('-', '_');
 alias Base64URLNoPadding = Base64Impl!('-', '_', Base64.NoPadding);
 
 ///
-@safe unittest
+pure @safe unittest
 {
     ubyte[] data = [0x83, 0xd7, 0x30, 0x7b, 0xef];
     assert(Base64URLNoPadding.encode(data) == "g9cwe-8");
@@ -180,7 +180,7 @@  template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      * Returns:
      *  The length of a Base64 encoding of an array of the given length.
      */
-    @safe
+    @safe @nogc
     pure nothrow size_t encodeLength(in size_t sourceLength)
     {
         static if (Padding == NoPadding)
@@ -218,8 +218,8 @@  template Base64Impl(char Map62th, char Map63th, char Padding = '=')
      *  The slice of $(D_PARAM buffer) that contains the encoded string.
      */
     @trusted
-    pure char[] encode(R1, R2)(in R1 source, return scope R2 buffer) if (isArray!R1 && is(ElementType!R1 : ubyte) &&
-                                                            is(R2 == char[]))
+    pure char[] encode(R1, R2)(const scope R1 source, return scope R2 buffer)
+    if (isArray!R1 && is(ElementType!R1 : ubyte) && is(R2 == char[]))
     in
     {
         assert(buffer.length >= encodeLength(source.length), "Insufficient buffer for encoding");
@@ -277,9 +277,9 @@  template Base64Impl(char Map62th, char Map63th, char Padding = '=')
     }
 
     ///
-    @safe unittest
+    @nogc nothrow @safe unittest
     {
-        ubyte[] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
+        ubyte[6] data = [0x83, 0xd7, 0x30, 0x7a, 0x01, 0x3f];
         char[32] buffer;    // much bigger than necessary
 
         // Just to be sure...
@@ -287,7 +287,7 @@  template Base64Impl(char Map62th, char Map63th, char Padding = '=')
         assert(buffer.length >= encodedLength);
 
         // encode() returns a slice to the provided buffer.
-        auto encoded = Base64.encode(data, buffer[]);
+        auto encoded = Base64.encode(data[], buffer[]);
         assert(encoded is buffer[0 .. encodedLength]);
         assert(encoded == "g9cwegE/");
     }
diff --git a/libphobos/src/std/int128.d b/libphobos/src/std/int128.d
new file mode 100644
index 00000000000..fc992f82422
--- /dev/null
+++ b/libphobos/src/std/int128.d
@@ -0,0 +1,374 @@ 
+// Written in the D programming language
+/**
+ * Implements a signed 128 bit integer type.
+ *
+    Author:     Walter Bright
+    Copyright:  Copyright (c) 2022, D Language Foundation
+    License:    $(HTTP boost.org/LICENSE_1_0.txt, Boost License 1.0)
+    Source:     $(PHOBOSSRC std/int128.d)
+ */
+module std.int128;
+
+private import core.int128;
+
+
+/***********************************
+ * 128 bit signed integer type.
+ */
+
+public struct Int128
+{
+  @safe pure nothrow @nogc:
+
+    Cent data;          /// core.int128.Cent
+
+    /****************
+     * Construct an `Int128` from a `long` value.
+     * The upper 64 bits are formed by sign extension.
+     * Params:
+     *  lo = signed lower 64 bits
+     */
+    this(long lo)
+    {
+        data.lo = lo;
+        data.hi = lo < 0 ? ~0L : 0;
+    }
+
+    /****************
+     * Construct an `Int128` from a `ulong` value.
+     * The upper 64 bits are set to zero.
+     * Params:
+     *  lo = unsigned lower 64 bits
+     */
+    this(ulong lo)
+    {
+        data.lo = lo;
+        data.hi = 0;
+    }
+
+    /****************
+     * Construct an `Int128` from a `long` value.
+     * Params:
+     *  hi = upper 64 bits
+     *  lo = lower 64 bits
+     */
+    this(long hi, long lo)
+    {
+        data.hi = hi;
+        data.lo = lo;
+    }
+
+    /********************
+     * Construct an `Int128` from a `Cent`.
+     * Params:
+     *  data = Cent data
+     */
+    this(Cent data)
+    {
+        this.data = data;
+    }
+
+    /********************
+     * Returns: hash value for Int128
+     */
+    size_t toHash() const
+    {
+        return cast(size_t)((data.lo & 0xFFFF_FFFF) + (data.hi & 0xFFFF_FFFF) + (data.lo >> 32) + (data.hi >> 32));
+    }
+
+    /************************
+     * Compare for equality
+     * Params: lo = signed value to compare with
+     * Returns: true if Int128 equals value
+     */
+    bool opEquals(long lo) const
+    {
+        return data.lo == lo && data.hi == (lo >> 63);
+    }
+
+    /************************
+     * Compare for equality
+     * Params: lo = unsigned value to compare with
+     * Returns: true if Int128 equals value
+     */
+    bool opEquals(ulong lo) const
+    {
+        return data.hi == 0 && data.lo == lo;
+    }
+
+    /************************
+     * Compare for equality
+     * Params: op2 = value to compare with
+     * Returns: true if Int128 equals value
+     */
+    bool opEquals(Int128 op2) const
+    {
+        return data.hi == op2.data.hi && data.lo == op2.data.lo;
+    }
+
+    /** Support unary arithmentic operator +
+     * Params: op = "+"
+     * Returns: lvalue of result
+     */
+    Int128 opUnary(string op)() const
+        if (op == "+")
+    {
+        return this;
+    }
+
+    /** Support unary arithmentic operator - ~
+     * Params: op = "-", "~"
+     * Returns: lvalue of result
+     */
+    Int128 opUnary(string op)() const
+        if (op == "-" || op == "~")
+    {
+        static if (op == "-")
+            return Int128(neg(this.data));
+        else static if (op == "~")
+            return Int128(com(this.data));
+    }
+
+    /** Support unary arithmentic operator ++ --
+     * Params: op = "++", "--"
+     * Returns: lvalue of result
+     */
+    Int128 opUnary(string op)()
+        if (op == "++" || op == "--")
+    {
+        static if (op == "++")
+            this.data = inc(this.data);
+        else static if (op == "--")
+            this.data = dec(this.data);
+        else
+            static assert(0, op);
+        return this;
+    }
+
+    /** Support casting to a bool
+     * Params: T = bool
+     * Returns: boolean result
+     */
+    bool opCast(T : bool)() const
+    {
+        return tst(this.data);
+    }
+
+    /** Support binary arithmetic operators + - * / % & | ^ << >> >>>
+     * Params:
+     *   op = one of the arithmetic binary operators
+     *   op2 = second operand
+     * Returns: value after the operation is applied
+     */
+    Int128 opBinary(string op)(Int128 op2) const
+        if (op == "+" || op == "-" ||
+            op == "*" || op == "/" || op == "%" ||
+            op == "&" || op == "|" || op == "^")
+    {
+        static if (op == "+")
+            return Int128(add(this.data, op2.data));
+        else static if (op == "-")
+            return Int128(sub(this.data, op2.data));
+        else static if (op == "*")
+            return Int128(mul(this.data, op2.data));
+        else static if (op == "/")
+            return Int128(div(this.data, op2.data));
+        else static if (op == "%")
+        {
+            Cent modulus;
+            divmod(this.data, op2.data, modulus);
+            return Int128(modulus);
+        }
+        else static if (op == "&")
+            return Int128(and(this.data, op2.data));
+        else static if (op == "|")
+            return Int128(or(this.data, op2.data));
+        else static if (op == "^")
+            return Int128(xor(this.data, op2.data));
+        else
+            static assert(0, "wrong op value");
+    }
+
+    /// ditto
+    Int128 opBinary(string op)(long op2) const
+        if (op == "+" || op == "-" ||
+            op == "*" || op == "/" || op == "%" ||
+            op == "&" || op == "|" || op == "^")
+    {
+        return mixin("this " ~ op ~ " Int128(0, op2)");
+    }
+
+    /// ditto
+    Int128 opBinaryRight(string op)(long op2) const
+        if (op == "+" || op == "-" ||
+            op == "*" || op == "/" || op == "%" ||
+            op == "&" || op == "|" || op == "^")
+    {
+        mixin("return Int128(0, op2) " ~ op ~ " this;");
+    }
+
+    /// ditto
+    Int128 opBinary(string op)(long op2) const
+        if (op == "<<")
+    {
+        return Int128(shl(this.data, cast(uint) op2));
+    }
+
+    /// ditto
+    Int128 opBinary(string op)(long op2) const
+        if (op == ">>")
+    {
+        return Int128(sar(this.data, cast(uint) op2));
+    }
+
+    /// ditto
+    Int128 opBinary(string op)(long op2) const
+        if (op == ">>>")
+    {
+        return Int128(shr(this.data, cast(uint) op2));
+    }
+
+    /** arithmetic assignment operators += -= *= /= %= &= |= ^= <<= >>= >>>=
+     * Params: op = one of +, -, etc.
+     *   op2 = second operand
+     * Returns: lvalue of updated left operand
+     */
+    ref Int128 opOpAssign(string op)(Int128 op2)
+        if (op == "+" || op == "-" ||
+            op == "*" || op == "/" || op == "%" ||
+            op == "&" || op == "|" || op == "^" ||
+            op == "<<" || op == ">>" || op == ">>>")
+    {
+        mixin("this = this " ~ op ~ " op2;");
+        return this;
+    }
+
+    /// ditto
+    ref Int128 opOpAssign(string op)(long op2)
+        if (op == "+" || op == "-" ||
+            op == "*" || op == "/" || op == "%" ||
+            op == "&" || op == "|" || op == "^" ||
+            op == "<<" || op == ">>" || op == ">>>")
+    {
+        mixin("this = this " ~ op ~ " op2;");
+        return this;
+    }
+
+    /** support signed arithmentic comparison operators < <= > >=
+     * Params: op2 = right hand operand
+     * Returns: -1 for less than, 0 for equals, 1 for greater than
+     */
+    int opCmp(Int128 op2) const
+    {
+        return this == op2 ? 0 : gt(this.data, op2.data) * 2 - 1;
+    }
+
+    /** support signed arithmentic comparison operators < <= > >=
+     * Params: op2 = right hand operand
+     * Returns: -1 for less than, 0 for equals, 1 for greater than
+     */
+    int opCmp(long op2) const
+    {
+        return opCmp(Int128(0, op2));
+    }
+
+    enum min = Int128(long.min, 0);             /// minimum value
+    enum max = Int128(long.max, ulong.max);     /// maximum value
+}
+
+/********************************************* Tests ************************************/
+
+version (unittest)
+{
+import core.stdc.stdio;
+
+@trusted void print(Int128 c)
+{
+    printf("%lld, %lld\n", c.data.hi, c.data.lo);
+}
+
+@trusted void printx(Int128 c)
+{
+    printf("%llx, %llx\n", c.data.hi, c.data.lo);
+}
+}
+
+/// Int128 tests
+@safe pure nothrow @nogc
+unittest
+{
+    Int128 c = Int128(5, 6);
+    assert(c == c);
+    assert(c == +c);
+    assert(c == - -c);
+    assert(~c == Int128(~5, ~6));
+    ++c;
+    assert(c == Int128(5, 7));
+    assert(--c == Int128(5, 6));
+    assert(!!c);
+    assert(!Int128());
+
+    assert(c + Int128(10, 20) == Int128(15, 26));
+    assert(c - Int128(1, 2)   == Int128(4, 4));
+    assert(c * Int128(100, 2) == Int128(610, 12));
+    assert(c / Int128(3, 2)   == Int128(0, 1));
+    assert(c % Int128(3, 2)   == Int128(2, 4));
+    assert((c & Int128(3, 2)) == Int128(1, 2));
+    assert((c | Int128(3, 2)) == Int128(7, 6));
+    assert((c ^ Int128(3, 2)) == Int128(6, 4));
+
+    assert(c + 15   == Int128(5, 21));
+    assert(c - 15   == Int128(4, -9));
+    assert(c * 15   == Int128(75, 90));
+    assert(c / 15   == Int128(0, 6148914691236517205));
+    assert(c % 15   == Int128(0, 11));
+    assert((c & 15) == Int128(0, 6));
+    assert((c | 15) == Int128(5, 15));
+    assert((c ^ 15) == Int128(5, 9));
+
+    assert(15 + c   == Int128(5, 21));
+    assert(15 - c   == Int128(-5, 9));
+    assert(15 * c   == Int128(75, 90));
+    assert(15 / c   == Int128(0, 0));
+    assert(15 % c   == Int128(0, 15));
+    assert((15 & c) == Int128(0, 6));
+    assert((15 | c) == Int128(5, 15));
+    assert((15 ^ c) == Int128(5, 9));
+
+    assert(c << 1 == Int128(10, 12));
+    assert(-c >> 1 == Int128(-3, 9223372036854775805));
+    assert(-c >>> 1 == Int128(9223372036854775805, 9223372036854775805));
+
+    assert((c += 1) == Int128(5, 7));
+    assert((c -= 1) == Int128(5, 6));
+    assert((c += Int128(0, 1)) == Int128(5, 7));
+    assert((c -= Int128(0, 1)) == Int128(5, 6));
+    assert((c *= 2) == Int128(10, 12));
+    assert((c /= 2) == Int128(5, 6));
+    assert((c %= 2) == Int128());
+    c += Int128(5, 6);
+    assert((c *= Int128(10, 20)) == Int128(160, 120));
+    assert((c /= Int128(10, 20)) == Int128(0, 15));
+    c += Int128(72, 0);
+    assert((c %= Int128(10, 20)) == Int128(1, -125));
+    assert((c &= Int128(3, 20)) == Int128(1, 0));
+    assert((c |= Int128(8, 2)) == Int128(9, 2));
+    assert((c ^= Int128(8, 2)) == Int128(1, 0));
+    c |= Int128(10, 5);
+    assert((c <<= 1) == Int128(11 * 2, 5 * 2));
+    assert((c >>>= 1) == Int128(11, 5));
+    c = Int128(long.min, long.min);
+    assert((c >>= 1) == Int128(long.min >> 1, cast(ulong) long.min >> 1));
+
+    assert(-Int128.min == Int128.min);
+    assert(Int128.max + 1 == Int128.min);
+
+    c = Int128(5, 6);
+    assert(c < Int128(6, 5));
+    assert(c > 10);
+
+    c = Int128(-1UL);
+    assert(c == -1UL);
+    c = Int128(-1L);
+    assert(c == -1L);
+}
diff --git a/libphobos/src/std/path.d b/libphobos/src/std/path.d
index 20518b86333..de180fcc548 100644
--- a/libphobos/src/std/path.d
+++ b/libphobos/src/std/path.d
@@ -1519,7 +1519,7 @@  if (isSomeChar!C)
     import std.range;
     // ir() wraps an array in a plain (i.e. non-forward) input range, so that
     // we can test both code paths
-    InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p); }
+    InputRange!(C[]) ir(C)(C[][] p...) { return inputRangeObject(p.dup); }
     version (Posix)
     {
         assert(buildPath("foo") == "foo");
diff --git a/libphobos/src/std/traits.d b/libphobos/src/std/traits.d
index 9ca676d312a..18400e3e859 100644
--- a/libphobos/src/std/traits.d
+++ b/libphobos/src/std/traits.d
@@ -1422,6 +1422,11 @@  if (isCallable!func)
             enum val = "val" ~ (name == "val" ? "_" : "");
             enum ptr = "ptr" ~ (name == "ptr" ? "_" : "");
             mixin("
+                enum hasDefaultArg = (PT[i .. i+1] " ~ args ~ ") { return true; };
+            ");
+            static if (is(typeof(hasDefaultArg())))
+            {
+                mixin("
                 // workaround scope escape check, see
                 // https://issues.dlang.org/show_bug.cgi?id=16582
                 // should use return scope once available
@@ -1432,10 +1437,9 @@  if (isCallable!func)
                     auto " ~ val ~ " = " ~ args ~ "[0];
                     auto " ~ ptr ~ " = &" ~ val ~ ";
                     return *" ~ ptr ~ ";
-                };
-            ");
-            static if (is(typeof(get())))
+                };");
                 enum Get = get();
+            }
             else
                 alias Get = void;
                 // If default arg doesn't exist, returns void instead.
@@ -1483,6 +1487,17 @@  if (isCallable!func)
     static foreach (V; Voids) static assert(is(V == void));
 }
 
+// https://issues.dlang.org/show_bug.cgi?id=20182
+@safe pure nothrow @nogc unittest
+{
+    struct S
+    {
+        this(ref S) {}
+    }
+
+    static assert(__traits(compiles, ParameterDefaults!(S.__ctor)));
+}
+
 /**
  * Alternate name for $(LREF ParameterDefaults), kept for legacy compatibility.
  */