diff mbox series

[committed] d: Merge upstream dmd 02a3fafc6, druntime 26b58167, phobos 16cb085b5.

Message ID 20220313131216.1137773-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd 02a3fafc6, druntime 26b58167, phobos 16cb085b5. | expand

Commit Message

Iain Buclaw March 13, 2022, 1:12 p.m. UTC
Hi,

This patch merges the D front-end implementation with upstream dmd
02a3fafc6, as well as the D runtime libraries with druntime 26b58167,
and phobos 16cb085b5, synchronizing with the release of 2.099.0.

D front-end changes:

    - Import dmd v2.099.0.
    - The deprecation period for D1-style operators has ended, any use
      of the D1 overload operators will now result in a compiler error.
    - `scope' as a type constraint on class, struct, union, and enum
      declarations has been deprecated.
    - Fix segmentation fault when emplacing a new front-end Expression
      node during CTFE (PR104835).

D runtime changes:

    - Import druntime v2.099.0.
    - Fix C bindings for stdint types (PR104738).
    - Fix bus error when allocating new array on the GC (PR104742).
    - Fix bus error when allocating new pointer on the GC (PR104745).

Phobos changes:

    - Import phobos v2.099.0.
    - New function `bind' in `std.functional'.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, with
further bootstrap testing on mips64el-linux-gnu and sparc64-linux-gnu
to verify found issues are fixed.  Committed to mainline.

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 02a3fafc6.
	* dmd/VERSION: Update version to v2.099.0.
	* imports.cc (ImportVisitor::visit (EnumDeclaration *)): Don't cache
	decl in front-end AST node.
	(ImportVisitor::visit (AggregateDeclaration *)): Likewise.
	(ImportVisitor::visit (ClassDeclaration *)): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 26b58167.
	* src/MERGE: Merge upstream phobos 16cb085b5.
---
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/VERSION                             |   2 +-
 gcc/d/dmd/common/outbuffer.d                  |  35 ++
 gcc/d/dmd/constfold.d                         |   5 +-
 gcc/d/dmd/cparse.d                            | 265 ++++++++++++-
 gcc/d/dmd/dcast.d                             |   8 +-
 gcc/d/dmd/dclass.d                            |  44 +--
 gcc/d/dmd/declaration.d                       |   7 +-
 gcc/d/dmd/declaration.h                       |   1 +
 gcc/d/dmd/dmodule.d                           |  26 +-
 gcc/d/dmd/dsymbol.d                           |  80 +++-
 gcc/d/dmd/dsymbol.h                           |   7 +-
 gcc/d/dmd/dsymbolsem.d                        |  49 ++-
 gcc/d/dmd/dtemplate.d                         |   6 +-
 gcc/d/dmd/dtoh.d                              |   9 +
 gcc/d/dmd/escape.d                            |  23 +-
 gcc/d/dmd/expression.d                        |  16 +-
 gcc/d/dmd/expressionsem.d                     |  81 +++-
 gcc/d/dmd/importc.d                           |   5 +-
 gcc/d/dmd/lexer.d                             | 344 +++--------------
 gcc/d/dmd/mtype.d                             |  20 +-
 gcc/d/dmd/mtype.h                             |   2 +
 gcc/d/dmd/opover.d                            |  45 ++-
 gcc/d/dmd/optimize.d                          |  53 +--
 gcc/d/dmd/parse.d                             |   6 +-
 gcc/d/dmd/statementsem.d                      | 105 +++---
 gcc/d/dmd/tokens.d                            |  21 --
 gcc/d/dmd/tokens.h                            |   1 -
 gcc/d/dmd/typesem.d                           |  16 +-
 gcc/d/imports.cc                              |   6 +-
 .../gdc.test/compilable/commontype.d          |   9 +-
 gcc/testsuite/gdc.test/compilable/test7172.d  |   5 +
 .../gdc.test/fail_compilation/dep_d1_ops.d    |  82 ++--
 .../gdc.test/fail_compilation/dephexstrings.d |   3 +-
 .../fail_compilation/deprecateopdot.d         |   6 +-
 .../gdc.test/fail_compilation/fail136.d       |   2 +-
 .../gdc.test/fail_compilation/fail18.d        |   2 +-
 .../gdc.test/fail_compilation/fail22780.d     |   3 +-
 .../gdc.test/fail_compilation/fail22827.d     |   9 +
 .../gdc.test/fail_compilation/issue22820.d    |  68 ++++
 .../gdc.test/fail_compilation/lexer1.d        |   4 +-
 .../gdc.test/fail_compilation/lexer2.d        |   8 +-
 .../gdc.test/fail_compilation/opapplyscope.d  |  27 ++
 .../gdc.test/fail_compilation/scope_class.d   |   3 +-
 .../gdc.test/fail_compilation/scope_type.d    |   8 +-
 .../gdc.test/fail_compilation/test15191.d     |  28 +-
 .../gdc.test/fail_compilation/test19097.d     |  44 ++-
 .../gdc.test/fail_compilation/test21008.d     |  41 ++
 .../fail_compilation/test_switch_error.d      |  78 ++++
 .../gdc.test/fail_compilation/typeerrors.d    |  31 +-
 gcc/testsuite/gdc.test/runnable/auto1.d       |   8 +-
 gcc/testsuite/gdc.test/runnable/interpret.d   |   2 +-
 gcc/testsuite/gdc.test/runnable/opover.d      | 352 ++++++++----------
 gcc/testsuite/gdc.test/runnable/sctor2.d      |   7 +-
 gcc/testsuite/gdc.test/runnable/test22136.d   |  25 --
 gcc/testsuite/gdc.test/runnable/testconst.d   |   4 +-
 gcc/testsuite/gdc.test/runnable/xtest46.d     |  18 +-
 gcc/testsuite/gdc.test/runnable/xtest46_gc.d  |   8 -
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/core/internal/gc/bits.d |   4 +-
 libphobos/libdruntime/core/stdc/config.d      |   2 +-
 libphobos/libdruntime/core/stdc/fenv.d        |   2 +
 libphobos/libdruntime/core/stdc/stdint.d      | 314 +++++++++++++---
 libphobos/libdruntime/core/stdcpp/new_.d      |   2 +-
 libphobos/libdruntime/core/sys/windows/stat.d |  61 ++-
 libphobos/libdruntime/rt/lifetime.d           |  11 +-
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/algorithm/setops.d          |   2 +-
 libphobos/src/std/bitmanip.d                  |   3 +-
 libphobos/src/std/datetime/interval.d         |   4 +-
 libphobos/src/std/datetime/systime.d          |   4 +-
 .../std/experimental/allocator/mallocator.d   |   1 +
 libphobos/src/std/functional.d                | 165 ++++++++
 libphobos/src/std/sumtype.d                   |   1 +
 libphobos/src/std/utf.d                       |  12 +-
 75 files changed, 1792 insertions(+), 975 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail22827.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/issue22820.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test21008.d
 delete mode 100644 gcc/testsuite/gdc.test/runnable/test22136.d
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 71dc2b0a155..220088969c5 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-423f19b41089f627808bf16ff21c60c0791712ba
+cbba5f41a32cfed7f22a213d537f8e2dee0b92f7
 
 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 4bb69df8e2c..17724c661f7 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.099.0-rc.1
+v2.099.0
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index fafe90e5357..0705c1880c0 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -662,6 +662,8 @@  struct OutBuffer
         return cast(char)data[i];
     }
 
+    alias opDollar = length;
+
     /***********************************
      * Extract the data as a slice and take ownership of it.
      *
@@ -879,3 +881,36 @@  unittest
     s = unsignedToTempString(29, buf[], 16);
     assert(s == "1d");
 }
+
+unittest
+{
+    OutBuffer buf;
+    buf.writeUTF8(0x0000_0011);
+    buf.writeUTF8(0x0000_0111);
+    buf.writeUTF8(0x0000_1111);
+    buf.writeUTF8(0x0001_1111);
+    buf.writeUTF8(0x0010_0000);
+    assert(buf[] == "\x11\U00000111\U00001111\U00011111\U00100000");
+
+    buf.reset();
+    buf.writeUTF16(0x0000_0011);
+    buf.writeUTF16(0x0010_FFFF);
+    assert(buf[] == cast(string) "\u0011\U0010FFFF"w);
+}
+
+unittest
+{
+    OutBuffer buf;
+    buf.doindent = true;
+
+    const(char)[] s = "abc";
+    buf.writestring(s);
+    buf.level += 1;
+    buf.indent();
+    buf.writestring("abs");
+
+    assert(buf[] == "abc\tabs");
+
+    buf.setsize(4);
+    assert(buf.length == 4);
+}
diff --git a/gcc/d/dmd/constfold.d b/gcc/d/dmd/constfold.d
index 7bc890f9ae2..96ca5207511 100644
--- a/gcc/d/dmd/constfold.d
+++ b/gcc/d/dmd/constfold.d
@@ -1230,7 +1230,7 @@  UnionExp ArrayLength(Type type, Expression e1)
 
 /* Also return EXP.cantExpression if this fails
  */
-UnionExp Index(Type type, Expression e1, Expression e2)
+UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
 {
     UnionExp ue = void;
     Loc loc = e1.loc;
@@ -1255,8 +1255,9 @@  UnionExp Index(Type type, Expression e1, Expression e2)
         TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
         uinteger_t length = tsa.dim.toInteger();
         uinteger_t i = e2.toInteger();
-        if (i >= length)
+        if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds))
         {
+            // C code only checks bounds if an ArrayLiteralExp
             e1.error("array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
             emplaceExp!(ErrorExp)(&ue);
         }
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 3ded10a7346..2edab14c2a4 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -22,6 +22,7 @@  import dmd.identifier;
 import dmd.lexer;
 import dmd.parse;
 import dmd.errors;
+import dmd.root.array;
 import dmd.root.filename;
 import dmd.common.outbuffer;
 import dmd.root.rmem;
@@ -38,6 +39,24 @@  final class CParser(AST) : Parser!AST
     bool addFuncName;           /// add declaration of __func__ to function symbol table
     bool importBuiltins;        /// seen use of C compiler builtins, so import __builtins;
 
+    private
+    {
+        structalign_t packalign;        // current state of #pragma pack alignment
+
+        // #pragma pack stack
+        Array!Identifier* records;      // identifers (or null)
+        Array!structalign_t* packs;     // parallel alignment values
+    }
+
+    /** C allows declaring a function with a typedef:
+     *   typedef int (myfunc)(); myfunc fun;
+     * but we need to distinguish `fun` being a function as opposed to a variable in the
+     * parse pass. This is accomplished by having a simple symbol table of typedefs
+     * where we know, by syntax, if they are function types or non-function types.
+     * funcTypeIds is the symbol table, of the identifiers of typedefs of function types.
+     */
+    AST.Identifiers funcTypeIds;  /// Identifiers in this are typedefs of function types
+
     extern (D) this(TARGET)(AST.Module _module, const(char)[] input, bool doDocComment,
                             const ref TARGET target)
     {
@@ -47,6 +66,7 @@  final class CParser(AST) : Parser!AST
         mod = _module;
         linkage = LINK.c;
         Ccompile = true;
+        this.packalign.setDefault();
 
         // Configure sizes for C `long`, `long double`, `wchar_t`, ...
         this.boolsize = target.boolsize;
@@ -130,6 +150,7 @@  final class CParser(AST) : Parser!AST
 
         //printf("cparseStatement()\n");
 
+        const funcTypeIdsLengthSave = funcTypeIds.length;
         auto symbolsSave = symbols;
         if (!(flags & (ParseStatementFlags.scope_ | ParseStatementFlags.curlyScope)))
             symbols = new AST.Dsymbols();
@@ -572,6 +593,7 @@  final class CParser(AST) : Parser!AST
         if (pEndloc)
             *pEndloc = prevloc;
         symbols = symbolsSave;
+        funcTypeIds.setDim(funcTypeIdsLengthSave);
         return s;
     }
 
@@ -1551,6 +1573,7 @@  final class CParser(AST) : Parser!AST
             return;
         }
 
+        const funcTypeIdsLengthSave = funcTypeIds.length;
         auto symbolsSave = symbols;
         Specifier specifier;
         specifier.packalign = this.packalign;
@@ -1660,11 +1683,13 @@  final class CParser(AST) : Parser!AST
                 t.value == TOK.leftCurly)  // start of compound-statement
             {
                 auto s = cparseFunctionDefinition(id, dt.isTypeFunction(), specifier);
+                funcTypeIds.setDim(funcTypeIdsLengthSave);
                 symbols = symbolsSave;
                 symbols.push(s);
                 return;
             }
             AST.Dsymbol s = null;
+            funcTypeIds.setDim(funcTypeIdsLengthSave);
             symbols = symbolsSave;
             if (!symbols)
                 symbols = new AST.Dsymbols;     // lazilly create it
@@ -1722,6 +1747,10 @@  final class CParser(AST) : Parser!AST
                         }
                     }
                 }
+                else if (isFunctionTypedef(dt))
+                {
+                    funcTypeIds.push(id);       // remember function typedefs
+                }
                 if (isalias)
                     s = new AST.AliasDeclaration(token.loc, id, dt);
             }
@@ -1743,7 +1772,8 @@  final class CParser(AST) : Parser!AST
                 }
                 // declare the symbol
                 assert(id);
-                if (dt.isTypeFunction())
+
+                if (isFunctionTypedef(dt))
                 {
                     if (hasInitializer)
                         error("no initializer for function declaration");
@@ -4546,5 +4576,238 @@  final class CParser(AST) : Parser!AST
         return s;
     }
 
+    /********************************
+     * Determines if type t is a function type.
+     * Make this work without needing semantic analysis.
+     * Params:
+     *  t = type to test
+     * Returns:
+     *  true if it represents a function
+     */
+    bool isFunctionTypedef(AST.Type t)
+    {
+        //printf("isFunctionTypedef() %s\n", t.toChars());
+        if (t.isTypeFunction())
+            return true;
+        if (auto tid = t.isTypeIdentifier())
+        {
+            /* Scan array of typedef identifiers that are an alias for
+             * a function type
+             */
+            foreach (ftid; funcTypeIds[])
+            {
+                if (tid.ident == ftid)
+                {
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    //}
+
+    /******************************************************************************/
+    /********************************* Directive Parser ***************************/
+    //{
+
+    override bool parseSpecialTokenSequence()
+    {
+        Token n;
+        scan(&n);
+        if (n.value == TOK.int32Literal)
+        {
+            poundLine(n, true);
+            return true;
+        }
+        if (n.value == TOK.identifier)
+        {
+            if (n.ident == Id.line)
+            {
+                poundLine(n, false);
+                return true;
+            }
+            else if (n.ident == Id.__pragma)
+            {
+                pragmaDirective(scanloc);
+                return true;
+            }
+        }
+        error("C preprocessor directive `#%s` is not supported", n.toChars());
+        return false;
+    }
+
+    /*********************************************
+     * C11 6.10.6 Pragma directive
+     * # pragma pp-tokens(opt) new-line
+     * The C preprocessor sometimes leaves pragma directives in
+     * the preprocessed output. Ignore them.
+     * Upon return, p is at start of next line.
+     */
+    private void pragmaDirective(const ref Loc loc)
+    {
+        Token n;
+        scan(&n);
+        if (n.value == TOK.identifier && n.ident == Id.pack)
+            return pragmaPack(loc);
+        skipToNextLine();
+    }
+
+    /*********
+     * # pragma pack
+     * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
+     * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
+     * Scanner is on the `pack`
+     * Params:
+     *  startloc = location to use for error messages
+     */
+    private void pragmaPack(const ref Loc startloc)
+    {
+        const loc = startloc;
+        Token n;
+        scan(&n);
+        if (n.value != TOK.leftParenthesis)
+        {
+            error(loc, "left parenthesis expected to follow `#pragma pack`");
+            skipToNextLine();
+            return;
+        }
+
+        void closingParen()
+        {
+            if (n.value != TOK.rightParenthesis)
+            {
+                error(loc, "right parenthesis expected to close `#pragma pack(`");
+            }
+            skipToNextLine();
+        }
+
+        void setPackAlign(ref const Token t)
+        {
+            const n = t.unsvalue;
+            if (n < 1 || n & (n - 1) || ushort.max < n)
+                error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
+            packalign.set(cast(uint)n);
+            packalign.setPack(true);
+        }
+
+        scan(&n);
+
+        if (!records)
+        {
+            records = new Array!Identifier;
+            packs = new Array!structalign_t;
+        }
+
+        /* # pragma pack ( show )
+         */
+        if (n.value == TOK.identifier && n.ident == Id.show)
+        {
+            if (packalign.isDefault())
+                warning(startloc, "current pack attribute is default");
+            else
+                warning(startloc, "current pack attribute is %d", packalign.get());
+            scan(&n);
+            return closingParen();
+        }
+        /* # pragma pack ( push )
+         * # pragma pack ( push , identifier )
+         * # pragma pack ( push , integer )
+         * # pragma pack ( push , identifier , integer )
+         */
+        if (n.value == TOK.identifier && n.ident == Id.push)
+        {
+            scan(&n);
+            Identifier record = null;
+            if (n.value == TOK.comma)
+            {
+                scan(&n);
+                if (n.value == TOK.identifier)
+                {
+                    record = n.ident;
+                    scan(&n);
+                    if (n.value == TOK.comma)
+                    {
+                        scan(&n);
+                        if (n.value == TOK.int32Literal)
+                        {
+                            setPackAlign(n);
+                            scan(&n);
+                        }
+                        else
+                            error(loc, "alignment value expected, not `%s`", n.toChars());
+                    }
+                }
+                else if (n.value == TOK.int32Literal)
+                {
+                    setPackAlign(n);
+                    scan(&n);
+                }
+                else
+                    error(loc, "alignment value expected, not `%s`", n.toChars());
+            }
+            this.records.push(record);
+            this.packs.push(packalign);
+            return closingParen();
+        }
+        /* # pragma pack ( pop )
+         * # pragma pack ( pop PopList )
+         * PopList :
+         *    , IdentifierOrInteger
+         *    , IdentifierOrInteger PopList
+         * IdentifierOrInteger:
+         *      identifier
+         *      integer
+         */
+        if (n.value == TOK.identifier && n.ident == Id.pop)
+        {
+            scan(&n);
+            while (n.value == TOK.comma)
+            {
+                scan(&n);
+                if (n.value == TOK.identifier)
+                {
+                    for (size_t len = this.records.length; len; --len)
+                    {
+                        if ((*this.records)[len - 1] == n.ident)
+                        {
+                            packalign = (*this.packs)[len - 1];
+                            this.records.setDim(len - 1);
+                            this.packs.setDim(len - 1);
+                            break;
+                        }
+                    }
+                    scan(&n);
+                }
+                else if (n.value == TOK.int32Literal)
+                {
+                    setPackAlign(n);
+                    this.records.push(null);
+                    this.packs.push(packalign);
+                    scan(&n);
+                }
+            }
+            return closingParen();
+        }
+        /* # pragma pack ( integer )
+         */
+        if (n.value == TOK.int32Literal)
+        {
+            setPackAlign(n);
+            scan(&n);
+            return closingParen();
+        }
+        /* # pragma pack ( )
+         */
+        if (n.value == TOK.rightParenthesis)
+        {
+            packalign.setDefault();
+            return closingParen();
+        }
+
+        error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
+        skipToNextLine();
+    }
+
     //}
 }
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index f1afa76e53b..69036ada483 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -2443,7 +2443,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         {
             printf("DelegateExp::castTo(this=%s, type=%s, t=%s)\n", e.toChars(), e.type.toChars(), t.toChars());
         }
-        __gshared const(char)* msg = "cannot form delegate due to covariant return type";
+        static immutable msg = "cannot form delegate due to covariant return type";
 
         Type tb = t.toBasetype();
         Type typeb = e.type.toBasetype();
@@ -2453,7 +2453,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
             int offset;
             e.func.tookAddressOf++;
             if (e.func.tintro && e.func.tintro.nextOf().isBaseOf(e.func.type.nextOf(), &offset) && offset)
-                e.error("%s", msg);
+                e.error("%s", msg.ptr);
             auto result = e.copy();
             result.type = t;
             return result;
@@ -2469,7 +2469,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                 {
                     int offset;
                     if (f.tintro && f.tintro.nextOf().isBaseOf(f.type.nextOf(), &offset) && offset)
-                        e.error("%s", msg);
+                        e.error("%s", msg.ptr);
                     if (f != e.func)    // if address not already marked as taken
                         f.tookAddressOf++;
                     auto result = new DelegateExp(e.loc, e.e1, f, false, e.vthis2);
@@ -2477,7 +2477,7 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
                     return result;
                 }
                 if (e.func.tintro)
-                    e.error("%s", msg);
+                    e.error("%s", msg.ptr);
             }
         }
 
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index ce463c023f0..15ac8d91735 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -205,7 +205,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
 
         super(loc, id);
 
-        __gshared const(char)* msg = "only object.d can define this reserved class name";
+        static immutable msg = "only object.d can define this reserved class name";
 
         if (baseclasses)
         {
@@ -232,37 +232,37 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
             if (id == Id.TypeInfo)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.dtypeinfo = this;
             }
             if (id == Id.TypeInfo_Class)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoclass = this;
             }
             if (id == Id.TypeInfo_Interface)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfointerface = this;
             }
             if (id == Id.TypeInfo_Struct)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfostruct = this;
             }
             if (id == Id.TypeInfo_Pointer)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfopointer = this;
             }
             if (id == Id.TypeInfo_Array)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoarray = this;
             }
             if (id == Id.TypeInfo_StaticArray)
@@ -274,61 +274,61 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
             if (id == Id.TypeInfo_AssociativeArray)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoassociativearray = this;
             }
             if (id == Id.TypeInfo_Enum)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoenum = this;
             }
             if (id == Id.TypeInfo_Function)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfofunction = this;
             }
             if (id == Id.TypeInfo_Delegate)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfodelegate = this;
             }
             if (id == Id.TypeInfo_Tuple)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfotypelist = this;
             }
             if (id == Id.TypeInfo_Const)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoconst = this;
             }
             if (id == Id.TypeInfo_Invariant)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoinvariant = this;
             }
             if (id == Id.TypeInfo_Shared)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfoshared = this;
             }
             if (id == Id.TypeInfo_Wild)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfowild = this;
             }
             if (id == Id.TypeInfo_Vector)
             {
                 if (!inObject)
-                    error("%s", msg);
+                    error("%s", msg.ptr);
                 Type.typeinfovector = this;
             }
         }
@@ -336,32 +336,32 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
         if (id == Id.Object)
         {
             if (!inObject)
-                error("%s", msg);
+                error("%s", msg.ptr);
             object = this;
         }
 
         if (id == Id.Throwable)
         {
             if (!inObject)
-                error("%s", msg);
+                error("%s", msg.ptr);
             throwable = this;
         }
         if (id == Id.Exception)
         {
             if (!inObject)
-                error("%s", msg);
+                error("%s", msg.ptr);
             exception = this;
         }
         if (id == Id.Error)
         {
             if (!inObject)
-                error("%s", msg);
+                error("%s", msg.ptr);
             errorException = this;
         }
         if (id == Id.cpp_type_info_ptr)
         {
             if (!inObject)
-                error("%s", msg);
+                error("%s", msg.ptr);
             cpp_type_info_ptr = this;
         }
 
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index cdf9355e94c..585ac2f0b60 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -29,6 +29,7 @@  import dmd.errors;
 import dmd.expression;
 import dmd.func;
 import dmd.globals;
+import dmd.gluelayer;
 import dmd.id;
 import dmd.identifier;
 import dmd.init;
@@ -227,6 +228,8 @@  extern (C++) abstract class Declaration : Dsymbol
       enum wasRead    = 1; // set if AliasDeclaration was read
       enum ignoreRead = 2; // ignore any reads of AliasDeclaration
 
+    Symbol* isym;           // import version of csym
+
     // overridden symbol with pragma(mangle, "...")
     const(char)[] mangleOverride;
 
@@ -679,10 +682,12 @@  extern (C++) final class TupleDeclaration : Declaration
 }
 
 /***********************************************************
+ * https://dlang.org/spec/declaration.html#AliasDeclaration
  */
 extern (C++) final class AliasDeclaration : Declaration
 {
-    Dsymbol aliassym;
+    Dsymbol aliassym;   // alias ident = aliassym;
+
     Dsymbol overnext;   // next in overload list
     Dsymbol _import;    // !=null if unresolved internal alias for selective import
 
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index e30acb41b2a..93e3a5a0b5d 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -119,6 +119,7 @@  public:
     LINK linkage;
     short inuse;                // used to detect cycles
     uint8_t adFlags;
+    Symbol* isym;               // import version of csym
     DString mangleOverride;     // overridden symbol with pragma(mangle, "...")
 
     const char *kind() const;
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index 6568442c17a..00fa031397c 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -675,24 +675,28 @@  extern (C++) final class Module : Package
 
         //printf("Module::read('%s') file '%s'\n", toChars(), srcfile.toChars());
 
-        if (global.params.emitMakeDeps)
-        {
-            global.params.makeDeps.push(srcfile.toChars());
-        }
 
+
+        bool success;
         if (auto readResult = FileManager.fileManager.lookup(srcfile))
         {
             srcBuffer = readResult;
-            return true;
+            success = true;
         }
-
-        auto readResult = File.read(srcfile.toChars());
-        if (loadSourceBuffer(loc, readResult))
+        else
         {
-            FileManager.fileManager.add(srcfile, srcBuffer);
-            return true;
+            auto readResult = File.read(srcfile.toChars());
+            if (loadSourceBuffer(loc, readResult))
+            {
+                FileManager.fileManager.add(srcfile, srcBuffer);
+                success = true;
+            }
         }
-        return false;
+        if (success && global.params.emitMakeDeps)
+        {
+            global.params.makeDeps.push(srcfile.toChars());
+        }
+        return success;
     }
 
     /// syntactic parse
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 200cb7639c7..f8ada2b1ea1 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -245,8 +245,6 @@  extern (C++) class Dsymbol : ASTNode
     /// C++ namespace this symbol belongs to
     CPPNamespaceDeclaration cppnamespace;
     Symbol* csym;           // symbol for code generator
-    Symbol* isym;           // import version of csym
-    const(char)* comment;   // documentation comment for this Dsymbol
     const Loc loc;          // where defined
     Scope* _scope;          // !=null means context to use for semantic()
     const(char)* prettystring;  // cached value of toPrettyChars()
@@ -257,10 +255,6 @@  extern (C++) class Dsymbol : ASTNode
     DeprecatedDeclaration depdecl;           // customized deprecation message
     UserAttributeDeclaration userAttribDecl;    // user defined attributes
 
-    // !=null means there's a ddoc unittest associated with this symbol
-    // (only use this with ddoc)
-    UnitTestDeclaration ddocUnittest;
-
     final extern (D) this()
     {
         //printf("Dsymbol::Dsymbol(%p)\n", this);
@@ -811,7 +805,7 @@  extern (C++) class Dsymbol : ASTNode
             Dsymbol s2 = sds.symtabLookup(this,ident);
 
             // If using C tag/prototype/forward declaration rules
-            if (sc.flags & SCOPE.Cfile)
+            if (sc.flags & SCOPE.Cfile && !this.isImport())
             {
                 if (handleTagSymbols(*sc, this, s2, sds))
                     return;
@@ -1214,17 +1208,65 @@  extern (C++) class Dsymbol : ASTNode
      */
     void addComment(const(char)* comment)
     {
-        //if (comment)
-        //    printf("adding comment '%s' to symbol %p '%s'\n", comment, this, toChars());
-        if (!this.comment)
-            this.comment = comment;
-        else if (comment && strcmp(cast(char*)comment, cast(char*)this.comment) != 0)
+        if (!comment || !*comment)
+            return;
+
+        //printf("addComment '%s' to Dsymbol %p '%s'\n", comment, this, toChars());
+        void* h = cast(void*)this;      // just the pointer is the key
+        auto p = h in commentHashTable;
+        if (!p)
+        {
+            commentHashTable[h] = comment;
+            return;
+        }
+        if (strcmp(*p, comment) != 0)
         {
             // Concatenate the two
-            this.comment = Lexer.combineComments(this.comment.toDString(), comment.toDString(), true);
+            *p = Lexer.combineComments((*p).toDString(), comment.toDString(), true);
         }
     }
 
+    /// get documentation comment for this Dsymbol
+    final const(char)* comment()
+    {
+        //printf("getcomment: %p '%s'\n", this, this.toChars());
+        if (auto p = cast(void*)this in commentHashTable)
+        {
+            //printf("comment: '%s'\n", *p);
+            return *p;
+        }
+        return null;
+    }
+
+    /* Shell around addComment() to avoid disruption for the moment */
+    final void comment(const(char)* comment) { addComment(comment); }
+
+    private extern (D) __gshared const(char)*[void*] commentHashTable;
+
+
+    /**********************************
+     * Get ddoc unittest associated with this symbol.
+     * (only use this with ddoc)
+     * Returns: ddoc unittest, null if none
+     */
+    final UnitTestDeclaration ddocUnittest()
+    {
+        if (auto p = cast(void*)this in ddocUnittestHashTable)
+            return *p;
+        return null;
+    }
+
+    /**********************************
+     * Set ddoc unittest associated with this symbol.
+     */
+    final void ddocUnittest(UnitTestDeclaration utd)
+    {
+        ddocUnittestHashTable[cast(void*)this] = utd;
+    }
+
+    private extern (D) __gshared UnitTestDeclaration[void*] ddocUnittestHashTable;
+
+
     /****************************************
      * Returns true if this symbol is defined in a non-root module without instantiation.
      */
@@ -1247,6 +1289,18 @@  extern (C++) class Dsymbol : ASTNode
         return false;
     }
 
+    /**
+     * Deinitializes the global state of the compiler.
+     *
+     * This can be used to restore the state set by `_init` to its original
+     * state.
+     */
+    static void deinitialize()
+    {
+        commentHashTable = commentHashTable.init;
+        ddocUnittestHashTable = ddocUnittestHashTable.init;
+    }
+
     /************
      */
     override void accept(Visitor v)
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 03d5c3d2e98..c5af06eb4cd 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -175,8 +175,6 @@  public:
     /// C++ namespace this symbol belongs to
     CPPNamespaceDeclaration *namespace_;
     Symbol *csym;               // symbol for code generator
-    Symbol *isym;               // import version of csym
-    const utf8_t *comment;      // documentation comment for this Dsymbol
     Loc loc;                    // where defined
     Scope *_scope;               // !=NULL means context to use for semantic()
     const utf8_t *prettystring;
@@ -185,7 +183,6 @@  public:
     unsigned short localNum;        // perturb mangled name to avoid collisions with those in FuncDeclaration.localsymtab
     DeprecatedDeclaration *depdecl; // customized deprecation message
     UserAttributeDeclaration *userAttribDecl;   // user defined attributes
-    UnitTestDeclaration *ddocUnittest; // !=NULL means there's a ddoc unittest associated with this symbol (only use this with ddoc)
 
     static Dsymbol *create(Identifier *);
     const char *toChars() const;
@@ -252,6 +249,10 @@  public:
     virtual void checkCtorConstInit() { }
 
     virtual void addComment(const utf8_t *comment);
+    const utf8_t *comment();                      // current value of comment
+
+    UnitTestDeclaration *ddocUnittest();
+    void ddocUnittest(UnitTestDeclaration *);
 
     bool inNonRoot();
 
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index ef25717e79f..b68d840c396 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -2140,6 +2140,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
         Module.dprogress++;
 
+        // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+        // Deprecated in 2.100
+        // Make an error in 2.110
+        if (sc.stc & STC.scope_)
+            deprecation(ed.loc, "`scope` as a type constraint is deprecated.  Use `scope` at the usage site.");
+
         Scope* sce;
         if (ed.isAnonymous())
             sce = sc;
@@ -3085,6 +3091,25 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             return null;
         }
 
+        if (sc.flags & SCOPE.Cfile)
+        {
+            /* C11 allows a function to be declared with a typedef, D does not.
+             */
+            if (auto ti = funcdecl.type.isTypeIdentifier())
+            {
+                auto tj = ti.typeSemantic(funcdecl.loc, sc);
+                if (auto tjf = tj.isTypeFunction())
+                {
+                    /* Copy the type instead of just pointing to it,
+                     * as we don't merge function types
+                     */
+                    auto tjf2 = new TypeFunction(tjf.parameterList, tjf.next, tjf.linkage);
+                    funcdecl.type = tjf2;
+                    funcdecl.originalType = tjf2;
+                }
+            }
+        }
+
         if (!getFunctionType(funcdecl))
             return;
 
@@ -3550,6 +3575,15 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
             default:
                 {
+                    if (vi >= cd.vtbl.length)
+                    {
+                        /* the derived class cd doesn't have its vtbl[] allocated yet.
+                         * https://issues.dlang.org/show_bug.cgi?id=21008
+                         */
+                        funcdecl.error("circular reference to class `%s`", cd.toChars());
+                        funcdecl.errors = true;
+                        return;
+                    }
                     FuncDeclaration fdv = cd.baseClass.vtbl[vi].isFuncDeclaration();
                     FuncDeclaration fdc = cd.vtbl[vi].isFuncDeclaration();
                     // This function is covariant with fdv
@@ -4625,6 +4659,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             sd.deferred.semantic2(sc);
             sd.deferred.semantic3(sc);
         }
+
+        // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+        // Deprecated in 2.100
+        // Make an error in 2.110
+        if (sd.storage_class & STC.scope_)
+            deprecation(sd.loc, "`scope` as a type constraint is deprecated.  Use `scope` at the usage site.");
     }
 
     void interfaceSemantic(ClassDeclaration cd)
@@ -5283,12 +5323,11 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         }
         //printf("-ClassDeclaration.dsymbolSemantic(%s), type = %p, sizeok = %d, this = %p\n", toChars(), type, sizeok, this);
 
-        // @@@DEPRECATED_2.097@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
-        // Deprecated in 2.087
-        // Make an error in 2.091
+        // @@@DEPRECATED_2.110@@@ https://dlang.org/deprecate.html#scope%20as%20a%20type%20constraint
+        // Deprecated in 2.100
+        // Make an error in 2.110
         // Don't forget to remove code at https://github.com/dlang/dmd/blob/b2f8274ba76358607fc3297a1e9f361480f9bcf9/src/dmd/dsymbolsem.d#L1032-L1036
-        if (0 &&          // deprecation disabled for now to accommodate existing extensive use
-            cldec.storage_class & STC.scope_)
+        if (cldec.storage_class & STC.scope_)
             deprecation(cldec.loc, "`scope` as a type constraint is deprecated.  Use `scope` at the usage site.");
     }
 
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 6abe69a9c4f..adb91edec78 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -7806,10 +7806,10 @@  struct TemplateInstanceBox
             /* Used when a proposed instance is used to see if there's
              * an existing instance.
              */
-            static if (__VERSION__ >= 2099)
-                res = (cast()ti).equalsx(cast()s.ti);
-            else // https://issues.dlang.org/show_bug.cgi?id=22717
+            static if (__VERSION__ < 2099) // https://issues.dlang.org/show_bug.cgi?id=22717
                 res = (cast()s.ti).equalsx(cast()ti);
+            else
+                res = (cast()ti).equalsx(cast()s.ti);
         }
 
         debug (FindExistingInstance) ++(res ? nHits : nCollisions);
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index a34e2ccae28..285b834f468 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -180,6 +180,15 @@  struct _d_dynamicArray final
 `);
     }
 
+    // prevent trailing newlines
+    version (Windows)
+        while (buf.length >= 4 && buf[$-4..$] == "\r\n\r\n")
+            buf.remove(buf.length - 2, 2);
+    else
+        while (buf.length >= 2 && buf[$-2..$] == "\n\n")
+            buf.remove(buf.length - 1, 1);
+
+
     if (global.params.cxxhdrname is null)
     {
         // Write to stdout; assume it succeeds
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 35c1f76e600..be11f26b04a 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -497,7 +497,7 @@  bool checkConstructorEscape(Scope* sc, CallExp ce, bool gag)
     {
         Expression arg = (*ce.arguments)[i];
         if (!arg.type.hasPointers())
-            return false;
+            continue;
 
         //printf("\targ[%d]: %s\n", i, arg.toChars());
 
@@ -620,7 +620,7 @@  bool checkAssignEscape(Scope* sc, Expression e, bool gag)
                 return false;
             if (va == fd.vthis) // `this` of a non-static member function is considered to be the first parameter
                 return true;
-            if (fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
+            if (!fd.vthis && fd.parameters && fd.parameters.length && (*fd.parameters)[0] == va) // va is first parameter
                 return true;
         }
         return false;
@@ -1029,7 +1029,6 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
                  */
                 !(p.parent == sc.func))
             {
-                // Only look for errors if in module listed on command line
                 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
                 {
@@ -1095,7 +1094,6 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
             continue;
 
         // https://dlang.org/spec/function.html#return-ref-parameters
-        // Only look for errors if in module listed on command line
         if (p == sc.func)
         {
             //printf("escaping reference to local ref variable %s\n", v.toChars());
@@ -1246,7 +1244,6 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                 !(!refs && sc.func.isFuncDeclaration().getLevel(pfunc, sc.intypeof) > 0)
                )
             {
-                // Only look for errors if in module listed on command line
                 // https://issues.dlang.org/show_bug.cgi?id=17029
                 if (global.params.useDIP1000 == FeatureState.enabled && sc.func.setUnsafe())
                 {
@@ -1278,11 +1275,7 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
     {
         if (log)
         {
-            printf("byref `%s`\n", v.toChars());
-            if (v.storage_class & STC.return_) printf(" return");
-            if (v.storage_class & STC.ref_)    printf(" ref");
-            if (v.storage_class & STC.scope_)  printf(" scope");
-            printf("\n");
+            printf("byref `%s` %s\n", v.toChars(), toChars(buildScopeRef(v.storage_class)));
         }
 
         // 'featureState' tells us whether to emit an error or a deprecation,
@@ -1714,9 +1707,10 @@  void escapeByValue(Expression e, EscapeByResults* er, bool live = false)
                     {
                         Parameter p = tf.parameterList[i - j];
                         const stc = tf.parameterStorageClass(null, p);
-                        if ((stc & (STC.scope_)) && (stc & STC.return_))
+                        ScopeRef psr = buildScopeRef(stc);
+                        if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
                             arg.accept(this);
-                        else if ((stc & (STC.ref_)) && (stc & STC.return_))
+                        else if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                         {
                             if (tf.isref)
                             {
@@ -1974,9 +1968,10 @@  void escapeByRef(Expression e, EscapeByResults* er, bool live = false)
                         {
                             Parameter p = tf.parameterList[i - j];
                             const stc = tf.parameterStorageClass(null, p);
-                            if ((stc & (STC.out_ | STC.ref_)) && (stc & STC.return_))
+                            ScopeRef psr = buildScopeRef(stc);
+                            if (psr == ScopeRef.ReturnRef || psr == ScopeRef.ReturnRef_Scope)
                                 arg.accept(this);
-                            else if ((stc & STC.scope_) && (stc & STC.return_))
+                            else if (psr == ScopeRef.ReturnScope || psr == ScopeRef.Ref_ReturnScope)
                             {
                                 if (auto de = arg.isDelegateExp())
                                 {
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 2b41219846a..45fefc03dea 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -72,10 +72,15 @@  import dmd.typesem;
 import dmd.visitor;
 
 enum LOGSEMANTIC = false;
+
 void emplaceExp(T : Expression, Args...)(void* p, Args args)
 {
-    scope tmp = new T(args);
-    memcpy(p, cast(void*)tmp, __traits(classInstanceSize, T));
+    static if (__VERSION__ < 2099)
+        const init = typeid(T).initializer;
+    else
+        const init = __traits(initSymbol, T);
+    p[0 .. __traits(classInstanceSize, T)] = init[];
+    (cast(T)p).__ctor(args);
 }
 
 void emplaceExp(T : UnionExp)(T* p, Expression e)
@@ -5831,6 +5836,13 @@  extern (C++) final class IndexExp : BinExp
         //printf("IndexExp::IndexExp('%s')\n", toChars());
     }
 
+    extern (D) this(const ref Loc loc, Expression e1, Expression e2, bool indexIsInBounds)
+    {
+        super(loc, EXP.index, __traits(classInstanceSize, IndexExp), e1, e2);
+        this.indexIsInBounds = indexIsInBounds;
+        //printf("IndexExp::IndexExp('%s')\n", toChars());
+    }
+
     override IndexExp syntaxCopy()
     {
         auto ie = new IndexExp(loc, e1.syntaxCopy(), e2.syntaxCopy());
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 6692fb9717e..f8e5af4ac95 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -5279,6 +5279,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     // The mangling change only works for D mangling
                 }
 
+                if (!(sc.flags & SCOPE.Cfile))
                 {
                     /* https://issues.dlang.org/show_bug.cgi?id=21272
                      * If we are in a foreach body we need to extract the
@@ -7057,19 +7058,10 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     return setError();
             }
         }
-        else if (exp.e1.op == EXP.call)
+        else if (auto ce = exp.e1.isCallExp())
         {
-            CallExp ce = cast(CallExp)exp.e1;
-            if (ce.e1.type.ty == Tfunction)
-            {
-                TypeFunction tf = cast(TypeFunction)ce.e1.type;
-                if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
-                    && tf.next.hasPointers() && sc.func.setUnsafe())
-                {
-                    exp.error("cannot take address of `ref return` of `%s()` in `@safe` function `%s`",
-                        ce.e1.toChars(), sc.func.toChars());
-                }
-            }
+            if (!checkAddressCall(sc, ce, "take address of"))
+                return setError();
         }
         else if (exp.e1.op == EXP.index)
         {
@@ -7800,7 +7792,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
 
         Type t1b = exp.e1.type.toBasetype();
-        if (t1b.ty == Tpointer)
+        if (auto tp = t1b.isTypePointer())
         {
             if (t1b.isPtrToFunction())
             {
@@ -7809,7 +7801,27 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
             if (!exp.lwr || !exp.upr)
             {
-                exp.error("need upper and lower bound to slice pointer");
+                exp.error("upper and lower bounds are needed to slice a pointer");
+                if (auto ad = isAggregate(tp.next.toBasetype()))
+                {
+                    auto s = search_function(ad, Id.index);
+                    if (!s) s = search_function(ad, Id.slice);
+                    if (s)
+                    {
+                        auto fd = s.isFuncDeclaration();
+                        if ((fd && !fd.getParameterList().length) || s.isTemplateDeclaration())
+                        {
+                            exp.errorSupplemental(
+                                "pointer `%s` points to an aggregate that defines an `%s`, perhaps you meant `(*%s)[]`",
+                                exp.e1.toChars(),
+                                s.ident.toChars(),
+                                exp.e1.toChars()
+                            );
+                        }
+
+                    }
+                }
+
                 return setError();
             }
             if (sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_) && sc.func.setUnsafe())
@@ -7844,6 +7856,12 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     if (v && !checkAddressVar(sc, exp.e1, v))
                         return setError();
                 }
+                // https://issues.dlang.org/show_bug.cgi?id=22539
+                if (auto ce = exp.e1.isCallExp())
+                {
+                    if (!checkAddressCall(sc, ce, "slice static array of"))
+                        return setError();
+                }
             }
         }
         else if (t1b.ty == Ttuple)
@@ -8446,7 +8464,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 if (length)
                 {
                     auto bounds = IntRange(SignExtendedNumber(0), SignExtendedNumber(length - 1));
-                    exp.indexIsInBounds = bounds.contains(getIntRange(exp.e2));
+                    // OR it in, because it might already be set for C array indexing
+                    exp.indexIsInBounds |= bounds.contains(getIntRange(exp.e2));
                 }
             }
         }
@@ -12943,6 +12962,38 @@  bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
     return true;
 }
 
+/****************************************************
+ * Determine if the address of a `ref return` value of
+ * a function call with type `tf` can be taken safely.
+ *
+ * This is currently stricter than necessary: it can be safe to take the
+ * address of a `ref` with pointer type when the pointer isn't `scope`, but
+ * that involves inspecting the function arguments and parameter types, which
+ * is left as a future enhancement.
+ *
+ * Params:
+ *      sc = context
+ *      ce = function call in question
+ *      action = for the error message, how the pointer is taken, e.g. "slice static array of"
+ * Returns:
+ *      `true` if ok, `false` for error
+ */
+private bool checkAddressCall(Scope* sc, CallExp ce, const(char)* action)
+{
+    if (auto tf = ce.e1.type.isTypeFunction())
+    {
+        if (tf.isref && sc.func && !sc.intypeof && !(sc.flags & SCOPE.debug_)
+            && tf.next.hasPointers() && sc.func.setUnsafe())
+        {
+            ce.error("cannot %s `ref return` of `%s()` in `@safe` function `%s`",
+                action, ce.e1.toChars(), sc.func.toChars());
+            ce.errorSupplemental("return type `%s` has pointers that may be `scope`", tf.next.toChars());
+            return false;
+        }
+    }
+    return true;
+}
+
 /*******************************
  * Checks the attributes of a function.
  * Purity (`pure`), safety (`@safe`), no GC allocations(`@nogc`)
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index a48b339bf50..72e0e1a93a5 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -159,7 +159,8 @@  Expression carraySemantic(ArrayExp ae, Scope* sc)
     if (t1.isTypeDArray() || t1.isTypeSArray())
     {
         e2 = e2.expressionSemantic(sc).arrayFuncConv(sc);
-        return new IndexExp(ae.loc, e1, e2).expressionSemantic(sc);
+        // C doesn't do array bounds checking, so `true` turns it off
+        return new IndexExp(ae.loc, e1, e2, true).expressionSemantic(sc);
     }
 
     e1 = e1.arrayFuncConv(sc);   // e1 might still be a function call
@@ -167,7 +168,7 @@  Expression carraySemantic(ArrayExp ae, Scope* sc)
     auto t2 = e2.type.toBasetype();
     if (t2.isTypeDArray() || t2.isTypeSArray())
     {
-        return new IndexExp(ae.loc, e2, e1).expressionSemantic(sc); // swap operands
+        return new IndexExp(ae.loc, e2, e1, true).expressionSemantic(sc); // swap operands
     }
 
     e2 = e2.arrayFuncConv(sc);
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index 965b3b45f87..dbdf6a503d1 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -68,8 +68,6 @@  class Lexer
     ubyte long_doublesize;      /// size of C long double, 8 or D real.sizeof
     ubyte wchar_tsize;          /// size of C wchar_t, 2 or 4
 
-    structalign_t packalign;    /// current state of #pragma pack alignment (ImportC)
-
     private
     {
         const(char)* base;      // pointer to start of buffer
@@ -89,10 +87,6 @@  class Lexer
         int lastDocLine;        // last line of previous doc comment
 
         Token* tokenFreelist;
-
-        // ImportC #pragma pack stack
-        Array!Identifier* records;      // identifers (or null)
-        Array!structalign_t* packs;     // parallel alignment values
     }
 
   nothrow:
@@ -124,7 +118,6 @@  class Lexer
         this.commentToken = commentToken;
         this.inTokenStringConstant = 0;
         this.lastDocLine = 0;
-        this.packalign.setDefault();
         //initKeywords();
         /* If first line starts with '#!', ignore the line
          */
@@ -381,24 +374,18 @@  class Lexer
                 goto case_ident;
 
             case 'r':
-                if (p[1] != '"')
+                if (Ccompile || p[1] != '"')
                     goto case_ident;
                 p++;
                 goto case '`';
             case '`':
+                if (Ccompile)
+                    goto default;
                 wysiwygStringConstant(t);
                 return;
-            case 'x':
-                if (p[1] != '"')
-                    goto case_ident;
-                p++;
-                auto start = p;
-                OutBuffer hexString;
-                t.value = hexStringConstant(t);
-                hexString.write(start[0 .. p - start]);
-                error("Built-in hex string literals are obsolete, use `std.conv.hexString!%s` instead.", hexString.extractChars());
-                return;
             case 'q':
+                if (Ccompile)
+                    goto case_ident;
                 if (p[1] == '"')
                 {
                     p++;
@@ -438,7 +425,7 @@  class Lexer
             //case 'u':
             case 'v':
             case 'w':
-                /*case 'x':*/
+            case 'x':
             case 'y':
             case 'z':
             case 'A':
@@ -676,6 +663,7 @@  class Lexer
                     endOfLine();
                     continue;
                 case '+':
+                    if (!Ccompile)
                     {
                         int nest;
                         startLoc = loc();
@@ -745,6 +733,7 @@  class Lexer
                         }
                         continue;
                     }
+                    break;
                 default:
                     break;
                 }
@@ -1051,35 +1040,8 @@  class Lexer
             case '#':
                 {
                     p++;
-                    Token n;
-                    scan(&n);
-                    if (Ccompile && n.value == TOK.int32Literal)
-                    {
-                        poundLine(n, true);
+                    if (parseSpecialTokenSequence())
                         continue;
-                    }
-                    if (n.value == TOK.identifier)
-                    {
-                        if (n.ident == Id.line)
-                        {
-                            poundLine(n, false);
-                            continue;
-                        }
-                        else if (n.ident == Id.__pragma && Ccompile)
-                        {
-                            pragmaDirective(scanloc);
-                            continue;
-                        }
-                        else
-                        {
-                            const locx = loc();
-                            warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
-                        }
-                    }
-                    else if (n.value == TOK.if_)
-                    {
-                        error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
-                    }
                     t.value = TOK.pound;
                     return;
                 }
@@ -1388,84 +1350,6 @@  class Lexer
         }
     }
 
-    /**************************************
-     * Lex hex strings:
-     *      x"0A ae 34FE BD"
-     */
-    private TOK hexStringConstant(Token* t)
-    {
-        Loc start = loc();
-        uint n = 0;
-        uint v = ~0; // dead assignment, needed to suppress warning
-        p++;
-        stringbuffer.setsize(0);
-        while (1)
-        {
-            dchar c = *p++;
-            switch (c)
-            {
-            case ' ':
-            case '\t':
-            case '\v':
-            case '\f':
-                continue; // skip white space
-            case '\r':
-                if (*p == '\n')
-                    continue; // ignore '\r' if followed by '\n'
-                // Treat isolated '\r' as if it were a '\n'
-                goto case '\n';
-            case '\n':
-                endOfLine();
-                continue;
-            case 0:
-            case 0x1A:
-                error("unterminated string constant starting at %s", start.toChars());
-                t.setString();
-                // decrement `p`, because it needs to point to the next token (the 0 or 0x1A character is the TOK.endOfFile token).
-                p--;
-                return TOK.hexadecimalString;
-            case '"':
-                if (n & 1)
-                {
-                    error("odd number (%d) of hex characters in hex string", n);
-                    stringbuffer.writeByte(v);
-                }
-                t.setString(stringbuffer);
-                stringPostfix(t);
-                return TOK.hexadecimalString;
-            default:
-                if (c >= '0' && c <= '9')
-                    c -= '0';
-                else if (c >= 'a' && c <= 'f')
-                    c -= 'a' - 10;
-                else if (c >= 'A' && c <= 'F')
-                    c -= 'A' - 10;
-                else if (c & 0x80)
-                {
-                    p--;
-                    const u = decodeUTF();
-                    p++;
-                    if (u == PS || u == LS)
-                        endOfLine();
-                    else
-                        error("non-hex character \\u%04x in hex string", u);
-                }
-                else
-                    error("non-hex character '%c' in hex string", c);
-                if (n & 1)
-                {
-                    v = (v << 4) | c;
-                    stringbuffer.writeByte(v);
-                }
-                else
-                    v = c;
-                n++;
-                break;
-            }
-        }
-        assert(0); // see bug 15731
-    }
-
     /**
     Lex a delimited string. Some examples of delimited strings are:
     ---
@@ -2666,6 +2550,37 @@  class Lexer
         va_end(args);
     }
 
+    /***************************************
+     * Parse special token sequence:
+     * Returns:
+     *  true if the special token sequence was handled
+     * References:
+     *  https://dlang.org/spec/lex.html#special-token-sequence
+     */
+    bool parseSpecialTokenSequence()
+    {
+        Token n;
+        scan(&n);
+        if (n.value == TOK.identifier)
+        {
+            if (n.ident == Id.line)
+            {
+                poundLine(n, false);
+                return true;
+            }
+            else
+            {
+                const locx = loc();
+                warning(locx, "C preprocessor directive `#%s` is not supported", n.ident.toChars());
+            }
+        }
+        else if (n.value == TOK.if_)
+        {
+            error("C preprocessor directive `#if` is not supported, use `version` or `static if`");
+        }
+        return false;
+    }
+
     /*********************************************
      * Parse line/file preprocessor directive:
      *    #line linnum [filespec]
@@ -2680,7 +2595,7 @@  class Lexer
      * References:
      *  linemarker https://gcc.gnu.org/onlinedocs/gcc-11.1.0/cpp/Preprocessor-Output.html
      */
-    private void poundLine(ref Token tok, bool linemarker)
+    final void poundLine(ref Token tok, bool linemarker)
     {
         auto linnum = this.scanloc.linnum;
         const(char)* filespec = null;
@@ -2806,183 +2721,10 @@  class Lexer
             error(loc, "#line integer [\"filespec\"]\\n expected");
     }
 
-    /*********************************************
-     * C11 6.10.6 Pragma directive
-     * # pragma pp-tokens(opt) new-line
-     * The C preprocessor sometimes leaves pragma directives in
-     * the preprocessed output. Ignore them.
-     * Upon return, p is at start of next line.
-     */
-    private void pragmaDirective(const ref Loc loc)
-    {
-        Token n;
-        scan(&n);
-        if (n.value == TOK.identifier && n.ident == Id.pack)
-            return pragmaPack(loc);
-        skipToNextLine();
-    }
-
-    /*********
-     * ImportC
-     * # pragma pack
-     * https://gcc.gnu.org/onlinedocs/gcc-4.4.4/gcc/Structure_002dPacking-Pragmas.html
-     * https://docs.microsoft.com/en-us/cpp/preprocessor/pack
-     * Scanner is on the `pack`
-     * Params:
-     *  startloc = location to use for error messages
-     */
-    private void pragmaPack(const ref Loc startloc)
-    {
-        const loc = startloc;
-        Token n;
-        scan(&n);
-        if (n.value != TOK.leftParenthesis)
-        {
-            error(loc, "left parenthesis expected to follow `#pragma pack`");
-            skipToNextLine();
-            return;
-        }
-
-        void closingParen()
-        {
-            if (n.value != TOK.rightParenthesis)
-            {
-                error(loc, "right parenthesis expected to close `#pragma pack(`");
-            }
-            skipToNextLine();
-        }
-
-        void setPackAlign(ref const Token t)
-        {
-            const n = t.unsvalue;
-            if (n < 1 || n & (n - 1) || ushort.max < n)
-                error(loc, "pack must be an integer positive power of 2, not 0x%llx", cast(ulong)n);
-            packalign.set(cast(uint)n);
-            packalign.setPack(true);
-        }
-
-        scan(&n);
-
-        if (!records)
-        {
-            records = new Array!Identifier;
-            packs = new Array!structalign_t;
-        }
-
-        /* # pragma pack ( show )
-         */
-        if (n.value == TOK.identifier && n.ident == Id.show)
-        {
-            if (packalign.isDefault())
-                warning(startloc, "current pack attribute is default");
-            else
-                warning(startloc, "current pack attribute is %d", packalign.get());
-            scan(&n);
-            return closingParen();
-        }
-        /* # pragma pack ( push )
-         * # pragma pack ( push , identifier )
-         * # pragma pack ( push , integer )
-         * # pragma pack ( push , identifier , integer )
-         */
-        if (n.value == TOK.identifier && n.ident == Id.push)
-        {
-            scan(&n);
-            Identifier record = null;
-            if (n.value == TOK.comma)
-            {
-                scan(&n);
-                if (n.value == TOK.identifier)
-                {
-                    record = n.ident;
-                    scan(&n);
-                    if (n.value == TOK.comma)
-                    {
-                        scan(&n);
-                        if (n.value == TOK.int32Literal)
-                        {
-                            setPackAlign(n);
-                            scan(&n);
-                        }
-                        else
-                            error(loc, "alignment value expected, not `%s`", n.toChars());
-                    }
-                }
-                else if (n.value == TOK.int32Literal)
-                {
-                    setPackAlign(n);
-                    scan(&n);
-                }
-                else
-                    error(loc, "alignment value expected, not `%s`", n.toChars());
-            }
-            this.records.push(record);
-            this.packs.push(packalign);
-            return closingParen();
-        }
-        /* # pragma pack ( pop )
-         * # pragma pack ( pop PopList )
-         * PopList :
-         *    , IdentifierOrInteger
-         *    , IdentifierOrInteger PopList
-         * IdentifierOrInteger:
-         *      identifier
-         *      integer
-         */
-        if (n.value == TOK.identifier && n.ident == Id.pop)
-        {
-            scan(&n);
-            while (n.value == TOK.comma)
-            {
-                scan(&n);
-                if (n.value == TOK.identifier)
-                {
-                    for (size_t len = this.records.length; len; --len)
-                    {
-                        if ((*this.records)[len - 1] == n.ident)
-                        {
-                            packalign = (*this.packs)[len - 1];
-                            this.records.setDim(len - 1);
-                            this.packs.setDim(len - 1);
-                            break;
-                        }
-                    }
-                    scan(&n);
-                }
-                else if (n.value == TOK.int32Literal)
-                {
-                    setPackAlign(n);
-                    this.records.push(null);
-                    this.packs.push(packalign);
-                    scan(&n);
-                }
-            }
-            return closingParen();
-        }
-        /* # pragma pack ( integer )
-         */
-        if (n.value == TOK.int32Literal)
-        {
-            setPackAlign(n);
-            scan(&n);
-            return closingParen();
-        }
-        /* # pragma pack ( )
-         */
-        if (n.value == TOK.rightParenthesis)
-        {
-            packalign.setDefault();
-            return closingParen();
-        }
-
-        error(loc, "unrecognized `#pragma pack(%s)`", n.toChars());
-        skipToNextLine();
-    }
-
     /***************************************
      * Scan forward to start of next line.
      */
-    private void skipToNextLine()
+    final void skipToNextLine()
     {
         while (1)
         {
@@ -3557,5 +3299,3 @@  unittest
         assert(tok == TOK.endOfFile);
     }
 }
-
-
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 9297ad9dd03..18af7721df1 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -4214,6 +4214,7 @@  extern (C++) final class TypeFunction : TypeNext
         inoutParam      = 0x0400, // inout on the parameters
         inoutQual       = 0x0800, // inout on the qualifier
         isctor          = 0x1000, // the function is a constructor
+        isreturnscope   = 0x2000, // `this` is returned by value
     }
 
     LINK linkage;               // calling convention
@@ -4247,6 +4248,8 @@  extern (C++) final class TypeFunction : TypeNext
             this.isref = true;
         if (stc & STC.return_)
             this.isreturn = true;
+        if (stc & STC.returnScope)
+            this.isreturnscope = true;
         if (stc & STC.returninferred)
             this.isreturninferred = true;
         if (stc & STC.scope_)
@@ -4285,6 +4288,7 @@  extern (C++) final class TypeFunction : TypeNext
         t.isproperty = isproperty;
         t.isref = isref;
         t.isreturn = isreturn;
+        t.isreturnscope = isreturnscope;
         t.isScopeQual = isScopeQual;
         t.isreturninferred = isreturninferred;
         t.isscopeinferred = isscopeinferred;
@@ -4507,6 +4511,7 @@  extern (C++) final class TypeFunction : TypeNext
             tf.isproperty = t.isproperty;
             tf.isref = t.isref;
             tf.isreturn = t.isreturn;
+            tf.isreturnscope = t.isreturnscope;
             tf.isScopeQual = t.isScopeQual;
             tf.isreturninferred = t.isreturninferred;
             tf.isscopeinferred = t.isscopeinferred;
@@ -4573,6 +4578,7 @@  extern (C++) final class TypeFunction : TypeNext
         t.isproperty = isproperty;
         t.isref = isref;
         t.isreturn = isreturn;
+        t.isreturnscope = isreturnscope;
         t.isScopeQual = isScopeQual;
         t.isreturninferred = isreturninferred;
         t.isscopeinferred = isscopeinferred;
@@ -5136,6 +5142,18 @@  extern (C++) final class TypeFunction : TypeNext
         else funcFlags &= ~FunctionFlag.isreturn;
     }
 
+    /// set or get if the function has the `returnscope` attribute
+    bool isreturnscope() const pure nothrow @safe @nogc
+    {
+        return (funcFlags & FunctionFlag.isreturnscope) != 0;
+    }
+    /// ditto
+    void isreturnscope(bool v) pure nothrow @safe @nogc
+    {
+        if (v) funcFlags |= FunctionFlag.isreturnscope;
+        else funcFlags &= ~FunctionFlag.isreturnscope;
+    }
+
     /// set or get if the function has the `scope` attribute
     bool isScopeQual() const pure nothrow @safe @nogc
     {
@@ -6384,7 +6402,7 @@  extern (C++) final class TypeClass : Type
         /* Conversion derived to const(base)
          */
         int offset = 0;
-        if (to.isBaseOf(this, &offset) && MODimplicitConv(mod, to.mod))
+        if (to.isBaseOf(this, &offset) && offset == 0 && MODimplicitConv(mod, to.mod))
         {
             // Disallow:
             //  derived to base
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index cb6023696ee..3f085b06091 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -625,6 +625,8 @@  public:
     void isref(bool v);
     bool isreturn() const;
     void isreturn(bool v);
+    bool isreturnscope() const;
+    void isreturnscope(bool v);
     bool isScopeQual() const;
     void isScopeQual(bool v);
     bool isreturninferred() const;
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index 01708d65655..fc643776edd 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -396,13 +396,10 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     fd = search_function(ad, id);
                     if (fd)
                     {
-                        // @@@DEPRECATED_2.098@@@.
-                        // Deprecated in 2.088
-                        // Make an error in 2.098
-                        e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
-                        // Rewrite +e1 as e1.add()
-                        result = build_overload(e.loc, sc, e.e1, null, fd);
-                        return result;
+                        // @@@DEPRECATED_2.110@@@.
+                        // Deprecated in 2.088, made an error in 2.100
+                        e.error("`%s` is obsolete.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+                        return ErrorExp.get();
                     }
                 }
                 // Didn't find it. Forward to aliasthis
@@ -670,13 +667,13 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                     s = search_function(ad1, id);
                     if (s && id != Id.assign)
                     {
-                        // @@@DEPRECATED_2.098@@@.
-                        // Deprecated in 2.088
-                        // Make an error in 2.098
+                        // @@@DEPRECATED_2.110@@@.
+                        // Deprecated in 2.088, made an error in 2.100
                         if (id == Id.postinc || id == Id.postdec)
-                            e.deprecation("`%s` is deprecated.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+                            e.error("`%s` is obsolete.  Use `opUnary(string op)() if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
                         else
-                            e.deprecation("`%s` is deprecated.  Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+                            e.error("`%s` is obsolete.  Use `opBinary(string op)(...) if (op == \"%s\")` instead.", id.toChars(), EXPtoString(e.op).ptr);
+                        return ErrorExp.get();
                     }
                 }
                 if (ad2 && id_r)
@@ -689,10 +686,10 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                         s_r = null;
                     if (s_r)
                     {
-                        // @@@DEPRECATED_2.098@@@.
-                        // Deprecated in 2.088
-                        // Make an error in 2.098
-                        e.deprecation("`%s` is deprecated.  Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
+                        // @@@DEPRECATED_2.110@@@.
+                        // Deprecated in 2.088, made an error in 2.100
+                        e.error("`%s` is obsolete.  Use `opBinaryRight(string op)(...) if (op == \"%s\")` instead.", id_r.toChars(), EXPtoString(e.op).ptr);
+                        return ErrorExp.get();
                     }
                 }
             }
@@ -1232,12 +1229,12 @@  Expression op_overload(Expression e, Scope* sc, EXP* pop = null)
                 s = search_function(ad1, id);
                 if (s)
                 {
-                    // @@@DEPRECATED_2.098@@@.
-                    // Deprecated in 2.088
-                    // Make an error in 2.098
+                    // @@@DEPRECATED_2.110@@@.
+                    // Deprecated in 2.088, made an error in 2.100
                     scope char[] op = EXPtoString(e.op).dup;
                     op[$-1] = '\0'; // remove trailing `=`
-                    e.deprecation("`%s` is deprecated.  Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
+                    e.error("`%s` is obsolete.  Use `opOpAssign(string op)(...) if (op == \"%s\")` instead.", id.toChars(), op.ptr);
+                    return ErrorExp.get();
                 }
             }
 
@@ -1552,7 +1549,8 @@  bool inferForeachAggregate(Scope* sc, bool isForeach, ref Expression feaggr, out
  * Params:
  *      fes = the foreach statement
  *      sc = context
- *      sapply = null or opApply or delegate
+ *      sapply = null or opApply or delegate, overload resolution has not been done.
+ *               Do overload resolution on sapply.
  * Returns:
  *      false for errors
  */
@@ -1588,8 +1586,7 @@  bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
          */
         if (FuncDeclaration fd = sapply.isFuncDeclaration())
         {
-            auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters);
-            if (fdapply)
+            if (auto fdapply = findBestOpApplyMatch(ethis, fd, fes.parameters))
             {
                 // Fill in any missing types on foreach parameters[]
                 matchParamsToOpApply(fdapply.type.isTypeFunction(), fes.parameters, true);
@@ -1598,7 +1595,7 @@  bool inferApplyArgTypes(ForeachStatement fes, Scope* sc, ref Dsymbol sapply)
             }
             return false;
         }
-        return sapply !is null;
+        return true;   // shouldn't this be false?
     }
 
     Parameter p = (*fes.parameters)[0];
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 10c265f600b..cc02bd9ea7c 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -338,9 +338,9 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
     void visitTuple(TupleExp e)
     {
         expOptimize(e.e0, WANTvalue);
-        for (size_t i = 0; i < e.exps.dim; i++)
+        foreach (ref ex; (*e.exps)[])
         {
-            expOptimize((*e.exps)[i], WANTvalue);
+            expOptimize(ex, WANTvalue);
         }
     }
 
@@ -349,9 +349,9 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         if (e.elements)
         {
             expOptimize(e.basis, result & WANTexpand);
-            for (size_t i = 0; i < e.elements.dim; i++)
+            foreach (ref ex; (*e.elements)[])
             {
-                expOptimize((*e.elements)[i], result & WANTexpand);
+                expOptimize(ex, result & WANTexpand);
             }
         }
     }
@@ -359,9 +359,9 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
     void visitAssocArrayLiteral(AssocArrayLiteralExp e)
     {
         assert(e.keys.dim == e.values.dim);
-        for (size_t i = 0; i < e.keys.dim; i++)
+        foreach (i, ref ekey; (*e.keys)[])
         {
-            expOptimize((*e.keys)[i], result & WANTexpand);
+            expOptimize(ekey, result & WANTexpand);
             expOptimize((*e.values)[i], result & WANTexpand);
         }
     }
@@ -374,9 +374,9 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         e.stageflags |= stageOptimize;
         if (e.elements)
         {
-            for (size_t i = 0; i < e.elements.dim; i++)
+            foreach (ref ex; (*e.elements)[])
             {
-                expOptimize((*e.elements)[i], result & WANTexpand);
+                expOptimize(ex, result & WANTexpand);
             }
         }
         e.stageflags = old;
@@ -647,9 +647,9 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         // Optimize parameters
         if (e.arguments)
         {
-            for (size_t i = 0; i < e.arguments.dim; i++)
+            foreach (ref arg; (*e.arguments)[])
             {
-                expOptimize((*e.arguments)[i], WANTvalue);
+                expOptimize(arg, WANTvalue);
             }
         }
     }
@@ -663,16 +663,16 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         if (e.arguments)
         {
             Type t1 = e.e1.type.toBasetype();
-            if (t1.ty == Tdelegate)
-                t1 = t1.nextOf();
+            if (auto td = t1.isTypeDelegate())
+                t1 = td.next;
             // t1 can apparently be void for __ArrayDtor(T) calls
             if (auto tf = t1.isTypeFunction())
             {
-                for (size_t i = 0; i < e.arguments.dim; i++)
+                foreach (i, ref arg; (*e.arguments)[])
                 {
                     Parameter p = tf.parameterList[i];
                     bool keep = p && p.isReference();
-                    expOptimize((*e.arguments)[i], WANTvalue, keep);
+                    expOptimize(arg, WANTvalue, keep);
                 }
             }
         }
@@ -719,14 +719,17 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
             }
         }
 
-        if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
+        // Returning e.e1 with changing its type
+        void returnE_e1()
         {
-            //printf(" returning2 %s\n", e.e1.toChars());
-        L1:
-            // Returning e1 with changing its type
             ret = (e1old == e.e1 ? e.e1.copy() : e.e1);
             ret.type = e.type;
-            return;
+        }
+
+        if (e.e1.op == EXP.structLiteral && e.e1.type.implicitConvTo(e.type) >= MATCH.constant)
+        {
+            //printf(" returning2 %s\n", e.e1.toChars());
+            return returnE_e1();
         }
         /* The first test here is to prevent infinite loops
          */
@@ -738,7 +741,7 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         if (e.e1.op == EXP.null_ && (e.type.ty == Tpointer || e.type.ty == Tclass || e.type.ty == Tarray))
         {
             //printf(" returning3 %s\n", e.e1.toChars());
-            goto L1;
+            return returnE_e1();
         }
         if (e.type.ty == Tclass && e.e1.type.ty == Tclass)
         {
@@ -750,7 +753,7 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
             if (cdfrom.errors || cdto.errors)
                 return error();
             if (cdto == ClassDeclaration.object && !cdfrom.isInterfaceDeclaration())
-                goto L1;    // can always convert a class to Object
+                return returnE_e1();    // can always convert a class to Object
             // Need to determine correct offset before optimizing away the cast.
             // https://issues.dlang.org/show_bug.cgi?id=16980
             cdfrom.size(e.loc);
@@ -760,13 +763,13 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
             if (cdto.isBaseOf(cdfrom, &offset) && offset == 0)
             {
                 //printf(" returning4 %s\n", e.e1.toChars());
-                goto L1;
+                return returnE_e1();
             }
         }
         if (e.e1.type.mutableOf().unSharedOf().equals(e.to.mutableOf().unSharedOf()))
         {
             //printf(" returning5 %s\n", e.e1.toChars());
-            goto L1;
+            return returnE_e1();
         }
         if (e.e1.isConst())
         {
@@ -781,7 +784,7 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
                         return error();
 
                     if (esz == e1sz)
-                        goto L1;
+                        return returnE_e1();
                 }
                 return;
             }
@@ -1065,7 +1068,7 @@  Expression Expression_optimize(Expression e, int result, bool keepLvalue)
         // Don't optimize to an array literal element directly in case an lvalue is requested
         if (keepLvalue && ex.op == EXP.arrayLiteral)
             return;
-        ret = Index(e.type, ex, e.e2).copy();
+        ret = Index(e.type, ex, e.e2, e.indexIsInBounds).copy();
         if (CTFEExp.isCantExp(ret) || (!ret.isErrorExp() && keepLvalue && !ret.isLvalue()))
             ret = e;
     }
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index e83b326c7e3..480a96c25db 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -1971,7 +1971,6 @@  class Parser(AST) : Lexer
         case TOK.wcharLiteral:
         case TOK.dcharLiteral:
         case TOK.string_:
-        case TOK.hexadecimalString:
         case TOK.file:
         case TOK.fileFullPath:
         case TOK.line:
@@ -5623,7 +5622,6 @@  LagainStc:
         case TOK.true_:
         case TOK.false_:
         case TOK.string_:
-        case TOK.hexadecimalString:
         case TOK.leftParenthesis:
         case TOK.cast_:
         case TOK.mul:
@@ -7106,7 +7104,6 @@  LagainStc:
                     case TOK.wcharLiteral:
                     case TOK.dcharLiteral:
                     case TOK.string_:
-                    case TOK.hexadecimalString:
                     case TOK.file:
                     case TOK.fileFullPath:
                     case TOK.line:
@@ -7987,7 +7984,6 @@  LagainStc:
             break;
 
         case TOK.string_:
-        case TOK.hexadecimalString:
             {
                 // cat adjacent strings
                 auto s = token.ustring;
@@ -7997,7 +7993,7 @@  LagainStc:
                 {
                     const prev = token;
                     nextToken();
-                    if (token.value == TOK.string_ || token.value == TOK.hexadecimalString)
+                    if (token.value == TOK.string_)
                     {
                         if (token.postfix)
                         {
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 88520e85c24..f229918d899 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -866,7 +866,6 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
                             assert(t.ty == Tdelegate);
                             tfld = cast(TypeFunction)t.nextOf();
                         }
-                        //printf("tfld = %s\n", tfld.toChars());
                     }
                 }
             }
@@ -1442,12 +1441,12 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
         /* Call:
          *      _aApply(aggr, flde)
          */
-        __gshared const(char)** fntab =
+        static immutable fntab =
         [
          "cc", "cw", "cd",
          "wc", "cc", "wd",
          "dc", "dw", "dd"
-         ];
+        ];
 
         const(size_t) BUFFER_LEN = 7 + 1 + 2 + dim.sizeof * 3 + 1;
         char[BUFFER_LEN] fdname;
@@ -1470,7 +1469,7 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
                 assert(0);
         }
         const(char)* r = (fs.op == TOK.foreach_reverse_) ? "R" : "";
-        int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag], cast(ulong)dim);
+        int j = sprintf(fdname.ptr, "_aApply%s%.*s%llu", r, 2, fntab[flag].ptr, cast(ulong)dim);
         assert(j < BUFFER_LEN);
 
         FuncDeclaration fdapply;
@@ -2475,68 +2474,66 @@  package (dmd) extern (C++) final class StatementSemanticVisitor : Visitor
             Expression initialExp = cs.exp;
 
             // The switch'ed value has errors and doesn't provide the actual type
-            // Don't touch the case to not replace it with an `ErrorExp` even if it is valid
+            // Omit the cast to enable further semantic (exluding the check for matching types)
             if (sw.condition.type && !sw.condition.type.isTypeError())
-            {
                 cs.exp = cs.exp.implicitCastTo(sc, sw.condition.type);
-                cs.exp = cs.exp.optimize(WANTvalue | WANTexpand);
+            cs.exp = cs.exp.optimize(WANTvalue | WANTexpand);
+
+            Expression e = cs.exp;
+            // Remove all the casts the user and/or implicitCastTo may introduce
+            // otherwise we'd sometimes fail the check below.
+            while (e.op == EXP.cast_)
+                e = (cast(CastExp)e).e1;
+
+            /* This is where variables are allowed as case expressions.
+            */
+            if (e.op == EXP.variable)
+            {
+                VarExp ve = cast(VarExp)e;
+                VarDeclaration v = ve.var.isVarDeclaration();
+                Type t = cs.exp.type.toBasetype();
+                if (v && (t.isintegral() || t.ty == Tclass))
+                {
+                    /* Flag that we need to do special code generation
+                    * for this, i.e. generate a sequence of if-then-else
+                    */
+                    sw.hasVars = 1;
+
+                    /* TODO check if v can be uninitialized at that point.
+                    */
+                    if (!v.isConst() && !v.isImmutable())
+                    {
+                        cs.error("`case` variables have to be `const` or `immutable`");
+                    }
 
-                Expression e = cs.exp;
-                // Remove all the casts the user and/or implicitCastTo may introduce
-                // otherwise we'd sometimes fail the check below.
-                while (e.op == EXP.cast_)
-                    e = (cast(CastExp)e).e1;
+                    if (sw.isFinal)
+                    {
+                        cs.error("`case` variables not allowed in `final switch` statements");
+                        errors = true;
+                    }
 
-                /* This is where variables are allowed as case expressions.
-                */
-                if (e.op == EXP.variable)
-                {
-                    VarExp ve = cast(VarExp)e;
-                    VarDeclaration v = ve.var.isVarDeclaration();
-                    Type t = cs.exp.type.toBasetype();
-                    if (v && (t.isintegral() || t.ty == Tclass))
+                    /* Find the outermost scope `scx` that set `sw`.
+                    * Then search scope `scx` for a declaration of `v`.
+                    */
+                    for (Scope* scx = sc; scx; scx = scx.enclosing)
                     {
-                        /* Flag that we need to do special code generation
-                        * for this, i.e. generate a sequence of if-then-else
-                        */
-                        sw.hasVars = 1;
-
-                        /* TODO check if v can be uninitialized at that point.
-                        */
-                        if (!v.isConst() && !v.isImmutable())
-                        {
-                            cs.error("`case` variables have to be `const` or `immutable`");
-                        }
+                        if (scx.enclosing && scx.enclosing.sw == sw)
+                            continue;
+                        assert(scx.sw == sw);
 
-                        if (sw.isFinal)
+                        if (!scx.search(cs.exp.loc, v.ident, null))
                         {
-                            cs.error("`case` variables not allowed in `final switch` statements");
+                            cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body",
+                                v.toChars(), v.loc.toChars());
                             errors = true;
                         }
-
-                        /* Find the outermost scope `scx` that set `sw`.
-                        * Then search scope `scx` for a declaration of `v`.
-                        */
-                        for (Scope* scx = sc; scx; scx = scx.enclosing)
-                        {
-                            if (scx.enclosing && scx.enclosing.sw == sw)
-                                continue;
-                            assert(scx.sw == sw);
-
-                            if (!scx.search(cs.exp.loc, v.ident, null))
-                            {
-                                cs.error("`case` variable `%s` declared at %s cannot be declared in `switch` body",
-                                    v.toChars(), v.loc.toChars());
-                                errors = true;
-                            }
-                            break;
-                        }
-                        goto L1;
+                        break;
                     }
+                    goto L1;
                 }
-                else
-                    cs.exp = cs.exp.ctfeInterpret();
             }
+            else
+                cs.exp = cs.exp.ctfeInterpret();
 
             if (StringExp se = cs.exp.toStringExp())
                 cs.exp = se;
diff --git a/gcc/d/dmd/tokens.d b/gcc/d/dmd/tokens.d
index 0b1d1583a55..6e56eb25474 100644
--- a/gcc/d/dmd/tokens.d
+++ b/gcc/d/dmd/tokens.d
@@ -124,7 +124,6 @@  enum TOK : ubyte
     // Leaf operators
     identifier,
     string_,
-    hexadecimalString,
     this_,
     super_,
     error,
@@ -854,8 +853,6 @@  extern (C++) struct Token
         TOK.wchar_tLiteral: "wchar_tv",
         TOK.whitespace: "whitespace",
 
-        TOK.hexadecimalString: "xstring",
-
         // C only keywords
         TOK.inline    : "inline",
         TOK.register  : "register",
@@ -1008,24 +1005,6 @@  nothrow:
                 p = buf.extractSlice().ptr;
             }
             break;
-        case TOK.hexadecimalString:
-            {
-                OutBuffer buf;
-                buf.writeByte('x');
-                buf.writeByte('"');
-                foreach (size_t i; 0 .. len)
-                {
-                    if (i)
-                        buf.writeByte(' ');
-                    buf.printf("%02x", ustring[i]);
-                }
-                buf.writeByte('"');
-                if (postfix)
-                    buf.writeByte(postfix);
-                buf.writeByte(0);
-                p = buf.extractSlice().ptr;
-                break;
-            }
         case TOK.identifier:
         case TOK.enum_:
         case TOK.struct_:
diff --git a/gcc/d/dmd/tokens.h b/gcc/d/dmd/tokens.h
index 6dfd0ce3333..c404cab2ad5 100644
--- a/gcc/d/dmd/tokens.h
+++ b/gcc/d/dmd/tokens.h
@@ -133,7 +133,6 @@  enum class TOK : unsigned char
     // Leaf operators
     identifier,
     string_,
-    hexadecimalString,
     this_,
     super_,
     error,
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 1f038363dfe..57188af90d6 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -666,9 +666,13 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
 
     Type visitType(Type t)
     {
+        // @@@DEPRECATED_2.110@@@
+        // Use of `cent` and `ucent` has always been an error.
+        // Starting from 2.100, recommend core.int128 as a replace for the
+        // lack of compiler support.
         if (t.ty == Tint128 || t.ty == Tuns128)
         {
-            .error(loc, "`cent` and `ucent` types not implemented");
+            .error(loc, "`cent` and `ucent` types are obsolete, use `core.int128.Cent` instead");
             return error();
         }
 
@@ -1188,6 +1192,8 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             tf.isref = true;
         if (sc.stc & STC.return_)
             tf.isreturn = true;
+        if (sc.stc & STC.returnScope)
+            tf.isreturnscope = true;
         if (sc.stc & STC.returninferred)
             tf.isreturninferred = true;
         if (sc.stc & STC.scope_)
@@ -3828,10 +3834,10 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, int flag)
                  *  e.opDot().ident
                  */
                 e = build_overload(e.loc, sc, e, null, fd);
-                // @@@DEPRECATED_2.092@@@.
-                e.deprecation("`opDot` is deprecated. Use `alias this`");
-                e = new DotIdExp(e.loc, e, ident);
-                return returnExp(e.expressionSemantic(sc));
+                // @@@DEPRECATED_2.110@@@.
+                // Deprecated in 2.082, made an error in 2.100.
+                e.error("`opDot` is obsolete. Use `alias this`");
+                return ErrorExp.get();
             }
 
             /* Look for overloaded opDispatch to see if we should forward request
diff --git a/gcc/d/imports.cc b/gcc/d/imports.cc
index 29c0fbfe6d2..6747ee5df27 100644
--- a/gcc/d/imports.cc
+++ b/gcc/d/imports.cc
@@ -106,20 +106,20 @@  public:
     tree type = build_ctype (d->type);
     /* Not all kinds of D enums create a TYPE_DECL.  */
     if (TREE_CODE (type) == ENUMERAL_TYPE)
-      d->isym = this->make_import (TYPE_STUB_DECL (type));
+      this->result_ = this->make_import (TYPE_STUB_DECL (type));
   }
 
   void visit (AggregateDeclaration *d)
   {
     tree type = build_ctype (d->type);
-    d->isym = this->make_import (TYPE_STUB_DECL (type));
+    this->result_ = this->make_import (TYPE_STUB_DECL (type));
   }
 
   void visit (ClassDeclaration *d)
   {
     /* Want the RECORD_TYPE, not POINTER_TYPE.  */
     tree type = TREE_TYPE (build_ctype (d->type));
-    d->isym = this->make_import (TYPE_STUB_DECL (type));
+    this->result_ = this->make_import (TYPE_STUB_DECL (type));
   }
 
   /* For now, ignore importing other kinds of dsymbols.  */
diff --git a/gcc/testsuite/gdc.test/compilable/commontype.d b/gcc/testsuite/gdc.test/compilable/commontype.d
index a740994d7b5..076e29baece 100644
--- a/gcc/testsuite/gdc.test/compilable/commontype.d
+++ b/gcc/testsuite/gdc.test/compilable/commontype.d
@@ -196,8 +196,7 @@  static assert(is( X!( C***, B*** ) == const(B**)* )); // `B***`
 
 static assert(is( X!( C*, I* ) == I* ));
 static assert(is( X!( I*, C* ) == I* ));
-//static assert(Error!( C**, I** ));
-static assert(is( X!( C**, I** ) == const(I*)* ));
+static assert(Error!( C**, I** ));
 
 static assert(Error!( C*, D* )); // should work
 
@@ -304,15 +303,13 @@  static assert(is( X!(C[4], B[4]) ));
 static assert(Error!( C[4], I[4] ));
 static assert(Error!( C[4], D[4] ));
 static assert(is( X!( C[4], const(B)[4] ) == const(B)[4] ));
-//static assert(Error!( C[4], const(I)[4] ));
-static assert(is( X!( C[4], const(I)[4] ) == const(I)[] ));
+static assert(Error!( C[4], const(I)[4] ));
 static assert(Error!( C[4], const(D)[4] ));
 static assert(Error!( C*[4], B*[4] ));
 static assert(Error!( C*[4], I*[4] ));
 static assert(Error!( C*[4], D*[4] ));
 static assert(is( X!( C*[4], const(B*)[4] ) == const(B*)[] )); // !?
-//static assert(Error!( C*[4], const(I*)[4] ));
-static assert(is( X!( C*[4], const(I*)[4] ) == const(I*)[] ));
+static assert(Error!( C*[4], const(I*)[4] ));
 static assert(Error!( C*[4], const(D*)[4] ));
 static assert(Error!( C*[4], B**[4] ));
 static assert(Error!( C*[4], const(B*)*[4] ));
diff --git a/gcc/testsuite/gdc.test/compilable/test7172.d b/gcc/testsuite/gdc.test/compilable/test7172.d
index a4cf663066e..013630bd483 100644
--- a/gcc/testsuite/gdc.test/compilable/test7172.d
+++ b/gcc/testsuite/gdc.test/compilable/test7172.d
@@ -1,3 +1,8 @@ 
+/* TEST_OUTPUT:
+---
+compilable/test7172.d(14): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+---
+*/
 void main()
 {
     abstract class AbstractC{}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d
index 230fc4bae3e..19c64752aaf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dep_d1_ops.d
@@ -2,47 +2,47 @@ 
 REQUIRED_ARGS: -de
 TEST_OUTPUT:
 ---
-fail_compilation/dep_d1_ops.d(105): Deprecation: `opAdd` is deprecated.  Use `opBinary(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(106): Deprecation: `opAdd_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(107): Deprecation: `opSub` is deprecated.  Use `opBinary(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(108): Deprecation: `opSub_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(109): Deprecation: `opMul` is deprecated.  Use `opBinary(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(110): Deprecation: `opMul_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(111): Deprecation: `opDiv` is deprecated.  Use `opBinary(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(112): Deprecation: `opDiv_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(113): Deprecation: `opMod` is deprecated.  Use `opBinary(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(114): Deprecation: `opMod_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(116): Deprecation: `opAnd` is deprecated.  Use `opBinary(string op)(...) if (op == "&")` instead.
-fail_compilation/dep_d1_ops.d(117): Deprecation: `opOr` is deprecated.  Use `opBinary(string op)(...) if (op == "|")` instead.
-fail_compilation/dep_d1_ops.d(118): Deprecation: `opXor` is deprecated.  Use `opBinary(string op)(...) if (op == "^")` instead.
-fail_compilation/dep_d1_ops.d(120): Deprecation: `opShl` is deprecated.  Use `opBinary(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(121): Deprecation: `opShl_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(122): Deprecation: `opShr` is deprecated.  Use `opBinary(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(123): Deprecation: `opShr_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(124): Deprecation: `opUShr` is deprecated.  Use `opBinary(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(125): Deprecation: `opUShr_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(127): Deprecation: `opCat` is deprecated.  Use `opBinary(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(128): Deprecation: `opCat_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(130): Deprecation: `opNeg` is deprecated.  Use `opUnary(string op)() if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(131): Deprecation: `opCom` is deprecated.  Use `opUnary(string op)() if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(132): Deprecation: `opPostInc` is deprecated.  Use `opUnary(string op)() if (op == "++")` instead.
-fail_compilation/dep_d1_ops.d(133): Deprecation: `opPostDec` is deprecated.  Use `opUnary(string op)() if (op == "--")` instead.
-fail_compilation/dep_d1_ops.d(134): Deprecation: `opStar` is deprecated.  Use `opUnary(string op)() if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(136): Deprecation: `opIn` is deprecated.  Use `opBinary(string op)(...) if (op == "in")` instead.
-fail_compilation/dep_d1_ops.d(137): Deprecation: `opIn_r` is deprecated.  Use `opBinaryRight(string op)(...) if (op == "in")` instead.
-fail_compilation/dep_d1_ops.d(139): Deprecation: `opAddAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "+")` instead.
-fail_compilation/dep_d1_ops.d(140): Deprecation: `opSubAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "-")` instead.
-fail_compilation/dep_d1_ops.d(141): Deprecation: `opMulAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "*")` instead.
-fail_compilation/dep_d1_ops.d(142): Deprecation: `opDivAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "/")` instead.
-fail_compilation/dep_d1_ops.d(143): Deprecation: `opModAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "%")` instead.
-fail_compilation/dep_d1_ops.d(144): Deprecation: `opAndAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "&")` instead.
-fail_compilation/dep_d1_ops.d(145): Deprecation: `opOrAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "|")` instead.
-fail_compilation/dep_d1_ops.d(146): Deprecation: `opXorAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "^")` instead.
-fail_compilation/dep_d1_ops.d(147): Deprecation: `opShlAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "<<")` instead.
-fail_compilation/dep_d1_ops.d(148): Deprecation: `opShrAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == ">>")` instead.
-fail_compilation/dep_d1_ops.d(149): Deprecation: `opUShrAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == ">>>")` instead.
-fail_compilation/dep_d1_ops.d(150): Deprecation: `opCatAssign` is deprecated.  Use `opOpAssign(string op)(...) if (op == "~")` instead.
-fail_compilation/dep_d1_ops.d(158): Deprecation: `opCom` is deprecated.  Use `opUnary(string op)() if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(105): Error: `opAdd` is obsolete.  Use `opBinary(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(106): Error: `opAdd_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(107): Error: `opSub` is obsolete.  Use `opBinary(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(108): Error: `opSub_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(109): Error: `opMul` is obsolete.  Use `opBinary(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(110): Error: `opMul_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(111): Error: `opDiv` is obsolete.  Use `opBinary(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(112): Error: `opDiv_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(113): Error: `opMod` is obsolete.  Use `opBinary(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(114): Error: `opMod_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(116): Error: `opAnd` is obsolete.  Use `opBinary(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(117): Error: `opOr` is obsolete.  Use `opBinary(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(118): Error: `opXor` is obsolete.  Use `opBinary(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(120): Error: `opShl` is obsolete.  Use `opBinary(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(121): Error: `opShl_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(122): Error: `opShr` is obsolete.  Use `opBinary(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(123): Error: `opShr_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(124): Error: `opUShr` is obsolete.  Use `opBinary(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(125): Error: `opUShr_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(127): Error: `opCat` is obsolete.  Use `opBinary(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(128): Error: `opCat_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(130): Error: `opNeg` is obsolete.  Use `opUnary(string op)() if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(131): Error: `opCom` is obsolete.  Use `opUnary(string op)() if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(132): Error: `opPostInc` is obsolete.  Use `opUnary(string op)() if (op == "++")` instead.
+fail_compilation/dep_d1_ops.d(133): Error: `opPostDec` is obsolete.  Use `opUnary(string op)() if (op == "--")` instead.
+fail_compilation/dep_d1_ops.d(134): Error: `opStar` is obsolete.  Use `opUnary(string op)() if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(136): Error: `opIn` is obsolete.  Use `opBinary(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(137): Error: `opIn_r` is obsolete.  Use `opBinaryRight(string op)(...) if (op == "in")` instead.
+fail_compilation/dep_d1_ops.d(139): Error: `opAddAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "+")` instead.
+fail_compilation/dep_d1_ops.d(140): Error: `opSubAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "-")` instead.
+fail_compilation/dep_d1_ops.d(141): Error: `opMulAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "*")` instead.
+fail_compilation/dep_d1_ops.d(142): Error: `opDivAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "/")` instead.
+fail_compilation/dep_d1_ops.d(143): Error: `opModAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "%")` instead.
+fail_compilation/dep_d1_ops.d(144): Error: `opAndAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "&")` instead.
+fail_compilation/dep_d1_ops.d(145): Error: `opOrAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "|")` instead.
+fail_compilation/dep_d1_ops.d(146): Error: `opXorAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "^")` instead.
+fail_compilation/dep_d1_ops.d(147): Error: `opShlAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "<<")` instead.
+fail_compilation/dep_d1_ops.d(148): Error: `opShrAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == ">>")` instead.
+fail_compilation/dep_d1_ops.d(149): Error: `opUShrAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == ">>>")` instead.
+fail_compilation/dep_d1_ops.d(150): Error: `opCatAssign` is obsolete.  Use `opOpAssign(string op)(...) if (op == "~")` instead.
+fail_compilation/dep_d1_ops.d(158): Error: `opCom` is obsolete.  Use `opUnary(string op)() if (op == "~")` instead.
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
index a97afdcdf75..2ce37959e11 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/dephexstrings.d
@@ -2,7 +2,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/dephexstrings.d(8): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"60"` instead.
+fail_compilation/dephexstrings.d(9): Error: semicolon expected following auto declaration, not `"60"`
+fail_compilation/dephexstrings.d(9): Error: declaration expected, not `"60"`
 ---
 */
 enum xstr = x"60";
diff --git a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d
index 5aaab6a2b17..46c949376e3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/deprecateopdot.d
@@ -2,9 +2,9 @@ 
 REQUIRED_ARGS: -de
 TEST_OUTPUT:
 ---
-fail_compilation/deprecateopdot.d(27): Deprecation: `opDot` is deprecated. Use `alias this`
-fail_compilation/deprecateopdot.d(28): Deprecation: `opDot` is deprecated. Use `alias this`
-fail_compilation/deprecateopdot.d(29): Deprecation: `opDot` is deprecated. Use `alias this`
+fail_compilation/deprecateopdot.d(27): Error: `opDot` is obsolete. Use `alias this`
+fail_compilation/deprecateopdot.d(28): Error: `opDot` is obsolete. Use `alias this`
+fail_compilation/deprecateopdot.d(29): Error: `opDot` is obsolete. Use `alias this`
 ---
 */
 struct S6
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail136.d b/gcc/testsuite/gdc.test/fail_compilation/fail136.d
index 299b994d919..16659b5fdc1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail136.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail136.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail136.d(10): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"EF BB BF"` instead.
+fail_compilation/fail136.d(10): Error: found `"EF BB BF"` when expecting `;` following statement
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail18.d b/gcc/testsuite/gdc.test/fail_compilation/fail18.d
index 55a4af1f45d..848b65116f1 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail18.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail18.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail18.d(14): Error: need upper and lower bound to slice pointer
+fail_compilation/fail18.d(14): Error: upper and lower bounds are needed to slice a pointer
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d
index dd83f75e9c2..e22be9fe047 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail22780.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22780.d
@@ -1,7 +1,8 @@ 
 // https://issues.dlang.org/show_bug.cgi?id=22780
 /* TEST_OUTPUT:
 ---
-fail_compilation/fail22780.d(11): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope`
+fail_compilation/fail22780.d(8): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+fail_compilation/fail22780.d(12): Error: variable `fail22780.test10717.c` reference to `scope class` must be `scope`
 ---
 */
 scope class C10717 { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail22827.d b/gcc/testsuite/gdc.test/fail_compilation/fail22827.d
new file mode 100644
index 00000000000..ee031ae1906
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail22827.d
@@ -0,0 +1,9 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=22827
+/* TEST_OUTPUT:
+---
+fail_compilation/fail22827.d(8): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead
+fail_compilation/fail22827.d(9): Error: `cent` and `ucent` types are obsolete, use `core.int128.Cent` instead
+---
+*/
+cent i22827;
+ucent j22827;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue22820.d b/gcc/testsuite/gdc.test/fail_compilation/issue22820.d
new file mode 100644
index 00000000000..af42b46d524
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue22820.d
@@ -0,0 +1,68 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/issue22820.d(138): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(138):        pointer `s1` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s1)[]`
+fail_compilation/issue22820.d(139): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(139):        pointer `s2` points to an aggregate that defines an `opSlice`, perhaps you meant `(*s2)[]`
+fail_compilation/issue22820.d(140): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(140):        pointer `s3` points to an aggregate that defines an `opIndex`, perhaps you meant `(*s3)[]`
+fail_compilation/issue22820.d(141): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(141):        pointer `cp` points to an aggregate that defines an `opIndex`, perhaps you meant `(*cp)[]`
+fail_compilation/issue22820.d(142): Error: upper and lower bounds are needed to slice a pointer
+fail_compilation/issue22820.d(142):        pointer `e` points to an aggregate that defines an `opIndex`, perhaps you meant `(*e)[]`
+---
+*/
+
+#line 100
+
+// normal functions
+struct S1 {
+	int[] opIndex() { return a; }
+	int[] a;
+}
+
+// opSlice alternative
+struct S2 {
+	int[] opSlice() { return a; }
+	int[] a;
+}
+
+// templates
+struct S3 {
+	int[] opIndex()() { return a; }
+	int[] a;
+}
+
+class C {
+	int[] opIndex()() { return a; }
+	int[] a;
+}
+
+enum E : S1
+{
+	a = S1([1])
+}
+
+void main() {
+	S1* s1 = new S1;
+	S2* s2 = new S2;
+	S3* s3 = new S3;
+	C c = new C;
+	C* cp = &c;
+	E* e = new E;
+	int* p;
+
+	p = s1[].ptr;
+	p = s2[].ptr;
+	p = s3[].ptr;
+	p = cp[].ptr;
+	p = e[].ptr;
+
+	p = (*s1)[].ptr;
+	p = (*s2)[].ptr;
+	p = (*s3)[].ptr;
+	p = (*cp)[].ptr;
+	p = (*e)[].ptr;
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
index 6569d4c2239..115f1366dce 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer1.d
@@ -1,8 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/lexer1.d(30): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"01 02 03"w` instead.
-fail_compilation/lexer1.d(30): Error: declaration expected, not `x"01 02 03"w`
+fail_compilation/lexer1.d(30): Error: no identifier for declarator `x`
+fail_compilation/lexer1.d(30): Error: declaration expected, not `"01 02 03"w`
 fail_compilation/lexer1.d(31): Error: declaration expected, not `2147483649U`
 fail_compilation/lexer1.d(32): Error: declaration expected, not `0.1`
 fail_compilation/lexer1.d(33): Error: declaration expected, not `0.1f`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
index 2386da597a8..f895e644c44 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/lexer2.d
@@ -1,10 +1,10 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/lexer2.d(16): Error: odd number (3) of hex characters in hex string
-fail_compilation/lexer2.d(16): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123"` instead.
-fail_compilation/lexer2.d(17): Error: non-hex character 'G' in hex string
-fail_compilation/lexer2.d(17): Error: Built-in hex string literals are obsolete, use `std.conv.hexString!"123G"` instead.
+fail_compilation/lexer2.d(16): Error: semicolon expected following auto declaration, not `"123"`
+fail_compilation/lexer2.d(16): Error: declaration expected, not `"123"`
+fail_compilation/lexer2.d(17): Error: semicolon expected following auto declaration, not `"123G"`
+fail_compilation/lexer2.d(17): Error: declaration expected, not `"123G"`
 fail_compilation/lexer2.d(18): Error: heredoc rest of line should be blank
 fail_compilation/lexer2.d(20): Error: unterminated delimited string constant starting at fail_compilation/lexer2.d(20)
 fail_compilation/lexer2.d(22): Error: semicolon expected following auto declaration, not `End of File`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
new file mode 100644
index 00000000000..b15d6e49b18
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/opapplyscope.d
@@ -0,0 +1,27 @@ 
+/* TEST_OUTPUT:
+---
+fail_compilation/opapplyscope.d(113): Error: function `opapplyscope.S.opApply(scope int delegate(scope int* ptr) @safe dg)` is not callable using argument types `(int delegate(int* x) nothrow @nogc @safe)`
+fail_compilation/opapplyscope.d(113):        cannot pass argument `__foreachbody3` of type `int delegate(int* x) nothrow @nogc @safe` to parameter `scope int delegate(scope int* ptr) @safe dg`
+---
+ */
+
+#line 100
+
+struct S
+{
+    int opApply(scope int delegate (scope int* ptr) @safe dg) @safe
+    {
+        return 0;
+    }
+}
+
+void test() @safe
+{
+    static int* global;
+    S s;
+    foreach (/*scope*/ int* x; s)
+    {
+        global = x;
+    }
+}
+
diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d
index b70e3eb8c5a..bba14908833 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/scope_class.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/scope_class.d
@@ -1,7 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/scope_class.d(11): Error: functions cannot return `scope scope_class.C`
+fail_compilation/scope_class.d(10): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+fail_compilation/scope_class.d(12): Error: functions cannot return `scope scope_class.C`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d
index 1e152f54d14..e0550138b7e 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/scope_type.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/scope_type.d
@@ -2,11 +2,15 @@ 
 REQUIRED_ARGS: -de
 TEST_OUTPUT:
 ---
-fail_compilation/scope_type.d(11): Error: `scope` as a type constraint is obsolete.  Use `scope` at the usage site.
+fail_compilation/scope_type.d(13): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+fail_compilation/scope_type.d(14): Error: `scope` as a type constraint is obsolete.  Use `scope` at the usage site.
+fail_compilation/scope_type.d(15): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+fail_compilation/scope_type.d(16): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
 ---
 */
 
 
 scope class C { }
 scope interface I { }
-//scope struct S { }
+scope struct S { }
+scope enum E { e }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test15191.d b/gcc/testsuite/gdc.test/fail_compilation/test15191.d
index fea9fb7958c..2ac3b562198 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test15191.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test15191.d
@@ -1,15 +1,19 @@ 
 /* TEST_OUTPUT:
-PERMUTE_ARGS: -dip1000
+REQUIRED_ARGS: -preview=dip1000
 ---
-fail_compilation/test15191.d(31): Error: returning `&identity(x)` escapes a reference to local variable `x`
-fail_compilation/test15191.d(37): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
-fail_compilation/test15191.d(43): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
-fail_compilation/test15191.d(43): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(35): Error: returning `&identity(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(41): Error: returning `&identityPtr(x)` escapes a reference to local variable `x`
+fail_compilation/test15191.d(47): Error: cannot take address of `ref return` of `identityPtr()` in `@safe` function `addrOfRefTransitive`
+fail_compilation/test15191.d(47):        return type `int*` has pointers that may be `scope`
+fail_compilation/test15191.d(68): Error: cannot slice static array of `ref return` of `identityArr()` in `@safe` function `sliceOfRefEscape`
+fail_compilation/test15191.d(68):        return type `int*[1]` has pointers that may be `scope`
 ---
 */
 
+// Test taking the address of a `ref return` using & and [] operators
 // https://issues.dlang.org/show_bug.cgi?id=15191
 // https://issues.dlang.org/show_bug.cgi?id=22519
+// https://issues.dlang.org/show_bug.cgi?id=22539
 
 @safe:
 ref int foo(return ref int s)
@@ -50,3 +54,17 @@  int* addrOfRefGlobal()
 {
 	return &getGlobalInt();
 }
+
+// Slice:
+ref int*[1] identityArr(ref return scope int*[1] x)
+{
+	return x;
+}
+
+int* sliceOfRefEscape()
+{
+	int stackVar = 0xFF;
+	scope int*[1] x = [&stackVar];
+	int*[] y = identityArr(x)[];
+	return y[0];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test19097.d b/gcc/testsuite/gdc.test/fail_compilation/test19097.d
index b5560f0b27b..034813b5316 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test19097.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test19097.d
@@ -1,7 +1,9 @@ 
 /* REQUIRED_ARGS: -preview=dip1000
  * TEST_OUTPUT:
 ---
-fail_compilation/test19097.d(35): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(37): Error: scope variable `s` may not be returned
+fail_compilation/test19097.d(66): Error: scope variable `z` assigned to `refPtr` with longer lifetime
+fail_compilation/test19097.d(97): Error: scope variable `s` may not be returned
 ---
  */
 
@@ -54,3 +56,43 @@  struct S2(T)
 
 S2!int s2;
 
+/************************/
+struct S3
+{
+    int* ptr;
+    void assign(ref int* refPtr, return scope int* z) scope @safe
+    {
+        this.ptr = z; // allowed, first ref
+        refPtr = z; // should not be allowed
+    }
+}
+
+int* escape() @safe
+{
+    int local;
+
+    S3 escapeThis;
+    int* escapeRef;
+
+    escapeThis.assign(escapeRef, &local);
+
+    return escapeRef;
+}
+
+/************************/
+// https://issues.dlang.org/show_bug.cgi?id=22837
+struct S4
+{
+    int* p;
+    this(int dummy, return scope int* p) @safe
+    {
+        this.p = p;
+    }
+}
+
+int* escape2()
+{
+    int x;
+    auto s = S4(0, &x);
+    return s.p;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test21008.d b/gcc/testsuite/gdc.test/fail_compilation/test21008.d
new file mode 100644
index 00000000000..d5cf96a6c3a
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test21008.d
@@ -0,0 +1,41 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test21008.d(110): Error: function `test21008.C.after` circular reference to class `C`
+fail_compilation/test21008.d(117): Error: need `this` for `toString` of type `string()`
+fail_compilation/test21008.d(117): Error: need `this` for `toHash` of type `nothrow @trusted $?:32=uint|64=ulong$()`
+fail_compilation/test21008.d(117): Error: function `object.Object.opCmp(Object o)` is not callable using argument types `()`
+fail_compilation/test21008.d(117):        missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117): Error: function `object.Object.opEquals(Object o)` is not callable using argument types `()`
+fail_compilation/test21008.d(117):        missing argument for parameter #1: `Object o`
+fail_compilation/test21008.d(117): Error: `Monitor` has no effect
+fail_compilation/test21008.d(117): Error: function `object.Object.factory(string classname)` is not callable using argument types `()`
+fail_compilation/test21008.d(117):        missing argument for parameter #1: `string classname`
+fail_compilation/test21008.d(105):        called from here: `handleMiddlewareAnnotation()`
+fail_compilation/test21008.d(108): Error: class `test21008.C` no size because of forward reference
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=21008
+
+#line 100
+
+class Base
+{
+    bool after();
+
+    mixin(handleMiddlewareAnnotation);
+}
+
+class C : Base
+{
+    override bool after();
+}
+
+string handleMiddlewareAnnotation()
+{
+    foreach (member; __traits(allMembers, C))
+    {
+        __traits(getMember, C, member);
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d
index a0d1d122e63..bfd8803d2f2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test_switch_error.d
@@ -99,3 +99,81 @@  void test5(int i)
 
     }
 }
+
+/++
+TEST_OUTPUT:
+---
+fail_compilation/test_switch_error.d(513): Error: undefined identifier `undefinedFunc`
+fail_compilation/test_switch_error.d(517): Error: `case` must be a `string` or an integral constant, not `Strukt(1)`
+fail_compilation/test_switch_error.d(518): Error: `case` variables have to be `const` or `immutable`
+fail_compilation/test_switch_error.d(518): Error: `case` variables not allowed in `final switch` statements
+fail_compilation/test_switch_error.d(519): Error: `case` variables not allowed in `final switch` statements
+fail_compilation/test_switch_error.d(522): Error: undefined identifier `undefinedFunc2`
+---
+++/
+#line 500
+
+enum Foo
+{
+   one, two
+}
+
+struct Strukt
+{
+    int i;
+}
+
+void errorsWithErrors(int param, immutable int constant)
+{
+   final switch(undefinedFunc())
+   {
+      case Foo.one:     break;
+      case Foo.two:     break;
+      case Strukt(1):   break;
+      case param:       break;
+      case constant:    break;
+   }
+
+   switch (undefinedFunc2())
+   {
+       case constant:   break;
+   }
+}
+
+/++
+TEST_OUTPUT:
+---
+fail_compilation/test_switch_error.d(622): Error: undefined identifier `undefinedFunc`
+fail_compilation/test_switch_error.d(624): Error: `case` must be a `string` or an integral constant, not `SubtypeOfInt(2)`
+fail_compilation/test_switch_error.d(625): Error: `case` must be a `string` or an integral constant, not `SubtypeOfIntMethod()`
+---
+++/
+#line 600
+
+struct SubtypeOfInt
+{
+    int i;
+    alias i this;
+}
+
+struct SubtypeOfIntMethod
+{
+    int getI() { return 0; }
+    alias getI this;
+}
+
+void errorsWithErrors2(int param)
+{
+    final switch(param)
+    {
+        case SubtypeOfInt(1):         break;
+        case SubtypeOfIntMethod():    break;
+    }
+
+    // This snippet causes somewhat misleading error messages
+    final switch(undefinedFunc())
+    {
+        case SubtypeOfInt(2):         break;
+        case SubtypeOfIntMethod():    break;
+    }
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
index a93a49fdc18..37395d4b897 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/typeerrors.d
@@ -1,22 +1,23 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/typeerrors.d(36): Error: tuple index 4 exceeds 4
-fail_compilation/typeerrors.d(38): Error: variable `x` cannot be read at compile time
-fail_compilation/typeerrors.d(39): Error: cannot have array of `void()`
-fail_compilation/typeerrors.d(40): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(32): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+fail_compilation/typeerrors.d(37): Error: tuple index 4 exceeds 4
+fail_compilation/typeerrors.d(39): Error: variable `x` cannot be read at compile time
+fail_compilation/typeerrors.d(40): Error: cannot have array of `void()`
 fail_compilation/typeerrors.d(41): Error: cannot have array of scope `typeerrors.C`
-fail_compilation/typeerrors.d(44): Error: `int[5]` is not an expression
-fail_compilation/typeerrors.d(46): Error: variable `x` is used as a type
-fail_compilation/typeerrors.d(37):        variable `x` is declared here
-fail_compilation/typeerrors.d(47): Error: cannot have associative array key of `void()`
-fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void`
-fail_compilation/typeerrors.d(49): Error: cannot have array of scope `typeerrors.C`
-fail_compilation/typeerrors.d(50): Error: cannot have associative array of `void`
-fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void()`
-fail_compilation/typeerrors.d(53): Error: cannot have parameter of type `void`
-fail_compilation/typeerrors.d(55): Error: slice `[1..5]` is out of range of [0..4]
-fail_compilation/typeerrors.d(56): Error: slice `[2..1]` is out of range of [0..4]
+fail_compilation/typeerrors.d(42): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(45): Error: `int[5]` is not an expression
+fail_compilation/typeerrors.d(47): Error: variable `x` is used as a type
+fail_compilation/typeerrors.d(38):        variable `x` is declared here
+fail_compilation/typeerrors.d(48): Error: cannot have associative array key of `void()`
+fail_compilation/typeerrors.d(49): Error: cannot have associative array key of `void`
+fail_compilation/typeerrors.d(50): Error: cannot have array of scope `typeerrors.C`
+fail_compilation/typeerrors.d(51): Error: cannot have associative array of `void`
+fail_compilation/typeerrors.d(52): Error: cannot have associative array of `void()`
+fail_compilation/typeerrors.d(54): Error: cannot have parameter of type `void`
+fail_compilation/typeerrors.d(56): Error: slice `[1..5]` is out of range of [0..4]
+fail_compilation/typeerrors.d(57): Error: slice `[2..1]` is out of range of [0..4]
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/runnable/auto1.d b/gcc/testsuite/gdc.test/runnable/auto1.d
index ea023836bf2..6ee075089d1 100644
--- a/gcc/testsuite/gdc.test/runnable/auto1.d
+++ b/gcc/testsuite/gdc.test/runnable/auto1.d
@@ -16,7 +16,7 @@  import core.stdc.stdio;
 
 /******************************************/
 
-scope class Foo
+class Foo
 {
     static int x;
 
@@ -65,7 +65,7 @@  void test1()
 
 int ax;
 
-scope class A2
+class A2
 {
   this()
   {
@@ -96,11 +96,11 @@  void test2()
 
 int status3;
 
-scope class Parent3
+class Parent3
 {
 }
 
-scope class Child3 : Parent3
+class Child3 : Parent3
 {
         this(){
                 assert(status3==0);
diff --git a/gcc/testsuite/gdc.test/runnable/interpret.d b/gcc/testsuite/gdc.test/runnable/interpret.d
index 4d02a924a21..6b1e89b65ff 100644
--- a/gcc/testsuite/gdc.test/runnable/interpret.d
+++ b/gcc/testsuite/gdc.test/runnable/interpret.d
@@ -3246,7 +3246,7 @@  int test6907()
     }
     {
         S1* p = new S1();
-        if (__ctfe) 
+        if (__ctfe)
         {
             (*p).__dtor();
             destroy(p);
diff --git a/gcc/testsuite/gdc.test/runnable/opover.d b/gcc/testsuite/gdc.test/runnable/opover.d
index 633981e4cbb..253a7a54ceb 100644
--- a/gcc/testsuite/gdc.test/runnable/opover.d
+++ b/gcc/testsuite/gdc.test/runnable/opover.d
@@ -31,7 +31,8 @@  import core.stdc.stdio;
 
 class A1
 {
-    int opAdd(int i) { return 7 + i; }
+    int opBinary(string op)(int i) if (op == "+") { return 7 + i; }
+    alias opBinaryRight = opBinary;
 }
 
 void test1()
@@ -50,8 +51,8 @@  void test1()
 
 class A2
 {
-    int opDiv(int i)   { return 9 + i; }
-    int opDiv_r(int i) { return 17 + i; }
+    int opBinary(string op)(int i)      if (op == "/") { return 9 + i; }
+    int opBinaryRight(string op)(int i) if (op == "/") { return 17 + i; }
 }
 
 void test2()
@@ -74,31 +75,31 @@  class C1
 
 class C2
 {
-    int opAdd(D1 d)   { return 1; }
-    int opAdd(D2 d)   { return 2; }
-    int opAdd(D3 d)   { return 3; }
-    int opAdd(D4 d)   { return 4; }
+    int opBinary(string op)(D1 d) if (op == "+") { return 1; }
+    int opBinary(string op)(D2 d) if (op == "+") { return 2; }
+    int opBinary(string op)(D3 d) if (op == "+") { return 3; }
+    int opBinary(string op)(D4 d) if (op == "+") { return 4; }
 }
 
 class C3
 {
-    int opAdd_r(D1 d) { return 5; }
-    int opAdd_r(D2 d) { return 6; }
-    int opAdd_r(D3 d) { return 7; }
-    int opAdd_r(D4 d) { return 8; }
+    int opBinaryRight(string op)(D1 d) if (op == "+") { return 5; }
+    int opBinaryRight(string op)(D2 d) if (op == "+") { return 6; }
+    int opBinaryRight(string op)(D3 d) if (op == "+") { return 7; }
+    int opBinaryRight(string op)(D4 d) if (op == "+") { return 8; }
 }
 
 class C4
 {
-    int opAdd(D1 d)   { return 9; }
-    int opAdd(D2 d)   { return 10; }
-    int opAdd(D3 d)   { return 11; }
-    int opAdd(D4 d)   { return 12; }
+    int opBinary(string op)(D1 d) if (op == "+") { return 9; }
+    int opBinary(string op)(D2 d) if (op == "+") { return 10; }
+    int opBinary(string op)(D3 d) if (op == "+") { return 11; }
+    int opBinary(string op)(D4 d) if (op == "+") { return 12; }
 
-    int opAdd_r(D1 d) { return 13; }
-    int opAdd_r(D2 d) { return 14; }
-    int opAdd_r(D3 d) { return 15; }
-    int opAdd_r(D4 d) { return 16; }
+    int opBinaryRight(string op)(D1 d) if (op == "+") { return 13; }
+    int opBinaryRight(string op)(D2 d) if (op == "+") { return 14; }
+    int opBinaryRight(string op)(D3 d) if (op == "+") { return 15; }
+    int opBinaryRight(string op)(D4 d) if (op == "+") { return 16; }
 }
 
 class D1
@@ -107,31 +108,31 @@  class D1
 
 class D2
 {
-    int opAdd(C1 c)   { return 17; }
-    int opAdd(C2 d)   { return 18; }
-    int opAdd(C3 d)   { return 19; }
-    int opAdd(C4 d)   { return 20; }
+    int opBinary(string op)(C1 d) if (op == "+") { return 17; }
+    int opBinary(string op)(C2 d) if (op == "+") { return 18; }
+    int opBinary(string op)(C3 d) if (op == "+") { return 19; }
+    int opBinary(string op)(C4 d) if (op == "+") { return 20; }
 }
 
 class D3
 {
-    int opAdd_r(C1 d) { return 21; }
-    int opAdd_r(C2 d) { return 22; }
-    int opAdd_r(C3 d) { return 23; }
-    int opAdd_r(C4 d) { return 24; }
+    int opBinaryRight(string op)(C1 d) if (op == "+") { return 21; }
+    int opBinaryRight(string op)(C2 d) if (op == "+") { return 22; }
+    int opBinaryRight(string op)(C3 d) if (op == "+") { return 23; }
+    int opBinaryRight(string op)(C4 d) if (op == "+") { return 24; }
 }
 
 class D4
 {
-    int opAdd(C1 d)   { return 25; }
-    int opAdd(C2 d)   { return 26; }
-    int opAdd(C3 d)   { return 27; }
-    int opAdd(C4 d)   { return 28; }
+    int opBinary(string op)(C1 d) if (op == "+") { return 25; }
+    int opBinary(string op)(C2 d) if (op == "+") { return 26; }
+    int opBinary(string op)(C3 d) if (op == "+") { return 27; }
+    int opBinary(string op)(C4 d) if (op == "+") { return 28; }
 
-    int opAdd_r(C1 d) { return 29; }
-    int opAdd_r(C2 d) { return 30; }
-    int opAdd_r(C3 d) { return 31; }
-    int opAdd_r(C4 d) { return 32; }
+    int opBinaryRight(string op)(C1 d) if (op == "+") { return 29; }
+    int opBinaryRight(string op)(C2 d) if (op == "+") { return 30; }
+    int opBinaryRight(string op)(C3 d) if (op == "+") { return 31; }
+    int opBinaryRight(string op)(C4 d) if (op == "+") { return 32; }
 }
 
 
@@ -149,90 +150,45 @@  void test3()
 
     int i;
 
-  version (ADD_R)
-  {
     //i = c1 + d1;    assert(i == );
-    i = c1 + d2;    assert(i == 17);
+    //i = c1 + d2;    assert(i == );
     i = c1 + d3;    assert(i == 21);
     i = c1 + d4;    assert(i == 29);
 
     i = c2 + d1;    assert(i == 1);
     i = c2 + d2;    assert(i == 2);
-    i = c2 + d3;    assert(i == 3);
-    i = c2 + d4;    assert(i == 4);
+    i = c2 + d3;    assert(i == 22);
+    i = c2 + d4;    assert(i == 30);
 
     //i = c3 + d1;    assert(i == );
-    i = c3 + d2;    assert(i == 19);
+    //i = c3 + d2;    assert(i == );
     i = c3 + d3;    assert(i == 23);
     i = c3 + d4;    assert(i == 31);
 
     i = c4 + d1;    assert(i == 9);
     i = c4 + d2;    assert(i == 10);
-    i = c4 + d3;    assert(i == 11);
-    i = c4 + d4;    assert(i == 12);
+    i = c4 + d3;    assert(i == 24);
+    i = c4 + d4;    assert(i == 32);
 
     //i = d1 + c1;    assert(i == );
-    i = d1 + c2;    assert(i == 1);
+    //i = d1 + c2;    assert(i == );
     i = d1 + c3;    assert(i == 5);
     i = d1 + c4;    assert(i == 13);
 
     i = d2 + c1;    assert(i == 17);
     i = d2 + c2;    assert(i == 18);
-    i = d2 + c3;    assert(i == 19);
-    i = d2 + c4;    assert(i == 20);
+    i = d2 + c3;    assert(i == 6);
+    i = d2 + c4;    assert(i == 14);
 
     //i = d3 + c1;    assert(i == );
-    i = d3 + c2;    assert(i == 3);
+    //i = d3 + c2;    assert(i == );
     i = d3 + c3;    assert(i == 7);
     i = d3 + c4;    assert(i == 15);
 
     i = d4 + c1;    assert(i == 25);
     i = d4 + c2;    assert(i == 26);
-    i = d4 + c3;    assert(i == 27);
-    i = d4 + c4;    assert(i == 28);
-  }
-  else
-  {
-    //i = c1 + d1;    assert(i == );
-    i = c1 + d2;    assert(i == 17);
-//    i = c1 + d3;    assert(i == 21);
-    i = c1 + d4;    assert(i == 29);
-
-    i = c2 + d1;    assert(i == 1);
-    i = c2 + d2;    assert(i == 2);
-//    i = c2 + d3;    assert(i == 3);
-//    i = c2 + d4;    assert(i == 4);
-
-    //i = c3 + d1;    assert(i == );
-//    i = c3 + d2;    printf("i = %d\n", i); assert(i == 19);
-//    i = c3 + d3;    assert(i == 23);
-    i = c3 + d4;    assert(i == 31);
-
-    i = c4 + d1;    assert(i == 9);
-    i = c4 + d2;    assert(i == 10);
-//    i = c4 + d3;    assert(i == 11);
-//    i = c4 + d4;    assert(i == 12);
-
-    //i = d1 + c1;    assert(i == );
-    i = d1 + c2;    assert(i == 1);
-//    i = d1 + c3;    assert(i == 5);
-    i = d1 + c4;    assert(i == 13);
-
-    i = d2 + c1;    assert(i == 17);
-    i = d2 + c2;    assert(i == 18);
-//    i = d2 + c3;    assert(i == 19);
-//    i = d2 + c4;    assert(i == 20);
-
-    //i = d3 + c1;    assert(i == );
-//    i = d3 + c2;    assert(i == 3);
-//    i = d3 + c3;    assert(i == 7);
-    i = d3 + c4;    assert(i == 15);
-
-    i = d4 + c1;    assert(i == 25);
-    i = d4 + c2;    assert(i == 26);
-//    i = d4 + c3;    assert(i == 27);
-//    i = d4 + c4;    assert(i == 28);
-  }
+    i = d4 + c3;    assert(i == 8);
+    i = d4 + c4;    assert(i == 16);
 }
 
 /**************************************/
@@ -258,44 +214,45 @@  void test4()
 
 class A5
 {
-    int opNeg()     { return 10; }
-    int opCom()     { return 11; }
-    int opPostInc() { return 12; }
-    int opPostDec() { return 13; }
-
-    int opAdd(int j)     { return 14; }
-    int opSub(int j)     { return 15; }
-    int opSub_r(int j)   { return 16; }
-    int opMul(int j)     { return 17; }
-    int opDiv(int j)     { return 18; }
-    int opDiv_r(int j)   { return 19; }
-    int opMod(int j)     { return 20; }
-    int opMod_r(int j)   { return 21; }
-    int opAnd(int j)     { return 22; }
-    int opOr(int j)      { return 23; }
-    int opXor(int j)     { return 24; }
-    int opShl(int j)     { return 25; }
-    int opShl_r(int j)   { return 26; }
-    int opShr(int j)     { return 27; }
-    int opShr_r(int j)   { return 28; }
-    int opUShr(int j)    { return 29; }
-    int opUShr_r(int j)  { return 30; }
-    int opCat(int j)     { return 31; }
-    int opCat_r(int j)   { return 32; }
+    int opUnary(string op)() if (op == "-")  { return 10; }
+    int opUnary(string op)() if (op == "~")  { return 11; }
+    int opUnary(string op)() if (op == "++") { return 12; }
+    int opUnary(string op)() if (op == "--") { return 13; }
+
+
+    int opBinary(string op)(int j)      if (op == "+")   { return 14; }
+    int opBinary(string op)(int j)      if (op == "-")   { return 15; }
+    int opBinaryRight(string op)(int j) if (op == "-")   { return 16; }
+    int opBinary(string op)(int j)      if (op == "*")   { return 17; }
+    int opBinary(string op)(int j)      if (op == "/")   { return 18; }
+    int opBinaryRight(string op)(int j) if (op == "/")   { return 19; }
+    int opBinary(string op)(int j)      if (op == "%")   { return 20; }
+    int opBinaryRight(string op)(int j) if (op == "%")   { return 21; }
+    int opBinary(string op)(int j)      if (op == "&")   { return 22; }
+    int opBinary(string op)(int j)      if (op == "|")   { return 23; }
+    int opBinary(string op)(int j)      if (op == "^")   { return 24; }
+    int opBinary(string op)(int j)      if (op == "<<")  { return 25; }
+    int opBinaryRight(string op)(int j) if (op == "<<")  { return 26; }
+    int opBinary(string op)(int j)      if (op == ">>")  { return 27; }
+    int opBinaryRight(string op)(int j) if (op == ">>")  { return 28; }
+    int opBinary(string op)(int j)      if (op == ">>>") { return 29; }
+    int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; }
+    int opBinary(string op)(int j)      if (op == "~")   { return 31; }
+    int opBinaryRight(string op)(int j) if (op == "~")   { return 32; }
     int opEquals(int j)  { return 33; }
     int opCmp(int j)     { return 34; }
-    int opAddAssign(int j)  { return 35; }
-    int opSubAssign(int j)  { return 36; }
-    int opMulAssign(int j)  { return 37; }
-    int opDivAssign(int j)  { return 38; }
-    int opModAssign(int j)  { return 39; }
-    int opAndAssign(int j)  { return 40; }
-    int opOrAssign(int j)   { return 41; }
-    int opXorAssign(int j)  { return 42; }
-    int opShlAssign(int j)  { return 43; }
-    int opShrAssign(int j)  { return 44; }
-    int opUShrAssign(int j) { return 45; }
-    int opCatAssign(int j)  { return 46; }
+    int opOpAssign(string op)(int j) if (op == "+")   { return 35; }
+    int opOpAssign(string op)(int j) if (op == "-")   { return 36; }
+    int opOpAssign(string op)(int j) if (op == "*")   { return 37; }
+    int opOpAssign(string op)(int j) if (op == "/")   { return 38; }
+    int opOpAssign(string op)(int j) if (op == "%")   { return 39; }
+    int opOpAssign(string op)(int j) if (op == "&")   { return 40; }
+    int opOpAssign(string op)(int j) if (op == "|")   { return 41; }
+    int opOpAssign(string op)(int j) if (op == "^")   { return 42; }
+    int opOpAssign(string op)(int j) if (op == "<<")  { return 43; }
+    int opOpAssign(string op)(int j) if (op == ">>")  { return 44; }
+    int opOpAssign(string op)(int j) if (op == ">>>") { return 45; }
+    int opOpAssign(string op)(int j) if (op == "~")   { return 46; }
 }
 
 void test5()
@@ -309,10 +266,10 @@  void test5()
     i = ~a;
     assert(i == 11);
 
-    i = a++;
+    i = ++a;
     assert(i == 12);
 
-    i = a--;
+    i = --a;
     assert(i == 13);
 
     i = a + 1;
@@ -402,13 +359,9 @@  printf("i = %d\n", i);
 
     i = (a += 1);
     assert(i == 35);
-    i = ++a;
-    assert(i == 35);
 
     i = (a -= 1);
     assert(i == 36);
-    i = --a;
-    assert(i == 36);
 
     i = (a *= 1);
     assert(i == 37);
@@ -445,45 +398,45 @@  printf("i = %d\n", i);
 
 struct A6
 {
-    int opNeg()     { return 10; }
-    int opCom()     { return 11; }
-    int opPostInc() { return 12; }
-    int opPostDec() { return 13; }
-
-    int opAdd(int j)     { return 14; }
-    int opSub(int j)     { return 15; }
-    int opSub_r(int j)   { return 16; }
-    int opMul(int j)     { return 17; }
-    int opDiv(int j)     { return 18; }
-    int opDiv_r(int j)   { return 19; }
-    int opMod(int j)     { return 20; }
-    int opMod_r(int j)   { return 21; }
-    int opAnd(int j)     { return 22; }
-    int opOr(int j)      { return 23; }
-    int opXor(int j)     { return 24; }
-    int opShl(int j)     { return 25; }
-    int opShl_r(int j)   { return 26; }
-    int opShr(int j)     { return 27; }
-    int opShr_r(int j)   { return 28; }
-    int opUShr(int j)    { return 29; }
-    int opUShr_r(int j)  { return 30; }
-    int opCat(int j)     { return 31; }
-    int opCat_r(int j)   { return 32; }
-    int opEquals(int j)      { return 33; }
+    int opUnary(string op)() if (op == "-")  { return 10; }
+    int opUnary(string op)() if (op == "~")  { return 11; }
+    int opUnary(string op)() if (op == "++") { return 12; }
+    int opUnary(string op)() if (op == "--") { return 13; }
+
+    int opBinary(string op)(int j)      if (op == "+")   { return 14; }
+    int opBinary(string op)(int j)      if (op == "-")   { return 15; }
+    int opBinaryRight(string op)(int j) if (op == "-")   { return 16; }
+    int opBinary(string op)(int j)      if (op == "*")   { return 17; }
+    int opBinary(string op)(int j)      if (op == "/")   { return 18; }
+    int opBinaryRight(string op)(int j) if (op == "/")   { return 19; }
+    int opBinary(string op)(int j)      if (op == "%")   { return 20; }
+    int opBinaryRight(string op)(int j) if (op == "%")   { return 21; }
+    int opBinary(string op)(int j)      if (op == "&")   { return 22; }
+    int opBinary(string op)(int j)      if (op == "|")   { return 23; }
+    int opBinary(string op)(int j)      if (op == "^")   { return 24; }
+    int opBinary(string op)(int j)      if (op == "<<")  { return 25; }
+    int opBinaryRight(string op)(int j) if (op == "<<")  { return 26; }
+    int opBinary(string op)(int j)      if (op == ">>")  { return 27; }
+    int opBinaryRight(string op)(int j) if (op == ">>")  { return 28; }
+    int opBinary(string op)(int j)      if (op == ">>>") { return 29; }
+    int opBinaryRight(string op)(int j) if (op == ">>>") { return 30; }
+    int opBinary(string op)(int j)      if (op == "~")   { return 31; }
+    int opBinaryRight(string op)(int j) if (op == "~")   { return 32; }
+    int opEquals(int j)  { return 33; }
     const bool opEquals(const ref A6)      { return false; }
     int opCmp(int j)     { return 34; }
-    int opAddAssign(int j)  { return 35; }
-    int opSubAssign(int j)  { return 36; }
-    int opMulAssign(int j)  { return 37; }
-    int opDivAssign(int j)  { return 38; }
-    int opModAssign(int j)  { return 39; }
-    int opAndAssign(int j)  { return 40; }
-    int opOrAssign(int j)   { return 41; }
-    int opXorAssign(int j)  { return 42; }
-    int opShlAssign(int j)  { return 43; }
-    int opShrAssign(int j)  { return 44; }
-    int opUShrAssign(int j) { return 45; }
-    int opCatAssign(int j)  { return 46; }
+    int opOpAssign(string op)(int j) if (op == "+")   { return 35; }
+    int opOpAssign(string op)(int j) if (op == "-")   { return 36; }
+    int opOpAssign(string op)(int j) if (op == "*")   { return 37; }
+    int opOpAssign(string op)(int j) if (op == "/")   { return 38; }
+    int opOpAssign(string op)(int j) if (op == "%")   { return 39; }
+    int opOpAssign(string op)(int j) if (op == "&")   { return 40; }
+    int opOpAssign(string op)(int j) if (op == "|")   { return 41; }
+    int opOpAssign(string op)(int j) if (op == "^")   { return 42; }
+    int opOpAssign(string op)(int j) if (op == "<<")  { return 43; }
+    int opOpAssign(string op)(int j) if (op == ">>")  { return 44; }
+    int opOpAssign(string op)(int j) if (op == ">>>") { return 45; }
+    int opOpAssign(string op)(int j) if (op == "~")   { return 46; }
 }
 
 void test6()
@@ -497,10 +450,10 @@  void test6()
     i = ~a;
     assert(i == 11);
 
-    i = a++;
+    i = ++a;
     assert(i == 12);
 
-    i = a--;
+    i = --a;
     assert(i == 13);
 
     i = a + 1;
@@ -589,13 +542,9 @@  void test6()
 
     i = (a += 1);
     assert(i == 35);
-    i = ++a;
-    assert(i == 35);
 
     i = (a -= 1);
     assert(i == 36);
-    i = --a;
-    assert(i == 36);
 
     i = (a *= 1);
     assert(i == 37);
@@ -652,19 +601,19 @@  void test7()
 
 interface IWriter
 {
-        int opShl (string i);
-        int opShl (int i);
+        int opBinary(string op)(string i) if (op == "<<");
+        int opBinary(string op)(int i) if (op == "<<");
 }
 
 class Writer : IWriter
 {
-    int opShl (string i)
+    int opBinary(string op)(string i) if (op == "<<")
     {
         printf("Writer.opShl(char[])\n");
         return 1;
     }
 
-    int opShl (int i)
+    int opBinary(string op)(int i) if (op == "<<")
     {
         printf("Writer.opShl(int)\n");
         return 2;
@@ -673,9 +622,13 @@  class Writer : IWriter
 
 class BinaryWriter : Writer
 {
-    alias Writer.opShl opShl;
+    int opBinary(string op)(string i) if (op == "<<")
+    {
+        printf("Writer.opShl(char[])\n");
+        return 1;
+    }
 
-    override int opShl (int i)
+    int opBinary(string op)(int i) if (op == "<<")
     {
         printf("BinaryWriter.opShl(int)\n");
         return 3;
@@ -712,12 +665,14 @@  void test9()
 
 class A10
 {
-    int opAdd(int i) { return i + 1; }
+    int opBinary(string op)(int i) if (op == "+") { return i + 1; }
+    alias opBinaryRight = opBinary;
 }
 
 class B10
 {
-    int opAdd_r(A10 a) { return 3; }
+    int opBinaryRight(string op)(A10 a) if (op == "+") { return 3; }
+    alias opBinary = opBinaryRight;
 }
 
 void test10()
@@ -791,13 +746,13 @@  void test12()
 
 class A13
 {
- A13 opShl(int x)
+ A13 opBinary(string op)(int x) if (op == "<<")
  {
     printf("A::opShl(int %d)\n", x);
     printf("%d",x);
     return this;
  }
- A13 opShl(string x)
+ A13 opBinary(string op)(string x) if (op == "<<")
  {
     printf("A::opShl(char[])\n");
     printf("%.*s", cast(int)x.length, x.ptr);
@@ -807,7 +762,7 @@  class A13
 
 class B13
 {
- A13 opShl_r(A13 a)
+ A13 opBinaryRight(string op)(A13 a) if (op == "<<")
  {
     printf("B::opShl_r(A)\n");
     return a;
@@ -829,7 +784,7 @@  void test13()
 class Foo14
 {   int a;
 
-    int opIn(int x)
+    int opBinary(string op)(int x) if (op == "in")
     {
         return a + x;
     }
@@ -999,18 +954,6 @@  struct Vec12778X
     float x = 0, y = 0;
 }
 
-struct Vec12778Y
-{
-    Vec12778Y opAdd()(Vec12778Y b) const
-    {
-        enum op = "+";
-        mixin("return Vec12778Y(this.x " ~ op ~ " b.x, this.y " ~ op ~ " b.y);");
-    }
-    alias opAdd_r = opAdd;
-
-    float x = 0, y = 0;
-}
-
 void test12778()
 {
     struct S
@@ -1018,17 +961,14 @@  void test12778()
         void test1()
         {
             Vec12778X vx = vx1 + vx2;   // ok
-            Vec12778Y vy = vy1 + vy2;   // ok
         }
 
         void test2() const
         {
             Vec12778X vx = vx1 + vx2;   // ok <- error
-            Vec12778Y vy = vy1 + vy2;   // ok <- error
         }
 
         Vec12778X vx1, vx2;
-        Vec12778Y vy1, vy2;
     }
 }
 
@@ -1049,8 +989,8 @@  struct S14343b
     int i;
     immutable(Object) o;
 
-    void opAddAssign(int j) { i += j; }
-    S14343b opPostInc() { ++i; return this; }
+    void opOpAssign(string op)(int j) if (op == "+") { i += j; }
+    S14343b opUnary(string op)() if (op == "++") { ++i; return this; }
     void opAssign(S14343b other) {}
 }
 
diff --git a/gcc/testsuite/gdc.test/runnable/sctor2.d b/gcc/testsuite/gdc.test/runnable/sctor2.d
index a2367cf7999..bd820e498f4 100644
--- a/gcc/testsuite/gdc.test/runnable/sctor2.d
+++ b/gcc/testsuite/gdc.test/runnable/sctor2.d
@@ -1,5 +1,10 @@ 
-// REQUIRED_ARGS: -w -de
+// REQUIRED_ARGS: -w -dw
 // PERMUTE_ARGS:
+/* TEST_OUTPUT:
+---
+runnable/sctor2.d(12): Deprecation: `scope` as a type constraint is deprecated.  Use `scope` at the usage site.
+---
+*/
 
 /***************************************************/
 // 15665
diff --git a/gcc/testsuite/gdc.test/runnable/test22136.d b/gcc/testsuite/gdc.test/runnable/test22136.d
deleted file mode 100644
index 8b5af24396e..00000000000
--- a/gcc/testsuite/gdc.test/runnable/test22136.d
+++ /dev/null
@@ -1,25 +0,0 @@ 
-
-interface IObject
-{
-    size_t toHash() @trusted nothrow;
-}
-
-interface Dummy {}
-interface Bug(E) : Dummy, IObject {}
-interface OK(E) : IObject, Dummy {}
-
-void main()
-{
-
-    {
-        Bug!string s;
-        size_t t = hashOf(s);
-    }
-    {
-        OK!string s;
-        size_t t = hashOf(s);
-    }
-
-    static assert(is(immutable Bug!string* : immutable IObject*));
-    static assert(is(immutable OK!string* : immutable IObject*));
-}
diff --git a/gcc/testsuite/gdc.test/runnable/testconst.d b/gcc/testsuite/gdc.test/runnable/testconst.d
index 191ddadc9f2..17e3236f80f 100644
--- a/gcc/testsuite/gdc.test/runnable/testconst.d
+++ b/gcc/testsuite/gdc.test/runnable/testconst.d
@@ -2175,13 +2175,13 @@  void test4251b()
     // derived class to const(base interface) in tail
     interface I {}
     class X : I {}
-    static assert(is( X[] : const(I)[] ));
+    static assert(!is( X[] : const(I)[] ));
 
     // interface to const(base interface) in tail
     interface J {}
     interface K : I, J {}
     static assert( is( K[] : const(I)[] )); // OK, runtime offset is same
-    static assert(is( K[] : const(J)[] )); // !? NG, runtime offset is different
+    static assert(!is( K[] : const(J)[] )); // NG, runtime offset is different
 }
 
 /************************************/
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46.d b/gcc/testsuite/gdc.test/runnable/xtest46.d
index a66e00f0c5d..eeaa1dbe72d 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest46.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest46.d
@@ -14,14 +14,6 @@  tuple(height)
 tuple(get, get)
 tuple(clear)
 tuple(draw, draw)
-runnable/xtest46.d(149): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(151): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(152): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(154): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(181): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(183): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(184): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46.d(186): Deprecation: `opDot` is deprecated. Use `alias this`
 const(int)
 string[]
 double[]
@@ -137,10 +129,7 @@  struct T6
     S6 s;
     int b = 7;
 
-    S6* opDot() return
-    {
-        return &s;
-    }
+    alias s this;
 }
 
 void test6()
@@ -169,10 +158,7 @@  class C7
     S7 s;
     int b = 7;
 
-    S7* opDot()
-    {
-        return &s;
-    }
+    alias s this;
 }
 
 void test7()
diff --git a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d
index 14b82a00cd3..348c05bd09d 100644
--- a/gcc/testsuite/gdc.test/runnable/xtest46_gc.d
+++ b/gcc/testsuite/gdc.test/runnable/xtest46_gc.d
@@ -15,14 +15,6 @@  tuple(height)
 tuple(get, get)
 tuple(clear)
 tuple(draw, draw)
-runnable/xtest46_gc.d-mixin-$n$(185): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(187): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(188): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(190): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(217): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(219): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(220): Deprecation: `opDot` is deprecated. Use `alias this`
-runnable/xtest46_gc.d-mixin-$n$(222): Deprecation: `opDot` is deprecated. Use `alias this`
 const(int)
 string[]
 double[]
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index c4b1538b3a4..77b6ad00173 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-0316b981e5f2fa1525e893c5d94c59c847a8c386
+26b581670ef6e2643d74078f200d1cd21fa40e90
 
 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/internal/gc/bits.d b/libphobos/libdruntime/core/internal/gc/bits.d
index 3c1bb543460..aa94e407642 100644
--- a/libphobos/libdruntime/core/internal/gc/bits.d
+++ b/libphobos/libdruntime/core/internal/gc/bits.d
@@ -239,7 +239,9 @@  struct GCBits
             size_t cntWords = lastWord - firstWord;
             copyWordsShifted(firstWord, cntWords, firstOff, source);
 
-            wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff)) | (source[cntWords] << firstOff);
+            wordtype src = (source[cntWords - 1] >> (BITS_PER_WORD - firstOff));
+            if (lastOff >= firstOff) // prevent buffer overread
+                src |= (source[cntWords] << firstOff);
             wordtype mask = (BITS_2 << lastOff) - 1;
             data[lastWord] = (data[lastWord] & ~mask) | (src & mask);
         }
diff --git a/libphobos/libdruntime/core/stdc/config.d b/libphobos/libdruntime/core/stdc/config.d
index 44bb7077b59..037af25a675 100644
--- a/libphobos/libdruntime/core/stdc/config.d
+++ b/libphobos/libdruntime/core/stdc/config.d
@@ -34,7 +34,7 @@  version (StdDdoc)
             alias ddoc_long = int;
             alias ddoc_ulong = uint;
         }
-        struct ddoc_complex(T) { T re; T im; };
+        struct ddoc_complex(T) { T re; T im; }
     }
 
     /***
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index 3002c022613..88123fb16a6 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -151,6 +151,8 @@  version (GNUFP)
     // https://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/sparc/fpu/bits/fenv.h
     else version (SPARC_Any)
     {
+        import core.stdc.config : c_ulong;
+
         alias fenv_t = c_ulong;
         alias fexcept_t = c_ulong;
     }
diff --git a/libphobos/libdruntime/core/stdc/stdint.d b/libphobos/libdruntime/core/stdc/stdint.d
index 9db2fdaa691..556ac019eeb 100644
--- a/libphobos/libdruntime/core/stdc/stdint.d
+++ b/libphobos/libdruntime/core/stdc/stdint.d
@@ -36,20 +36,7 @@  extern (C):
 nothrow:
 @nogc:
 
-// These are defined the same way as D basic types, so the definition is
-// platform-independant
-alias int8_t   = byte;   ///
-alias int16_t  = short;  ///
-alias uint8_t  = ubyte;  ///
-alias uint16_t = ushort; ///
-
-// 32 bit types and need to be defined on-platform basis, because
-// they might have C++ binary mangling of `int` or `long`.
-// 64-bit types respectively might be mangled as `long` or `long long`
-
-// It would seem correct to define intmax_t and uintmax_t here, but C and C++
-// compilers don't in practice always set them to the maximum supported value.
-// See https://quuxplusone.github.io/blog/2019/02/28/is-int128-integral/
+
 static if (is(ucent))
 {
     alias int128_t = cent;   ///
@@ -58,6 +45,10 @@  static if (is(ucent))
 
 version (Windows)
 {
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
     version (CRuntime_DigitalMars)
     {
         alias int32_t  = cpp_long;  ///
@@ -71,23 +62,31 @@  version (Windows)
     alias int64_t  = long;   ///
     alias uint64_t = ulong;  ///
 
-    alias int_least8_t   = byte; ///
-    alias uint_least8_t  = ubyte; ///
-    alias int_least16_t  = short; ///
-    alias uint_least16_t = ushort; ///
-    alias int_least32_t  = int32_t; ///
+    alias int_least8_t   = byte;     ///
+    alias uint_least8_t  = ubyte;    ///
+    alias int_least16_t  = short;    ///
+    alias uint_least16_t = ushort;   ///
+    alias int_least32_t  = int32_t;  ///
     alias uint_least32_t = uint32_t; ///
-    alias int_least64_t  = long; ///
-    alias uint_least64_t = ulong; ///
+    alias int_least64_t  = long;     ///
+    alias uint_least64_t = ulong;    ///
 
-    alias int_fast8_t   = byte; ///
-    alias uint_fast8_t  = ubyte; ///
-    alias int_fast16_t  = int; ///
-    alias uint_fast16_t = uint; ///
-    alias int_fast32_t  = int32_t; ///
+    alias int_fast8_t   = byte;     ///
+    alias uint_fast8_t  = ubyte;    ///
+    version (MinGW)
+    {
+        alias int_fast16_t  = short;  ///
+        alias uint_fast16_t = ushort; ///
+    }
+    else
+    {
+        alias int_fast16_t  = int;  ///
+        alias uint_fast16_t = uint; ///
+    }
+    alias int_fast32_t  = int32_t;  ///
     alias uint_fast32_t = uint32_t; ///
-    alias int_fast64_t  = long; ///
-    alias uint_fast64_t = ulong; ///
+    alias int_fast64_t  = long;     ///
+    alias uint_fast64_t = ulong;    ///
 
     alias intptr_t  = ptrdiff_t; ///
     alias uintptr_t = size_t;    ///
@@ -96,6 +95,10 @@  version (Windows)
 }
 else version (Darwin)
 {
+    alias int8_t   = byte;          ///
+    alias int16_t  = short;         ///
+    alias uint8_t  = ubyte;         ///
+    alias uint16_t = ushort;        ///
     alias int32_t  = int;           ///
     alias uint32_t = uint;          ///
     alias int64_t  = cpp_longlong;  ///
@@ -124,32 +127,27 @@  else version (Darwin)
     alias intmax_t  = long;      ///
     alias uintmax_t = ulong;     ///
 }
-else version (Posix)
+else version (linux)
 {
-    alias int32_t  = int; ///
-    alias uint32_t = uint; ///
-    alias int64_t  = long; ///
-    alias uint64_t = ulong; ///
-
-    alias int_least8_t   = byte; ///
-    alias uint_least8_t  = ubyte; ///
-    alias int_least16_t  = short; ///
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = byte;   ///
+    alias uint_least8_t  = ubyte;  ///
+    alias int_least16_t  = short;  ///
     alias uint_least16_t = ushort; ///
-    alias int_least32_t  = int; ///
-    alias uint_least32_t = uint; ///
-    alias int_least64_t  = long; ///
-    alias uint_least64_t = ulong;///
+    alias int_least32_t  = int;    ///
+    alias uint_least32_t = uint;   ///
+    alias int_least64_t  = long;   ///
+    alias uint_least64_t = ulong;  ///
 
-    version (FreeBSD)
-    {
-        alias int_fast8_t   = int;  ///
-        alias uint_fast8_t  = uint; ///
-        alias int_fast16_t  = int;  ///
-        alias uint_fast16_t = uint; ///
-        alias int_fast32_t  = int;  ///
-        alias uint_fast32_t = uint; ///
-    }
-    else version (CRuntime_Musl)
+    version (CRuntime_Musl)
     {
         alias int_fast8_t   = byte;  ///
         alias uint_fast8_t  = ubyte; ///
@@ -167,17 +165,221 @@  else version (Posix)
         alias int_fast32_t  = ptrdiff_t; ///
         alias uint_fast32_t = size_t;    ///
     }
-    alias int_fast64_t  = long; ///
+    alias int_fast64_t  = long;      ///
+    alias uint_fast64_t = ulong;     ///
+
+    alias intptr_t  = ptrdiff_t; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
+}
+else version (CRuntime_Glibc)
+{
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = byte;   ///
+    alias uint_least8_t  = ubyte;  ///
+    alias int_least16_t  = short;  ///
+    alias uint_least16_t = ushort; ///
+    alias int_least32_t  = int;    ///
+    alias uint_least32_t = uint;   ///
+    alias int_least64_t  = long;   ///
+    alias uint_least64_t = ulong;  ///
+
+    alias int_fast8_t   = byte;      ///
+    alias uint_fast8_t  = ubyte;     ///
+    alias int_fast16_t  = ptrdiff_t; ///
+    alias uint_fast16_t = size_t;    ///
+    alias int_fast32_t  = ptrdiff_t; ///
+    alias uint_fast32_t = size_t;    ///
+    alias int_fast64_t  = long;      ///
+    alias uint_fast64_t = ulong;     ///
+
+    alias intptr_t  = ptrdiff_t; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
+}
+else version (DragonFlyBSD)
+{
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = int8_t;   ///
+    alias uint_least8_t  = uint8_t;  ///
+    alias int_least16_t  = int16_t;  ///
+    alias uint_least16_t = uint16_t; ///
+    alias int_least32_t  = int32_t;  ///
+    alias uint_least32_t = uint32_t; ///
+    alias int_least64_t  = int64_t;  ///
+    alias uint_least64_t = uint64_t; ///
+
+    alias int_fast8_t   = int32_t;   ///
+    alias uint_fast8_t  = uint32_t;  ///
+    alias int_fast16_t  = int32_t;   ///
+    alias uint_fast16_t = uint32_t;  ///
+    alias int_fast32_t  = int32_t;   ///
+    alias uint_fast32_t = uint32_t;  ///
+    alias int_fast64_t  = int64_t;   ///
+    alias uint_fast64_t = uint64_t;  ///
+
+    alias intptr_t  = ptrdiff_t; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
+}
+else version (FreeBSD)
+{
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = byte;   ///
+    alias uint_least8_t  = ubyte;  ///
+    alias int_least16_t  = short;  ///
+    alias uint_least16_t = ushort; ///
+    alias int_least32_t  = int;    ///
+    alias uint_least32_t = uint;   ///
+    alias int_least64_t  = long;   ///
+    alias uint_least64_t = ulong;  ///
+
+    alias int_fast8_t   = int;   ///
+    alias uint_fast8_t  = uint;  ///
+    alias int_fast16_t  = int;   ///
+    alias uint_fast16_t = uint;  ///
+    alias int_fast32_t  = int;   ///
+    alias uint_fast32_t = uint;  ///
+    alias int_fast64_t  = long;  ///
     alias uint_fast64_t = ulong; ///
 
     alias intptr_t  = ptrdiff_t; ///
-    alias uintptr_t = size_t; ///
-    alias intmax_t  = long; ///
-    alias uintmax_t = ulong; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
+}
+else version (NetBSD)
+{
+    alias int8_t   = byte;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = int8_t;   ///
+    alias uint_least8_t  = uint8_t;  ///
+    alias int_least16_t  = int16_t;  ///
+    alias uint_least16_t = uint16_t; ///
+    alias int_least32_t  = int32_t;  ///
+    alias uint_least32_t = uint32_t; ///
+    alias int_least64_t  = int64_t;  ///
+    alias uint_least64_t = uint64_t; ///
+
+    alias int_fast8_t   = int32_t;   ///
+    alias uint_fast8_t  = uint32_t;  ///
+    alias int_fast16_t  = int32_t;   ///
+    alias uint_fast16_t = uint32_t;  ///
+    alias int_fast32_t  = int32_t;   ///
+    alias uint_fast32_t = uint32_t;  ///
+    alias int_fast64_t  = int64_t;   ///
+    alias uint_fast64_t = uint64_t;  ///
+
+    alias intptr_t  = ptrdiff_t; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
+}
+else version (OpenBSD)
+{
+    alias int8_t   = byte;          ///
+    alias int16_t  = short;         ///
+    alias uint8_t  = ubyte;         ///
+    alias uint16_t = ushort;        ///
+    alias int32_t  = int;           ///
+    alias uint32_t = uint;          ///
+    alias int64_t  = cpp_longlong;  ///
+    alias uint64_t = cpp_ulonglong; ///
+
+    alias int_least8_t   = byte;          ///
+    alias uint_least8_t  = ubyte;         ///
+    alias int_least16_t  = short;         ///
+    alias uint_least16_t = ushort;        ///
+    alias int_least32_t  = int;           ///
+    alias uint_least32_t = uint;          ///
+    alias int_least64_t  = cpp_longlong;  ///
+    alias uint_least64_t = cpp_ulonglong; ///
+
+    alias int_fast8_t   = int;           ///
+    alias uint_fast8_t  = uint;          ///
+    alias int_fast16_t  = int;           ///
+    alias uint_fast16_t = uint;          ///
+    alias int_fast32_t  = int;           ///
+    alias uint_fast32_t = uint;          ///
+    alias int_fast64_t  = cpp_longlong;  ///
+    alias uint_fast64_t = cpp_ulonglong; ///
+
+    alias intptr_t  = cpp_long;      ///
+    alias uintptr_t = cpp_ulong;     ///
+    alias intmax_t  = cpp_longlong;  ///
+    alias uintmax_t = cpp_ulonglong; ///
+}
+else version (Solaris)
+{
+    alias int8_t   = char;   ///
+    alias int16_t  = short;  ///
+    alias uint8_t  = ubyte;  ///
+    alias uint16_t = ushort; ///
+    alias int32_t  = int;    ///
+    alias uint32_t = uint;   ///
+    alias int64_t  = long;   ///
+    alias uint64_t = ulong;  ///
+
+    alias int_least8_t   = char;   ///
+    alias uint_least8_t  = ubyte;  ///
+    alias int_least16_t  = short;  ///
+    alias uint_least16_t = ushort; ///
+    alias int_least32_t  = int;    ///
+    alias uint_least32_t = uint;   ///
+    alias int_least64_t  = long;   ///
+    alias uint_least64_t = ulong;  ///
+
+    alias int_fast8_t   = char;  ///
+    alias uint_fast8_t  = ubyte; ///
+    alias int_fast16_t  = int;   ///
+    alias uint_fast16_t = uint;  ///
+    alias int_fast32_t  = int;   ///
+    alias uint_fast32_t = uint;  ///
+    alias int_fast64_t  = long;  ///
+    alias uint_fast64_t = ulong; ///
+
+    alias intptr_t  = ptrdiff_t; ///
+    alias uintptr_t = size_t;    ///
+    alias intmax_t  = long;      ///
+    alias uintmax_t = ulong;     ///
 }
 else
 {
-    static assert(0);
+    static assert(false, "Unsupported architecture.");
 }
 
 
diff --git a/libphobos/libdruntime/core/stdcpp/new_.d b/libphobos/libdruntime/core/stdcpp/new_.d
index 77c179ce962..6a598baec28 100644
--- a/libphobos/libdruntime/core/stdcpp/new_.d
+++ b/libphobos/libdruntime/core/stdcpp/new_.d
@@ -26,7 +26,7 @@  extern (C++, "std")
     struct nothrow_t {}
 
     ///
-    enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ };
+    enum align_val_t : size_t { defaultAlignment = __STDCPP_DEFAULT_NEW_ALIGNMENT__ }
 
     ///
     class bad_alloc : exception
diff --git a/libphobos/libdruntime/core/sys/windows/stat.d b/libphobos/libdruntime/core/sys/windows/stat.d
index c9ee6ce5ca8..16f66e1287e 100644
--- a/libphobos/libdruntime/core/sys/windows/stat.d
+++ b/libphobos/libdruntime/core/sys/windows/stat.d
@@ -8,6 +8,8 @@  version (Windows):
 extern (C) nothrow @nogc:
 @system:
 
+import core.sys.windows.stdc.time;
+
 // Posix version is in core.sys.posix.sys.stat
 
 enum S_IFMT   = 0xF000;
@@ -30,22 +32,49 @@  int S_ISDIR(int m)  { return (m & S_IFMT) == S_IFDIR; }
 int S_ISCHR(int m)  { return (m & S_IFMT) == S_IFCHR; }
 }
 
-struct struct_stat
+version (CRuntime_DigitalMars)
 {
-    short st_dev;
-    ushort st_ino;
-    ushort st_mode;
-    short st_nlink;
-    ushort st_uid;
-    ushort st_gid;
-    short st_rdev;
-    short dummy;
-    int st_size;
-    int st_atime;
-    int st_mtime;
-    int st_ctime;
+    struct struct_stat
+    {
+        short st_dev;
+        ushort st_ino;
+        ushort st_mode;
+        short st_nlink;
+        ushort st_uid;
+        ushort st_gid;
+        short st_rdev;
+        short dummy;
+        int st_size;
+        time_t st_atime;
+        time_t st_mtime;
+        time_t st_ctime;
+    }
+
+    int stat(const(char)*, struct_stat *);
+    int fstat(int, struct_stat *) @trusted;
+    int _wstat(const(wchar)*, struct_stat *);
 }
+else version (CRuntime_Microsoft)
+{
+    struct struct_stat
+    {
+        uint st_dev;
+        ushort st_ino;
+        ushort st_mode;
+        short st_nlink;
+        short st_uid;
+        short st_gid;
+        uint st_rdev;
+        int st_size;
+        time_t st_atime;
+        time_t st_mtime;
+        time_t st_ctime;
+    }
 
-int  stat(const(char)*, struct_stat *);
-int  fstat(int, struct_stat *) @trusted;
-int  _wstat(const(wchar)*, struct_stat *);
+    // These assume time_t is 32 bits (which druntime's definition currently is)
+    // Add pragma(mangle) to use _stat64 etc. when time_t is made 64-bit
+    // See also: https://issues.dlang.org/show_bug.cgi?id=21134
+    int stat(const(char)*, struct_stat *);
+    int fstat(int, struct_stat *) @trusted;
+    int _wstat(const(wchar)*, struct_stat *);
+}
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index 1f7a81de80f..b0e25b57054 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -1011,8 +1011,12 @@  extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @
     foreach (T; AliasSeq!(ubyte, ushort, uint, ulong))
     {
     case T.sizeof:
-        (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
-        return result;
+        if (tinext.talign % T.alignof == 0)
+        {
+            (cast(T*)result.ptr)[0 .. size * length / T.sizeof] = *cast(T*)init.ptr;
+            return result;
+        }
+        goto default;
     }
 
     default:
@@ -1118,7 +1122,8 @@  extern (C) void* _d_newitemU(scope const TypeInfo _ti) pure nothrow @weak
 
     if (tiSize)
     {
-        *cast(TypeInfo*)(p + itemSize) = null; // the GC might not have cleared this area
+        // the GC might not have cleared the padding area in the block
+        *cast(TypeInfo*)(p + (itemSize & ~(size_t.sizeof - 1))) = null;
         *cast(TypeInfo*)(p + blkInf.size - tiSize) = cast() ti;
     }
 
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 5fd357c534a..963ffe020de 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-a1f8c4c0700ce4e256f4130ad7883c6ea3890901
+16cb085b584f100fa677e2e64ff6b6dbb4921ad1
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/algorithm/setops.d b/libphobos/src/std/algorithm/setops.d
index ede1831028e..cc6f5b77db7 100644
--- a/libphobos/src/std/algorithm/setops.d
+++ b/libphobos/src/std/algorithm/setops.d
@@ -404,7 +404,7 @@  if (ranges.length >= 2 &&
                     r = ranges[i].save; // rollover
             }
         }
-        @property Result save() scope return
+        @property Result save() return scope
         {
             Result copy = this;
             foreach (i, r; ranges)
diff --git a/libphobos/src/std/bitmanip.d b/libphobos/src/std/bitmanip.d
index 9af9d721230..de2e0fb262f 100644
--- a/libphobos/src/std/bitmanip.d
+++ b/libphobos/src/std/bitmanip.d
@@ -1447,7 +1447,8 @@  public:
             size_t bitCount;
             foreach (i; 0 .. fullWords)
                 bitCount += countBitsSet(_ptr[i]);
-            bitCount += countBitsSet(_ptr[fullWords] & endMask);
+            if (endBits)
+                bitCount += countBitsSet(_ptr[fullWords] & endMask);
             return bitCount;
         }
         else
diff --git a/libphobos/src/std/datetime/interval.d b/libphobos/src/std/datetime/interval.d
index ba2a21056c7..d787e3a8080 100644
--- a/libphobos/src/std/datetime/interval.d
+++ b/libphobos/src/std/datetime/interval.d
@@ -7848,12 +7848,12 @@  if (isTimePoint!TP &&
         duration = The duration which separates each successive time point in
                    the range.
   +/
-TP delegate(scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow
+TP delegate(return scope const TP) everyDuration(TP, Direction dir = Direction.fwd, D)(D duration) nothrow
 if (isTimePoint!TP &&
     __traits(compiles, TP.init + duration) &&
     (dir == Direction.fwd || dir == Direction.bwd))
 {
-    TP func(scope const TP tp)
+    TP func(return scope const TP tp)
     {
         static if (dir == Direction.fwd)
             return tp + duration;
diff --git a/libphobos/src/std/datetime/systime.d b/libphobos/src/std/datetime/systime.d
index db325f727e8..949ad7d75cc 100644
--- a/libphobos/src/std/datetime/systime.d
+++ b/libphobos/src/std/datetime/systime.d
@@ -6269,7 +6269,7 @@  public:
             duration = The $(REF Duration, core,time) to add to or subtract from
                        this $(LREF SysTime).
       +/
-    SysTime opBinary(string op)(Duration duration) @safe const pure nothrow scope
+    SysTime opBinary(string op)(Duration duration) @safe const pure nothrow return scope
         if (op == "+" || op == "-")
     {
         SysTime retval = SysTime(this._stdTime, this._timezone);
@@ -7668,7 +7668,7 @@  public:
         $(LREF SysTime) for the last day in the month that this Date is in.
         The time portion of endOfMonth is always 23:59:59.9999999.
       +/
-    @property SysTime endOfMonth() @safe const nothrow scope
+    @property SysTime endOfMonth() @safe const nothrow return scope
     {
         immutable hnsecs = adjTime;
         immutable days = getUnitsFromHNSecs!"days"(hnsecs);
diff --git a/libphobos/src/std/experimental/allocator/mallocator.d b/libphobos/src/std/experimental/allocator/mallocator.d
index 895d5883f52..de9afbbf7d5 100644
--- a/libphobos/src/std/experimental/allocator/mallocator.d
+++ b/libphobos/src/std/experimental/allocator/mallocator.d
@@ -392,6 +392,7 @@  version (Posix)
     AlignedMallocator.instance.alignedReallocate(c, 32, 32);
     assert(c.ptr);
 
+    version (LDC_AddressSanitizer) {} else // AddressSanitizer does not support such large memory allocations (0x10000000000 max)
     version (DragonFlyBSD) {} else    /* FIXME: Malloc on DragonFly does not return NULL when allocating more than UINTPTR_MAX
                                        * $(LINK: https://bugs.dragonflybsd.org/issues/3114, dragonfly bug report)
                                        * $(LINK: https://github.com/dlang/druntime/pull/1999#discussion_r157536030, PR Discussion) */
diff --git a/libphobos/src/std/functional.d b/libphobos/src/std/functional.d
index da698e045fe..90b0f91ecce 100644
--- a/libphobos/src/std/functional.d
+++ b/libphobos/src/std/functional.d
@@ -1847,3 +1847,168 @@  if (isCallable!(F))
         static assert(! is(typeof(dg_xtrnC) == typeof(dg_xtrnD)));
     }
 }
+
+// Converts an unsigned integer to a compile-time string constant.
+private enum toCtString(ulong n) = n.stringof[0 .. $ - "LU".length];
+
+// Check that .stringof does what we expect, since it's not guaranteed by the
+// language spec.
+@safe unittest
+{
+    assert(toCtString!0 == "0");
+    assert(toCtString!123456 == "123456");
+}
+
+/**
+ * Passes the fields of a struct as arguments to a function.
+ *
+ * Can be used with a $(LINK2 https://dlang.org/spec/expression.html#function_literals,
+ * function literal) to give temporary names to the fields of a struct or
+ * tuple.
+ *
+ * Params:
+ *   fun = Callable that the struct's fields will be passed to.
+ *
+ * Returns:
+ *   A function that accepts a single struct as an argument and passes its
+ *   fields to `fun` when called.
+ */
+template bind(alias fun)
+{
+    /**
+     * Params:
+     *   args = The struct or tuple whose fields will be used as arguments.
+     *
+     * Returns: `fun(args.tupleof)`
+     */
+    auto ref bind(T)(auto ref T args)
+    if (is(T == struct))
+    {
+        import std.meta : Map = staticMap;
+        import core.lifetime : move;
+
+        // Forwards the i'th member of `args`
+        // Needed because core.lifetime.forward doesn't work on struct members
+        template forwardArg(size_t i)
+        {
+            static if (__traits(isRef, args) || !is(typeof(move(args.tupleof[i]))))
+                enum forwardArg = "args.tupleof[" ~ toCtString!i ~ "], ";
+            else
+                enum forwardArg = "move(args.tupleof[" ~ toCtString!i ~ "]), ";
+        }
+
+        static if (args.tupleof.length == 0)
+            enum argList = "";
+        else
+            alias argList = Map!(forwardArg, Iota!(args.tupleof.length));
+
+        return mixin("fun(", argList, ")");
+    }
+}
+
+/// Giving names to tuple elements
+@safe unittest
+{
+    import std.typecons : tuple;
+
+    auto name = tuple("John", "Doe");
+    string full = name.bind!((first, last) => first ~ " " ~ last);
+    assert(full == "John Doe");
+}
+
+/// Passing struct fields to a function
+@safe unittest
+{
+    import std.algorithm.comparison : min, max;
+
+    struct Pair
+    {
+        int a;
+        int b;
+    }
+
+    auto p = Pair(123, 456);
+    assert(p.bind!min == 123); // min(p.a, p.b)
+    assert(p.bind!max == 456); // max(p.a, p.b)
+}
+
+/// In a range pipeline
+@safe unittest
+{
+    import std.algorithm.iteration : map, filter;
+    import std.algorithm.comparison : equal;
+    import std.typecons : tuple;
+
+    auto ages = [
+        tuple("Alice", 35),
+        tuple("Bob",   64),
+        tuple("Carol", 21),
+        tuple("David", 39),
+        tuple("Eve",   50)
+    ];
+
+    auto overForty = ages
+        .filter!(bind!((name, age) => age > 40))
+        .map!(bind!((name, age) => name));
+
+    assert(overForty.equal(["Bob", "Eve"]));
+}
+
+// Zero arguments
+@safe unittest
+{
+    struct Empty {}
+
+    assert(Empty().bind!(() => 123) == 123);
+}
+
+// Non-copyable arguments
+@safe unittest
+{
+    import std.typecons : tuple;
+
+    static struct NoCopy
+    {
+        int n;
+        @disable this(this);
+    }
+
+    static struct Pair
+    {
+        NoCopy a, b;
+    }
+
+    static auto fun(NoCopy a, NoCopy b)
+    {
+        return tuple(a.n, b.n);
+    }
+
+    auto expected = fun(NoCopy(1), NoCopy(2));
+    assert(Pair(NoCopy(1), NoCopy(2)).bind!fun == expected);
+}
+
+// ref arguments
+@safe unittest
+{
+    import std.typecons : tuple;
+
+    auto t = tuple(123, 456);
+    t.bind!((ref int a, int b) { a = 789; b = 1011; });
+
+    assert(t[0] == 789);
+    assert(t[1] == 456);
+}
+
+// auto ref arguments
+@safe unittest
+{
+    import std.typecons : tuple;
+
+    auto t = tuple(123);
+    t.bind!((auto ref x) {
+        static assert(__traits(isRef, x));
+    });
+    tuple(123).bind!((auto ref x) {
+        static assert(!__traits(isRef, x));
+    });
+}
diff --git a/libphobos/src/std/sumtype.d b/libphobos/src/std/sumtype.d
index 3833c84243c..8da38bdb4e6 100644
--- a/libphobos/src/std/sumtype.d
+++ b/libphobos/src/std/sumtype.d
@@ -13,6 +13,7 @@  include:
 
 License: Boost License 1.0
 Authors: Paul Backus
+Source: $(PHOBOSSRC std/sumtype.d)
 +/
 module std.sumtype;
 
diff --git a/libphobos/src/std/utf.d b/libphobos/src/std/utf.d
index 5c23684b9ae..f0200ce7052 100644
--- a/libphobos/src/std/utf.d
+++ b/libphobos/src/std/utf.d
@@ -1209,6 +1209,15 @@  do
     assert("ë"w.decode(i) == 'ë' && i == 1);
 }
 
+@safe pure unittest // https://issues.dlang.org/show_bug.cgi?id=22867
+{
+    import std.conv : hexString;
+    string data = hexString!"f787a598";
+    size_t offset = 0;
+    try data.decode(offset);
+    catch (UTFException ex) assert(offset == 0);
+}
+
 /++
     `decodeFront` is a variant of $(LREF decode) which specifically decodes
     the first code point. Unlike $(LREF decode), `decodeFront` accepts any
@@ -1671,7 +1680,6 @@  if (
                 }
             }
 
-            index += i + 1;
             static if (i == 3)
             {
                 if (d > dchar.max)
@@ -1682,6 +1690,8 @@  if (
                         throw invalidUTF();
                 }
             }
+
+            index += i + 1;
             return d;
         }
     }