diff mbox series

[committed] d: Merge upstream dmd, druntime f1a045928e

Message ID 20240202232050.92754-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd, druntime f1a045928e | expand

Commit Message

Iain Buclaw Feb. 2, 2024, 11:20 p.m. UTC
Hi,

This patch merges the D front-end and runtime library with upstream as
of dmd f1a045928e. 

Synchronizing with the upstream RC release of v2.106.1.

D front-end changes:

    - Import dmd v2.106.1-rc.1.
    - Unrecognized pragmas are no longer an error by default.

D runtime changes:

    - Import druntime v2.106.1-rc.1.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd f1a045928e.
	* dmd/VERSION: Bump version to v2.106.1-rc.1.
	* gdc.texi (fignore-unknown-pragmas): Update documentation.
	* d-builtins.cc (covariant_with_builtin_type_p): Update for new
	front-end interface.
	* d-lang.cc (d_parse_file): Likewise.
	* typeinfo.cc (make_frontend_typeinfo): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime f1a045928e.
	* libdruntime/Makefile.am (DRUNTIME_DSOURCES): Add
	core/stdc/stdatomic.d.
	* libdruntime/Makefile.in: Regenerate.
---
 gcc/d/d-builtins.cc                           |    2 +-
 gcc/d/d-lang.cc                               |    3 +-
 gcc/d/dmd/MERGE                               |    2 +-
 gcc/d/dmd/VERSION                             |    2 +-
 gcc/d/dmd/aliasthis.d                         |  166 +--
 gcc/d/dmd/astcodegen.d                        |    2 +-
 gcc/d/dmd/attrib.d                            |  103 --
 gcc/d/dmd/attrib.h                            |    5 -
 gcc/d/dmd/cparse.d                            |  113 +-
 gcc/d/dmd/ctfeexpr.d                          |    3 +
 gcc/d/dmd/dcast.d                             |    1 +
 gcc/d/dmd/dclass.d                            |    5 +-
 gcc/d/dmd/declaration.d                       |  287 -----
 gcc/d/dmd/declaration.h                       |    1 -
 gcc/d/dmd/dimport.d                           |   42 -
 gcc/d/dmd/dmodule.d                           |  118 +-
 gcc/d/dmd/doc.d                               |   11 +-
 gcc/d/dmd/dscope.d                            |   37 +-
 gcc/d/dmd/dstruct.d                           |    2 +-
 gcc/d/dmd/dsymbol.d                           |   75 +-
 gcc/d/dmd/dsymbol.h                           |   35 +-
 gcc/d/dmd/dsymbolsem.d                        |  749 ++++++++++-
 gcc/d/dmd/dtemplate.d                         |   11 +-
 gcc/d/dmd/dtoh.d                              |    2 +-
 gcc/d/dmd/errorsink.d                         |   14 +
 gcc/d/dmd/expression.d                        |    3 +-
 gcc/d/dmd/expressionsem.d                     |   32 +-
 gcc/d/dmd/func.d                              |    5 +
 gcc/d/dmd/globals.d                           |    2 +-
 gcc/d/dmd/import.h                            |    1 -
 gcc/d/dmd/init.d                              |    6 -
 gcc/d/dmd/initsem.d                           |   77 +-
 gcc/d/dmd/lambdacomp.d                        |    2 +-
 gcc/d/dmd/lexer.d                             |   35 +-
 gcc/d/dmd/module.h                            |    5 +-
 gcc/d/dmd/mtype.d                             |  834 +-----------
 gcc/d/dmd/mtype.h                             |    4 +-
 gcc/d/dmd/nspace.d                            |   16 -
 gcc/d/dmd/nspace.h                            |    1 -
 gcc/d/dmd/scope.h                             |    2 +-
 gcc/d/dmd/semantic3.d                         |    3 +-
 gcc/d/dmd/statement.d                         |    8 +-
 gcc/d/dmd/statement.h                         |    2 +-
 gcc/d/dmd/statementsem.d                      |   22 +-
 gcc/d/dmd/staticassert.d                      |    3 -
 gcc/d/dmd/template.h                          |    1 -
 gcc/d/dmd/traits.d                            |    6 +-
 gcc/d/dmd/typesem.d                           |  802 +++++++++++-
 gcc/d/gdc.texi                                |    6 +-
 gcc/d/typeinfo.cc                             |    3 +-
 .../gdc.test/compilable/imports/defines.c     |    4 +
 gcc/testsuite/gdc.test/compilable/test9565.d  |   86 --
 .../gdc.test/compilable/testdefines.d         |    3 +
 .../gdc.test/fail_compilation/fail19890a.d    |    2 +-
 .../gdc.test/fail_compilation/fail19890b.d    |    2 +-
 .../gdc.test/fail_compilation/fail4611.d      |    2 +-
 .../gdc.test/fail_compilation/pragmas.d       |    3 +-
 libphobos/libdruntime/MERGE                   |    2 +-
 libphobos/libdruntime/Makefile.am             |   40 +-
 libphobos/libdruntime/Makefile.in             |   76 +-
 .../core/internal/array/operations.d          |   35 +-
 libphobos/libdruntime/core/internal/atomic.d  |  105 +-
 libphobos/libdruntime/core/stdc/stdatomic.d   | 1124 +++++++++++++++++
 libphobos/libdruntime/core/thread/osthread.d  |    7 +
 libphobos/libdruntime/object.d                |    6 +
 65 files changed, 3209 insertions(+), 1960 deletions(-)
 delete mode 100644 gcc/testsuite/gdc.test/compilable/test9565.d
 create mode 100644 libphobos/libdruntime/core/stdc/stdatomic.d
diff mbox series

Patch

diff --git a/gcc/d/d-builtins.cc b/gcc/d/d-builtins.cc
index 59a1b4ca01c..9d604974f85 100644
--- a/gcc/d/d-builtins.cc
+++ b/gcc/d/d-builtins.cc
@@ -724,7 +724,7 @@  static bool
 covariant_with_builtin_type_p (Type *t1, Type *t2)
 {
   /* Check whether the declared function matches the built-in.  */
-  if (same_type_p (t1, t2) || t1->covariant (t2) == Covariant::yes)
+  if (same_type_p (t1, t2) || covariant (t1, t2) == Covariant::yes)
     return true;
 
   /* May not be covariant because of D attributes applied on t1.
diff --git a/gcc/d/d-lang.cc b/gcc/d/d-lang.cc
index 7840cf8a132..a25d0316da6 100644
--- a/gcc/d/d-lang.cc
+++ b/gcc/d/d-lang.cc
@@ -23,6 +23,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "dmd/cond.h"
 #include "dmd/declaration.h"
 #include "dmd/doc.h"
+#include "dmd/dsymbol.h"
 #include "dmd/errors.h"
 #include "dmd/expression.h"
 #include "dmd/hdrgen.h"
@@ -1226,7 +1227,7 @@  d_parse_file (void)
       if (global.params.v.verbose)
 	message ("importall %s", m->toChars ());
 
-      m->importAll (NULL);
+      importAll (m, NULL);
     }
 
   if (global.errors)
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 5edcee1c84d..fa7004b7a41 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-2bbf64907cbbb483d003e0a8fcf8b502e4883799
+f1a045928e03239b9477f9497f43f2cf0e61e959
 
 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 8c95cd04f80..9d7be5b4326 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.106.0
+v2.106.1-rc.1
diff --git a/gcc/d/dmd/aliasthis.d b/gcc/d/dmd/aliasthis.d
index a8933f6d2fe..0c156360fdc 100644
--- a/gcc/d/dmd/aliasthis.d
+++ b/gcc/d/dmd/aliasthis.d
@@ -14,16 +14,10 @@ 
 module dmd.aliasthis;
 
 import core.stdc.stdio;
-import dmd.aggregate;
-import dmd.dscope;
+
 import dmd.dsymbol;
-import dmd.expression;
-import dmd.expressionsem;
-import dmd.globals;
 import dmd.identifier;
 import dmd.location;
-import dmd.mtype;
-import dmd.tokens;
 import dmd.visitor;
 
 /***********************************************************
@@ -71,161 +65,3 @@  extern (C++) final class AliasThis : Dsymbol
         return this.isDeprecated_;
     }
 }
-
-/*************************************
- * Find the `alias this` symbol of e's type.
- * Params:
- *      sc = context
- *      e = expression forming the `this`
- *      gag = do not print errors, return `null` instead
- *      findOnly = don't do further processing like resolving properties,
- *                 i.e. just return plain dotExp() result.
- * Returns:
- *      Expression that is `e.aliasthis`
- */
-Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
-{
-    import dmd.typesem : dotExp;
-    for (AggregateDeclaration ad = isAggregate(e.type); ad;)
-    {
-        if (ad.aliasthis)
-        {
-            Loc loc = e.loc;
-            Type tthis = (e.op == EXP.type ? e.type : null);
-            const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
-            uint olderrors = gag ? global.startGagging() : 0;
-            e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
-            if (!e || findOnly)
-                return gag && global.endGagging(olderrors) ? null : e;
-
-            if (tthis && ad.aliasthis.sym.needThis())
-            {
-                if (auto ve = e.isVarExp())
-                {
-                    if (auto fd = ve.var.isFuncDeclaration())
-                    {
-                        // https://issues.dlang.org/show_bug.cgi?id=13009
-                        // Support better match for the overloaded alias this.
-                        bool hasOverloads;
-                        if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
-                        {
-                            if (!hasOverloads)
-                                fd = f;     // use exact match
-                            e = new VarExp(loc, fd, hasOverloads);
-                            e.type = f.type;
-                            e = new CallExp(loc, e);
-                            goto L1;
-                        }
-                    }
-                }
-                /* non-@property function is not called inside typeof(),
-                 * so resolve it ahead.
-                 */
-                {
-                    int save = sc.intypeof;
-                    sc.intypeof = 1; // bypass "need this" error check
-                    e = resolveProperties(sc, e);
-                    sc.intypeof = save;
-                }
-            L1:
-                e = new TypeExp(loc, new TypeTypeof(loc, e));
-                e = e.expressionSemantic(sc);
-            }
-            e = resolveProperties(sc, e);
-            if (!gag)
-                ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
-            else if (global.endGagging(olderrors))
-                e = null;
-        }
-
-        import dmd.dclass : ClassDeclaration;
-        auto cd = ad.isClassDeclaration();
-        if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
-        {
-            ad = cd.baseClass;
-            continue;
-        }
-        break;
-    }
-    return e;
-}
-
-/**
- * Check if an `alias this` is deprecated
- *
- * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
- * check if `expression` uses a deprecated `aliasthis`, but this calls
- * `toPrettyChars` which lead to the following message:
- * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
- *
- * Params:
- *   at  = The `AliasThis` object to check
- *   loc = `Loc` of the expression triggering the access to `at`
- *   sc  = `Scope` of the expression
- *         (deprecations do not trigger in deprecated scopes)
- *
- * Returns:
- *   Whether the alias this was reported as deprecated.
- */
-bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
-{
-    import dmd.errors : deprecation, Classification;
-    import dmd.dsymbolsem : getMessage;
-
-    if (global.params.useDeprecated != DiagnosticReporting.off
-        && at.isDeprecated() && !sc.isDeprecated())
-    {
-        const(char)* message = null;
-        for (Dsymbol p = at; p; p = p.parent)
-        {
-            message = p.depdecl ? p.depdecl.getMessage() : null;
-            if (message)
-                break;
-        }
-        if (message)
-            deprecation(loc, "`alias %s this` is deprecated - %s",
-                        at.sym.toChars(), message);
-        else
-            deprecation(loc, "`alias %s this` is deprecated",
-                        at.sym.toChars());
-
-        if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
-            ti.printInstantiationTrace(Classification.deprecation);
-
-        return true;
-    }
-    return false;
-}
-
-/**************************************
- * Check and set 'att' if 't' is a recursive 'alias this' type
- *
- * The goal is to prevent endless loops when there is a cycle in the alias this chain.
- * Since there is no multiple `alias this`, the chain either ends in a leaf,
- * or it loops back on itself as some point.
- *
- * Example: S0 -> (S1 -> S2 -> S3 -> S1)
- *
- * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
- * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
- * this still returns `false`, but `att1` is set to `S1`.
- * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
- * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
- *
- * Params:
- *   att = type reference used to detect recursion. Should be initialized to `null`.
- *   t   = type of 'alias this' rewrite to attempt
- *
- * Returns:
- *   `false` if the rewrite is safe, `true` if it would loop back around
- */
-bool isRecursiveAliasThis(ref Type att, Type t)
-{
-    //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
-    auto tb = t.toBasetype();
-    if (att && tb.equivalent(att))
-        return true;
-    else if (!att && tb.checkAliasThisRec())
-        att = tb;
-    return false;
-}
diff --git a/gcc/d/dmd/astcodegen.d b/gcc/d/dmd/astcodegen.d
index d40f836faae..f17907719a7 100644
--- a/gcc/d/dmd/astcodegen.d
+++ b/gcc/d/dmd/astcodegen.d
@@ -97,6 +97,6 @@  struct ASTCodegen
     alias isExpression              = dmd.dtemplate.isExpression;
     alias isTuple                   = dmd.dtemplate.isTuple;
 
-    alias IgnoreErrors              = dmd.dsymbol.IgnoreErrors;
+    alias SearchOpt                 = dmd.dsymbol.SearchOpt;
     alias PASS                      = dmd.dsymbol.PASS;
 }
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index faf04890e8e..cc6ef9c431b 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -123,19 +123,6 @@  extern (C++) abstract class AttribDeclaration : Dsymbol
         return sc;
     }
 
-    override void importAll(Scope* sc)
-    {
-        Dsymbols* d = include(sc);
-        //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
-        if (d)
-        {
-            Scope* sc2 = newScope(sc);
-            d.foreachDsymbol( s => s.importAll(sc2) );
-            if (sc2 != sc)
-                sc2.pop();
-        }
-    }
-
     override void addComment(const(char)* comment)
     {
         //printf("AttribDeclaration::addComment %s\n", comment);
@@ -156,11 +143,6 @@  extern (C++) abstract class AttribDeclaration : Dsymbol
         return Dsymbol.oneMembers(d, ps, ident);
     }
 
-    override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
-    }
-
     override final bool hasPointers()
     {
         return include(null).foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
@@ -675,81 +657,6 @@  extern (C++) final class AnonDeclaration : AttribDeclaration
         return new AnonDeclaration(loc, isunion, Dsymbol.arraySyntaxCopy(decl));
     }
 
-    override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", this);
-        if (decl)
-        {
-            /* This works by treating an AnonDeclaration as an aggregate 'member',
-             * so in order to place that member we need to compute the member's
-             * size and alignment.
-             */
-            size_t fieldstart = ad.fields.length;
-
-            /* Hackishly hijack ad's structsize and alignsize fields
-             * for use in our fake anon aggregate member.
-             */
-            uint savestructsize = ad.structsize;
-            uint savealignsize = ad.alignsize;
-            ad.structsize = 0;
-            ad.alignsize = 0;
-
-            FieldState fs;
-            decl.foreachDsymbol( (s)
-            {
-                s.setFieldOffset(ad, fs, this.isunion);
-                if (this.isunion)
-                    fs.offset = 0;
-            });
-
-            /* https://issues.dlang.org/show_bug.cgi?id=13613
-             * If the fields in this.members had been already
-             * added in ad.fields, just update *poffset for the subsequent
-             * field offset calculation.
-             */
-            if (fieldstart == ad.fields.length)
-            {
-                ad.structsize = savestructsize;
-                ad.alignsize = savealignsize;
-                fieldState.offset = ad.structsize;
-                return;
-            }
-
-            anonstructsize = ad.structsize;
-            anonalignsize = ad.alignsize;
-            ad.structsize = savestructsize;
-            ad.alignsize = savealignsize;
-
-            // 0 sized structs are set to 1 byte
-            if (anonstructsize == 0)
-            {
-                anonstructsize = 1;
-                anonalignsize = 1;
-            }
-
-            assert(_scope);
-            auto alignment = _scope.alignment();
-
-            /* Given the anon 'member's size and alignment,
-             * go ahead and place it.
-             */
-            anonoffset = placeField(
-                fieldState.offset,
-                anonstructsize, anonalignsize, alignment,
-                ad.structsize, ad.alignsize,
-                isunion);
-
-            // Add to the anon fields the base offset of this anonymous aggregate
-            //printf("anon fields, anonoffset = %d\n", anonoffset);
-            foreach (const i; fieldstart .. ad.fields.length)
-            {
-                VarDeclaration v = ad.fields[i];
-                //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
-                v.offset += anonoffset;
-            }
-        }
-    }
-
     override const(char)* kind() const
     {
         return (isunion ? "anonymous union" : "anonymous struct");
@@ -943,11 +850,6 @@  extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
         }
     }
 
-    override void importAll(Scope* sc)
-    {
-        // do not evaluate condition before semantic pass
-    }
-
     override const(char)* kind() const
     {
         return "static if";
@@ -1057,11 +959,6 @@  extern (C++) final class StaticForeachDeclaration : AttribDeclaration
         // change this to give semantics to documentation comments on static foreach declarations
     }
 
-    override void importAll(Scope* sc)
-    {
-        // do not evaluate aggregate before semantic pass
-    }
-
     override const(char)* kind() const
     {
         return "static foreach";
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index 98c5e521977..35628e26105 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -26,11 +26,9 @@  public:
 
     virtual Dsymbols *include(Scope *sc);
     virtual Scope *newScope(Scope *sc);
-    void importAll(Scope *sc) override;
     void addComment(const utf8_t *comment) override;
     const char *kind() const override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
     bool hasPointers() override final;
     bool hasStaticCtorOrDtor() override final;
     void checkCtorConstInit() override final;
@@ -132,7 +130,6 @@  public:
     unsigned anonalignsize;     // size of anonymous struct for alignment purposes
 
     AnonDeclaration *syntaxCopy(Dsymbol *s) override;
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
     const char *kind() const override;
     AnonDeclaration *isAnonDeclaration() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
@@ -171,7 +168,6 @@  public:
 
     StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
     Dsymbols *include(Scope *sc) override;
-    void importAll(Scope *sc) override;
     StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
@@ -190,7 +186,6 @@  public:
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
     Dsymbols *include(Scope *sc) override;
     void addComment(const utf8_t *comment) override;
-    void importAll(Scope *sc) override;
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
 };
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 89a594823ae..4c0b96a4c8c 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -247,6 +247,8 @@  final class CParser(AST) : Parser!AST
             break;
 
         case TOK.charLiteral:
+        case TOK.wcharLiteral:
+        case TOK.dcharLiteral:
         case TOK.int32Literal:
         case TOK.uns32Literal:
         case TOK.int64Literal:
@@ -725,6 +727,12 @@  final class CParser(AST) : Parser!AST
             nextToken();
             break;
 
+        case TOK.wcharLiteral:
+            e = new AST.IntegerExp(loc, token.intvalue, AST.Type.tuns16);
+            nextToken();
+            break;
+
+        case TOK.dcharLiteral:
         case TOK.uns32Literal:
             e = new AST.IntegerExp(loc, token.unsvalue, AST.Type.tuns32);
             nextToken();
@@ -1899,6 +1907,7 @@  final class CParser(AST) : Parser!AST
                 }
 
                 bool isalias = true;
+                Identifier idt;
                 if (auto ts = dt.isTypeStruct())
                 {
                     if (ts.sym.isAnonymous())
@@ -1908,6 +1917,7 @@  final class CParser(AST) : Parser!AST
                         ts.sym.ident = id;
                         isalias = false;
                     }
+                    idt = ts.sym.ident;
                 }
                 else if (auto te = dt.isTypeEnum())
                 {
@@ -1917,6 +1927,7 @@  final class CParser(AST) : Parser!AST
                         te.sym.ident = id;
                         isalias = false;
                     }
+                    idt = te.sym.ident;
                 }
                 else if (auto tt = dt.isTypeTag())
                 {
@@ -1930,11 +1941,13 @@  final class CParser(AST) : Parser!AST
                         Specifier spec;
                         declareTag(tt, spec);
                     }
+                    idt = tt.id;
                 }
                 if (isalias)
                 {
                     auto ad = new AST.AliasDeclaration(token.loc, id, dt);
-                    ad.adFlags |= ad.hidden; // do not print when generating .di files
+                    if (id == idt)
+                        ad.adFlags |= ad.hidden; // do not print when generating .di files
                     s = ad;
                 }
 
@@ -4272,6 +4285,7 @@  final class CParser(AST) : Parser!AST
                 case TOK.rightParenthesis:
                 case TOK.rightBracket:
                 case TOK.endOfFile:
+                case TOK.endOfLine:
                     if (!any)
                         return false;
                     break;
@@ -4940,6 +4954,8 @@  final class CParser(AST) : Parser!AST
         {
             case TOK.identifier:
             case TOK.charLiteral:
+            case TOK.wcharLiteral:
+            case TOK.dcharLiteral:
             case TOK.int32Literal:
             case TOK.uns32Literal:
             case TOK.int64Literal:
@@ -5794,6 +5810,9 @@  final class CParser(AST) : Parser!AST
         buf.writeByte(0);
         auto slice = buf.peekChars()[0 .. length];
         resetDefineLines(slice);                // reset lexer
+        auto save = eSink;
+        auto eLatch = new ErrorSinkLatch();
+        eSink = eLatch;
 
         const(char)* endp = &slice[length - 7];
 
@@ -5801,40 +5820,40 @@  final class CParser(AST) : Parser!AST
                                     // indexed by Identifier, returns index into symbols[]
                                     // The memory for this is leaked
 
-        void addVar(AST.VarDeclaration v)
+        void addVar(AST.Dsymbol s)
         {
-            //printf("addVar() %s\n", v.toChars());
-            v.isCmacro(true);           // mark it as coming from a C #define
+            //printf("addVar() %s\n", s.toChars());
+            if (auto v = s.isVarDeclaration())
+                v.isCmacro(true);       // mark it as coming from a C #define
             /* If it's already defined, replace the earlier
              * definition
              */
-            if (size_t* pd = cast(void*)v.ident in defineTab)
+            if (size_t* pd = cast(void*)s.ident in defineTab)
             {
                 //printf("replacing %s\n", v.toChars());
-                (*symbols)[*pd] = v;
+                (*symbols)[*pd] = s;
                 return;
             }
-            defineTab[cast(void*)v.ident] = symbols.length;
-            symbols.push(v);
+            defineTab[cast(void*)s.ident] = symbols.length;
+            symbols.push(s);
         }
 
-        Token n;
-
         while (p < endp)
         {
             if (p[0 .. 7] == "#define")
             {
                 p += 7;
-                scan(&n);
-                //printf("%s\n", n.toChars());
-                if (n.value == TOK.identifier)
+                nextToken();
+                //printf("define %s\n", token.toChars());
+                if (token.value == TOK.identifier)
                 {
-                    auto id = n.ident;
-                    scan(&n);
+                    auto id = token.ident;
+                    const params = *p == '(';
+                    nextToken();
 
                     AST.Type t;
 
-                    switch (n.value)
+                    switch (token.value)
                     {
                         case TOK.endOfLine:     // #define identifier
                             nextDefineLine();
@@ -5842,14 +5861,16 @@  final class CParser(AST) : Parser!AST
 
                         case TOK.int32Literal:
                         case TOK.charLiteral:       t = AST.Type.tint32;    goto Linteger;
+                        case TOK.wcharLiteral:      t = AST.Type.tuns16;    goto Linteger;
+                        case TOK.dcharLiteral:
                         case TOK.uns32Literal:      t = AST.Type.tuns32;    goto Linteger;
                         case TOK.int64Literal:      t = AST.Type.tint64;    goto Linteger;
                         case TOK.uns64Literal:      t = AST.Type.tuns64;    goto Linteger;
 
                         Linteger:
-                            const intvalue = n.intvalue;
-                            scan(&n);
-                            if (n.value == TOK.endOfLine)
+                            const intvalue = token.intvalue;
+                            nextToken();
+                            if (token.value == TOK.endOfLine)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = intvalue;
@@ -5870,9 +5891,9 @@  final class CParser(AST) : Parser!AST
                         case TOK.imaginary80Literal:  t = AST.Type.timaginary80; goto Lfloat;
 
                         Lfloat:
-                            const floatvalue = n.floatvalue;
-                            scan(&n);
-                            if (n.value == TOK.endOfLine)
+                            const floatvalue = token.floatvalue;
+                            nextToken();
+                            if (token.value == TOK.endOfLine)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = floatvalue;
@@ -5886,11 +5907,11 @@  final class CParser(AST) : Parser!AST
                             break;
 
                         case TOK.string_:
-                            const str = n.ustring;
-                            const len = n.len;
-                            const postfix = n.postfix;
-                            scan(&n);
-                            if (n.value == TOK.endOfLine)
+                            const str = token.ustring;
+                            const len = token.len;
+                            const postfix = token.postfix;
+                            nextToken();
+                            if (token.value == TOK.endOfLine)
                             {
                                 /* Declare manifest constant:
                                  *  enum id = "string";
@@ -5903,6 +5924,39 @@  final class CParser(AST) : Parser!AST
                             }
                             break;
 
+                        case TOK.leftParenthesis:
+                            /* Look for:
+                             *  #define ID ( expression )
+                             * and rewrite it to a template function:
+                             *  auto ID()() { return expression; }
+                             */
+                            if (params)
+                                break;                  // no parameters
+                            nextToken();
+                            eLatch.sawErrors = false;
+                            auto exp = cparseExpression();
+                            if (eLatch.sawErrors)   // parsing errors
+                                break;              // abandon this #define
+                            if (token.value != TOK.rightParenthesis)
+                                break;
+                            nextToken();
+                            if (token.value != TOK.endOfLine)
+                                break;
+                            auto ret = new AST.ReturnStatement(exp.loc, exp);
+                            auto parameterList = AST.ParameterList(new AST.Parameters(), VarArg.none, 0);
+                            StorageClass stc = STC.auto_;
+                            auto tf = new AST.TypeFunction(parameterList, null, LINK.d, stc);
+                            auto fd = new AST.FuncDeclaration(exp.loc, exp.loc, id, stc, tf, 0);
+                            fd.fbody = ret;
+                            AST.Dsymbols* decldefs = new AST.Dsymbols();
+                            decldefs.push(fd);
+                            AST.TemplateParameters* tpl = new AST.TemplateParameters();
+                            AST.Expression constraint = null;
+                            auto tempdecl = new AST.TemplateDeclaration(exp.loc, id, tpl, constraint, decldefs, false);
+                            addVar(tempdecl);
+                            nextDefineLine();
+                            continue;
+
                         default:
                             break;
                     }
@@ -5911,8 +5965,8 @@  final class CParser(AST) : Parser!AST
             }
             else
             {
-                scan(&n);
-                if (n.value != TOK.endOfLine)
+                scan(&token);
+                if (token.value != TOK.endOfLine)
                 {
                     skipToNextLine();
                 }
@@ -5920,6 +5974,7 @@  final class CParser(AST) : Parser!AST
             nextDefineLine();
         }
 
+        eSink = save;
         defines = buf;
     }
 
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index 43efc05b5d3..993bab023f9 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -636,8 +636,11 @@  bool isSafePointerCast(Type srcPointee, Type destPointee)
 
     // It's OK if function pointers differ only in safe/pure/nothrow
     if (srcPointee.ty == Tfunction && destPointee.ty == Tfunction)
+    {
+        import dmd.typesem : covariant;
         return srcPointee.covariant(destPointee) == Covariant.yes ||
             destPointee.covariant(srcPointee) == Covariant.yes;
+    }
     // it's OK to cast to void*
     if (destPointee.ty == Tvoid)
         return true;
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index bb86b080be6..cfa374c970b 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -24,6 +24,7 @@  import dmd.dinterpret;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.escape;
 import dmd.expression;
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index 72b85cfc64e..e066d877e8a 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -594,7 +594,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
         fieldState.offset = structsize;
         foreach (s; *members)
         {
-            s.setFieldOffset(this, fieldState, false);
+            s.setFieldOffset(this, &fieldState, false);
         }
 
         sizeok = Sizeok.done;
@@ -614,7 +614,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
     final bool isFuncHidden(FuncDeclaration fd)
     {
         //printf("ClassDeclaration.isFuncHidden(class = %s, fd = %s)\n", toChars(), fd.toPrettyChars());
-        Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
+        Dsymbol s = this.search(Loc.initial, fd.ident, SearchOpt.ignoreAmbiguous | SearchOpt.ignoreErrors);
         if (!s)
         {
             //printf("not found\n");
@@ -670,6 +670,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
 
         void searchVtbl(ref Dsymbols vtbl)
         {
+            import dmd.typesem : covariant;
             bool seenInterfaceVirtual;
             foreach (s; vtbl)
             {
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 0e125fdd001..bdc91f4f1f2 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -1214,88 +1214,6 @@  extern (C++) class VarDeclaration : Declaration
         return v;
     }
 
-    override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
-
-        if (aliasTuple)
-        {
-            // If this variable was really a tuple, set the offsets for the tuple fields
-            aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
-            return;
-        }
-
-        if (!isField())
-            return;
-        assert(!(storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
-
-        //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
-
-        /* Fields that are tuples appear both as part of TupleDeclarations and
-         * as members. That means ignore them if they are already a field.
-         */
-        if (offset)
-        {
-            // already a field
-            fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
-            return;
-        }
-        for (size_t i = 0; i < ad.fields.length; i++)
-        {
-            if (ad.fields[i] == this)
-            {
-                // already a field
-                fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
-                return;
-            }
-        }
-
-        // Check for forward referenced types which will fail the size() call
-        Type t = type.toBasetype();
-        if (storage_class & STC.ref_)
-        {
-            // References are the size of a pointer
-            t = Type.tvoidptr;
-        }
-        Type tv = t.baseElemOf();
-        if (tv.ty == Tstruct)
-        {
-            auto ts = cast(TypeStruct)tv;
-            assert(ts.sym != ad);   // already checked in ad.determineFields()
-            if (!ts.sym.determineSize(loc))
-            {
-                type = Type.terror;
-                errors = true;
-                return;
-            }
-        }
-
-        // List in ad.fields. Even if the type is error, it's necessary to avoid
-        // pointless error diagnostic "more initializers than fields" on struct literal.
-        ad.fields.push(this);
-
-        if (t.ty == Terror)
-            return;
-
-        /* If coming after a bit field in progress,
-         * advance past the field
-         */
-        fieldState.inFlight = false;
-
-        const sz = t.size(loc);
-        assert(sz != SIZE_INVALID && sz < uint.max);
-        uint memsize = cast(uint)sz;                // size of member
-        uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
-        offset = placeField(
-            fieldState.offset,
-            memsize, memalignsize, alignment,
-            ad.structsize, ad.alignsize,
-            isunion);
-
-        //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
-        //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
-    }
-
     override const(char)* kind() const
     {
         return "variable";
@@ -1803,211 +1721,6 @@  extern (C++) class BitFieldDeclaration : VarDeclaration
                            :  (1L << (width - 1)) - 1);
         return v;
     }
-
-    override final void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        enum log = false;
-        static if (log)
-        {
-            printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), toChars());
-            void print(const ref FieldState fieldState)
-            {
-                fieldState.print();
-                printf("          fieldWidth   = %d bits\n",    fieldWidth);
-            }
-            print(fieldState);
-        }
-
-        Type t = type.toBasetype();
-        const bool anon = isAnonymous();
-
-        // List in ad.fields. Even if the type is error, it's necessary to avoid
-        // pointless error diagnostic "more initializers than fields" on struct literal.
-        if (!anon)
-            ad.fields.push(this);
-
-        if (t.ty == Terror)
-            return;
-
-        const sz = t.size(loc);
-        assert(sz != SIZE_INVALID && sz < uint.max);
-        uint memsize = cast(uint)sz;                // size of member
-        uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
-        if (log) printf("          memsize: %u memalignsize: %u\n", memsize, memalignsize);
-
-        if (fieldWidth == 0 && !anon)
-            error(loc, "named bit fields cannot have 0 width");
-        if (fieldWidth > memsize * 8)
-            error(loc, "bit field width %d is larger than type", fieldWidth);
-
-        const style = target.c.bitFieldStyle;
-
-        void startNewField()
-        {
-            if (log) printf("startNewField()\n");
-            uint alignsize;
-            if (style == TargetC.BitFieldStyle.Gcc_Clang)
-            {
-                if (fieldWidth > 32)
-                    alignsize = memalignsize;
-                else if (fieldWidth > 16)
-                    alignsize = 4;
-                else if (fieldWidth > 8)
-                    alignsize = 2;
-                else
-                    alignsize = 1;
-            }
-            else
-                alignsize = memsize; // not memalignsize
-
-            uint dummy;
-            offset = placeField(
-                fieldState.offset,
-                memsize, alignsize, alignment,
-                ad.structsize,
-                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
-                isunion);
-
-            fieldState.inFlight = true;
-            fieldState.fieldOffset = offset;
-            fieldState.bitOffset = 0;
-            fieldState.fieldSize = memsize;
-        }
-
-        if (style == TargetC.BitFieldStyle.Gcc_Clang)
-        {
-            if (fieldWidth == 0)
-            {
-                if (!isunion)
-                {
-                    // Use type of zero width field to align to next field
-                    fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
-                    ad.structsize = fieldState.offset;
-                }
-
-                fieldState.inFlight = false;
-                return;
-            }
-
-            if (ad.alignsize == 0)
-                ad.alignsize = 1;
-            if (!anon &&
-                  ad.alignsize < memalignsize)
-                ad.alignsize = memalignsize;
-        }
-        else if (style == TargetC.BitFieldStyle.MS)
-        {
-            if (ad.alignsize == 0)
-                ad.alignsize = 1;
-            if (fieldWidth == 0)
-            {
-                if (fieldState.inFlight && !isunion)
-                {
-                    // documentation says align to next int
-                    //const alsz = cast(uint)Type.tint32.size();
-                    const alsz = memsize; // but it really does this
-                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
-                    ad.structsize = fieldState.offset;
-                }
-
-                fieldState.inFlight = false;
-                return;
-            }
-        }
-        else if (style == TargetC.BitFieldStyle.DM)
-        {
-            if (anon && fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
-                return;  // this probably should be a bug in DMC
-            if (ad.alignsize == 0)
-                ad.alignsize = 1;
-            if (fieldWidth == 0)
-            {
-                if (fieldState.inFlight && !isunion)
-                {
-                    const alsz = memsize;
-                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
-                    ad.structsize = fieldState.offset;
-                }
-
-                fieldState.inFlight = false;
-                return;
-            }
-        }
-
-        if (!fieldState.inFlight)
-        {
-            //printf("not in flight\n");
-            startNewField();
-        }
-        else if (style == TargetC.BitFieldStyle.Gcc_Clang)
-        {
-            // If the bit-field spans more units of alignment than its type,
-            // start a new field at the next alignment boundary.
-            if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
-                fieldState.bitOffset + fieldWidth > memalignsize * 8)
-            {
-                if (log) printf("more units of alignment than its type\n");
-                startNewField();        // the bit field is full
-            }
-            else
-            {
-                // if alignment boundary is crossed
-                uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
-                uint end   = start + fieldWidth;
-                //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
-                if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
-                {
-                    if (log) printf("alignment is crossed\n");
-                    startNewField();
-                }
-            }
-        }
-        else if (style == TargetC.BitFieldStyle.DM ||
-                 style == TargetC.BitFieldStyle.MS)
-        {
-            if (memsize != fieldState.fieldSize ||
-                fieldState.bitOffset + fieldWidth > fieldState.fieldSize * 8)
-            {
-                //printf("new field\n");
-                startNewField();
-            }
-        }
-        else
-            assert(0);
-
-        offset = fieldState.fieldOffset;
-        bitOffset = fieldState.bitOffset;
-
-        const pastField = bitOffset + fieldWidth;
-        if (style == TargetC.BitFieldStyle.Gcc_Clang)
-        {
-            auto size = (pastField + 7) / 8;
-            fieldState.fieldSize = size;
-            //printf(" offset: %d, size: %d\n", offset, size);
-            if (isunion)
-            {
-                const newstructsize = offset + size;
-                if (newstructsize > ad.structsize)
-                    ad.structsize = newstructsize;
-            }
-            else
-                ad.structsize = offset + size;
-        }
-        else
-            fieldState.fieldSize = memsize;
-        //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
-        //print(fieldState);
-
-        if (!isunion)
-        {
-            fieldState.offset = offset + fieldState.fieldSize;
-            fieldState.bitOffset = pastField;
-        }
-
-        //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
-        //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
-        //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
-    }
 }
 
 /***********************************************************
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index a65fb4467e5..adbc26bf570 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -281,7 +281,6 @@  public:
     bool systemInferred(bool v);
     static VarDeclaration *create(const Loc &loc, Type *t, Identifier *id, Initializer *init, StorageClass storage_class = STCundefined);
     VarDeclaration *syntaxCopy(Dsymbol *) override;
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override final;
     const char *kind() const override;
     AggregateDeclaration *isThis() override final;
     bool needThis() override final;
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index 5c01a9f5889..51b9220c185 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -222,48 +222,6 @@  extern (C++) final class Import : Dsymbol
         return global.errors != errors;
     }
 
-    override void importAll(Scope* sc)
-    {
-        if (mod) return; // Already done
-
-        /*
-         * https://issues.dlang.org/show_bug.cgi?id=15525
-         *
-         * Loading the import has failed,
-         * most likely because of parsing errors.
-         * Therefore we cannot trust the resulting AST.
-         */
-        if (load(sc))
-        {
-            // https://issues.dlang.org/show_bug.cgi?id=23873
-            // For imports that are not at module or function level,
-            // e.g. aggregate level, the import symbol is added to the
-            // symbol table and later semantic is performed on it.
-            // This leads to semantic analysis on an malformed AST
-            // which causes all kinds of segfaults.
-            // The fix is to note that the module has errors and avoid
-            // semantic analysis on it.
-            if(mod)
-                mod.errors = true;
-            return;
-        }
-
-        if (!mod) return; // Failed
-
-        if (sc.stc & STC.static_)
-            isstatic = true;
-        mod.importAll(null);
-        mod.checkImportDeprecation(loc, sc);
-        if (sc.explicitVisibility)
-            visibility = sc.visibility;
-        if (!isstatic && !aliasId && !names.length)
-            sc.scopesym.importScope(mod, visibility);
-        // Enable access to pkgs/mod as soon as posible, because compiler
-        // can traverse them before the import gets semantic (Issue: 21501)
-        if (!aliasId && !names.length)
-            addPackageAccess(sc.scopesym);
-    }
-
     /*******************************
      * Mark the imported packages as accessible from the current
      * scope. This access check is necessary when using FQN b/c
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index d096e437cf9..6c9e90a2c8f 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -401,7 +401,7 @@  extern (C++) final class Module : Package
 
     Identifier searchCacheIdent;
     Dsymbol searchCacheSymbol;  // cached value of search
-    int searchCacheFlags;       // cached flags
+    SearchOptFlags searchCacheFlags;       // cached flags
     bool insearch;
 
     /**
@@ -921,70 +921,6 @@  extern (C++) final class Module : Package
         return this;
     }
 
-    override void importAll(Scope* prevsc)
-    {
-        //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", this, toChars(), parent);
-        if (_scope)
-            return; // already done
-        if (filetype == FileType.ddoc)
-        {
-            error(loc, "%s `%s` is a Ddoc file, cannot import it", kind, toPrettyChars);
-            return;
-        }
-
-        /* Note that modules get their own scope, from scratch.
-         * This is so regardless of where in the syntax a module
-         * gets imported, it is unaffected by context.
-         * Ignore prevsc.
-         */
-        Scope* sc = Scope.createGlobal(this, global.errorSink); // create root scope
-
-        if (md && md.msg)
-            md.msg = semanticString(sc, md.msg, "deprecation message");
-
-        // Add import of "object", even for the "object" module.
-        // If it isn't there, some compiler rewrites, like
-        //    classinst == classinst -> .object.opEquals(classinst, classinst)
-        // would fail inside object.d.
-        if (filetype != FileType.c &&
-            (members.length == 0 ||
-             (*members)[0].ident != Id.object ||
-             (*members)[0].isImport() is null))
-        {
-            auto im = new Import(Loc.initial, null, Id.object, null, 0);
-            members.shift(im);
-        }
-        if (!symtab)
-        {
-            // Add all symbols into module's symbol table
-            symtab = new DsymbolTable();
-            for (size_t i = 0; i < members.length; i++)
-            {
-                Dsymbol s = (*members)[i];
-                s.addMember(sc, sc.scopesym);
-            }
-        }
-        // anything else should be run after addMember, so version/debug symbols are defined
-        /* Set scope for the symbols so that if we forward reference
-         * a symbol, it can possibly be resolved on the spot.
-         * If this works out well, it can be extended to all modules
-         * before any semantic() on any of them.
-         */
-        this.setScope(sc); // remember module scope for semantic
-        for (size_t i = 0; i < members.length; i++)
-        {
-            Dsymbol s = (*members)[i];
-            s.setScope(sc);
-        }
-        for (size_t i = 0; i < members.length; i++)
-        {
-            Dsymbol s = (*members)[i];
-            s.importAll(sc);
-        }
-        sc = sc.pop();
-        sc.pop(); // 2 pops because Scope.createGlobal() created 2
-    }
-
     /**********************************
      * Determine if we need to generate an instance of ModuleInfo
      * for this Module.
@@ -1021,14 +957,14 @@  extern (C++) final class Module : Package
         }
     }
 
-    override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
+    override bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all)
     {
         if (insearch) // don't follow import cycles
             return false;
         insearch = true;
         scope (exit)
             insearch = false;
-        if (flags & IgnorePrivateImports)
+        if (flags & SearchOpt.ignorePrivateImports)
             visibility = Visibility(Visibility.Kind.public_); // only consider public imports
         return super.isPackageAccessible(p, visibility);
     }
@@ -1384,7 +1320,53 @@  extern (C++) void getLocalClasses(Module mod, ref ClassDeclarations aclasses)
         return 0;
     }
 
-    ScopeDsymbol._foreach(null, mod.members, &pushAddClassDg);
+    _foreach(null, mod.members, &pushAddClassDg);
+}
+
+
+alias ForeachDg = int delegate(size_t idx, Dsymbol s);
+
+/***************************************
+ * Expands attribute declarations in members in depth first
+ * order. Calls dg(size_t symidx, Dsymbol *sym) for each
+ * member.
+ * If dg returns !=0, stops and returns that value else returns 0.
+ * Use this function to avoid the O(N + N^2/2) complexity of
+ * calculating dim and calling N times getNth.
+ * Returns:
+ *  last value returned by dg()
+ */
+int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
+{
+    assert(dg);
+    if (!members)
+        return 0;
+    size_t n = pn ? *pn : 0; // take over index
+    int result = 0;
+    foreach (size_t i; 0 .. members.length)
+    {
+        import dmd.attrib : AttribDeclaration;
+        import dmd.dtemplate : TemplateMixin;
+
+        Dsymbol s = (*members)[i];
+        if (AttribDeclaration a = s.isAttribDeclaration())
+            result = _foreach(sc, a.include(sc), dg, &n);
+        else if (TemplateMixin tm = s.isTemplateMixin())
+            result = _foreach(sc, tm.members, dg, &n);
+        else if (s.isTemplateInstance())
+        {
+        }
+        else if (s.isUnitTestDeclaration())
+        {
+        }
+        else
+            result = dg(n++, s);
+        if (result)
+            break;
+    }
+    if (pn)
+        *pn = n; // update index
+    return result;
 }
 
 /**
diff --git a/gcc/d/dmd/doc.d b/gcc/d/dmd/doc.d
index 5488d5a0008..03848c0274b 100644
--- a/gcc/d/dmd/doc.d
+++ b/gcc/d/dmd/doc.d
@@ -748,7 +748,8 @@  void emitAnchor(ref OutBuffer buf, Dsymbol s, Scope* sc, bool forHeader = false)
                 auto a = imp.aliases[i];
                 auto id = a ? a : imp.names[i];
                 auto loc = Loc.init;
-                if (auto symFromId = sc.search(loc, id, null))
+                Dsymbol pscopesym;
+                if (auto symFromId = sc.search(loc, id, pscopesym))
                 {
                     emitAnchor(buf, symFromId, sc, forHeader);
                 }
@@ -3636,11 +3637,12 @@  struct MarkdownLinkReferences
         if (id)
         {
             auto loc = Loc();
-            auto symbol = _scope.search(loc, id, null, IgnoreErrors);
+            Dsymbol pscopesym;
+            auto symbol = _scope.search(loc, id, pscopesym, SearchOpt.ignoreErrors);
             for (size_t i = 1; symbol && i < ids.length; ++i)
             {
                 id = Identifier.lookup(ids[i].ptr, ids[i].length);
-                symbol = id !is null ? symbol.search(loc, id, IgnoreErrors) : null;
+                symbol = id !is null ? symbol.search(loc, id, SearchOpt.ignoreErrors) : null;
             }
             if (symbol)
                 link = MarkdownLink(createHref(symbol), null, name, symbol);
@@ -4997,7 +4999,8 @@  void highlightCode(Scope* sc, Dsymbol s, ref OutBuffer buf, size_t offset)
             auto a = imp.aliases[i];
             auto id = a ? a : imp.names[i];
             auto loc = Loc.init;
-            if (auto symFromId = sc.search(loc, id, null))
+            Dsymbol pscopesym;
+            if (auto symFromId = sc.search(loc, id, pscopesym))
             {
                 highlightCode(sc, symFromId, buf, offset);
             }
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index d68bcdaad40..cd177a66f50 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -344,13 +344,13 @@  extern (C++) struct Scope
      * Params:
      *  loc = location to use for error messages
      *  ident = name to look up
-     *  pscopesym = if supplied and name is found, set to scope that ident was found in
+     *  pscopesym = if supplied and name is found, set to scope that ident was found in, otherwise set to null
      *  flags = modify search based on flags
      *
      * Returns:
      *  symbol if found, null if not
      */
-    extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
+    extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, out Dsymbol pscopesym, SearchOptFlags flags = SearchOpt.all)
     {
         version (LOGSEARCH)
         {
@@ -371,7 +371,7 @@  extern (C++) struct Scope
         }
 
         // This function is called only for unqualified lookup
-        assert(!(flags & (SearchLocalsOnly | SearchImportsOnly)));
+        assert(!(flags & (SearchOpt.localsOnly | SearchOpt.importsOnly)));
 
         /* If ident is "start at module scope", only look at module scope
          */
@@ -386,15 +386,14 @@  extern (C++) struct Scope
                 if (Dsymbol s = sc.scopesym.isModule())
                 {
                     //printMsg("\tfound", s);
-                    if (pscopesym)
-                        *pscopesym = sc.scopesym;
+                    pscopesym = sc.scopesym;
                     return s;
                 }
             }
             return null;
         }
 
-        Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, int flags, Expression* exp)
+        Dsymbol checkAliasThis(AggregateDeclaration ad, Identifier ident, SearchOptFlags flags, Expression* exp)
         {
             import dmd.mtype;
             if (!ad || !ad.aliasthis)
@@ -458,7 +457,7 @@  extern (C++) struct Scope
             return s;
         }
 
-        Dsymbol searchScopes(int flags)
+        Dsymbol searchScopes(SearchOptFlags flags)
         {
             for (Scope* sc = &this; sc; sc = sc.enclosing)
             {
@@ -468,13 +467,13 @@  extern (C++) struct Scope
                 //printf("\tlooking in scopesym '%s', kind = '%s', flags = x%x\n", sc.scopesym.toChars(), sc.scopesym.kind(), flags);
 
                 if (sc.scopesym.isModule())
-                    flags |= SearchUnqualifiedModule;        // tell Module.search() that SearchLocalsOnly is to be obeyed
+                    flags |= SearchOpt.unqualifiedModule;    // tell Module.search() that SearchOpt.localsOnly is to be obeyed
                 else if (sc.flags & SCOPE.Cfile && sc.scopesym.isStructDeclaration())
                     continue;                                // C doesn't have struct scope
 
                 if (Dsymbol s = sc.scopesym.search(loc, ident, flags))
                 {
-                    if (flags & TagNameSpace)
+                    if (flags & SearchOpt.tagNameSpace)
                     {
                         // ImportC: if symbol is not a tag, look for it in tag table
                         if (!s.isScopeDsymbol())
@@ -486,8 +485,7 @@  extern (C++) struct Scope
                         }
                     }
                     //printMsg("\tfound local", s);
-                    if (pscopesym)
-                        *pscopesym = sc.scopesym;
+                    pscopesym = sc.scopesym;
                     return s;
                 }
 
@@ -499,8 +497,7 @@  extern (C++) struct Scope
                     if (aliasSym)
                     {
                         //printf("found aliassym: %s\n", aliasSym.toChars());
-                        if (pscopesym)
-                            *pscopesym = new ExpressionDsymbol(exp);
+                        pscopesym = new ExpressionDsymbol(exp);
                         return aliasSym;
                     }
                 }
@@ -513,15 +510,15 @@  extern (C++) struct Scope
         }
 
         if (this.flags & SCOPE.ignoresymbolvisibility)
-            flags |= IgnoreSymbolVisibility;
+            flags |= SearchOpt.ignoreVisibility;
 
         // First look in local scopes
-        Dsymbol s = searchScopes(flags | SearchLocalsOnly);
+        Dsymbol s = searchScopes(flags | SearchOpt.localsOnly);
         version (LOGSEARCH) if (s) printMsg("-Scope.search() found local", s);
         if (!s)
         {
             // Second look in imported modules
-            s = searchScopes(flags | SearchImportsOnly);
+            s = searchScopes(flags | SearchOpt.importsOnly);
             version (LOGSEARCH) if (s) printMsg("-Scope.search() found import", s);
         }
         return s;
@@ -554,8 +551,8 @@  extern (C++) struct Scope
                 return null;
             Scope* sc = &this;
             Module.clearCache();
-            Dsymbol scopesym = null;
-            Dsymbol s = sc.search(Loc.initial, id, &scopesym, IgnoreErrors);
+            Dsymbol scopesym;
+            Dsymbol s = sc.search(Loc.initial, id, scopesym, SearchOpt.ignoreErrors);
             if (!s)
                 return null;
 
@@ -579,9 +576,9 @@  extern (C++) struct Scope
             return s;
         }
 
-        Dsymbol scopesym = null;
+        Dsymbol scopesym;
         // search for exact name first
-        if (auto s = search(Loc.initial, ident, &scopesym, IgnoreErrors))
+        if (auto s = search(Loc.initial, ident, scopesym, SearchOpt.ignoreErrors))
             return s;
         return speller!scope_search_fp(ident.toString());
     }
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index 36e847c3f88..0e0a1f52f88 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -289,7 +289,7 @@  extern (C++) class StructDeclaration : AggregateDeclaration
         for (size_t i = 0; i < members.length; i++)
         {
             Dsymbol s = (*members)[i];
-            s.setFieldOffset(this, fieldState, isunion);
+            s.setFieldOffset(this, &fieldState, isunion);
         }
         if (type.ty == Terror)
         {
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 8f5a292a284..6613c2bc5c2 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -203,20 +203,21 @@  enum PASS : ubyte
 }
 
 // Search options
-enum : int
+alias SearchOptFlags = uint;
+enum SearchOpt : SearchOptFlags
 {
-    IgnoreNone              = 0x00, // default
-    IgnorePrivateImports    = 0x01, // don't search private imports
-    IgnoreErrors            = 0x02, // don't give error messages
-    IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
-    SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
-    SearchImportsOnly       = 0x10, // only look in imports
-    SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
+    all                     = 0x00, // search for all symbols
+    ignorePrivateImports    = 0x01, // don't search private imports
+    ignoreErrors            = 0x02, // don't give error messages
+    ignoreAmbiguous         = 0x04, // return NULL if ambiguous
+    localsOnly              = 0x08, // only look at locals (don't search imports)
+    importsOnly             = 0x10, // only look in imports
+    unqualifiedModule       = 0x20, // the module scope search is unqualified,
                                     // meaning don't search imports in that scope,
                                     // because qualified module searches search
                                     // their imports
-    IgnoreSymbolVisibility  = 0x80, // also find private and package protected symbols
-    TagNameSpace            = 0x100, // search ImportC tag symbol table
+    tagNameSpace            = 0x40, // search ImportC tag symbol table
+    ignoreVisibility        = 0x80, // also find private and package protected symbols
 }
 
 /***********************************************************
@@ -712,10 +713,6 @@  extern (C++) class Dsymbol : ASTNode
         return toAlias();
     }
 
-    void importAll(Scope* sc)
-    {
-    }
-
     bool overloadInsert(Dsymbol s)
     {
         //printf("Dsymbol::overloadInsert('%s')\n", s.toChars());
@@ -922,10 +919,6 @@  extern (C++) class Dsymbol : ASTNode
         return true;
     }
 
-    void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-    }
-
     /*****************************************
      * Is Dsymbol a variable that contains pointers?
      */
@@ -1263,7 +1256,7 @@  public:
         (*pary)[p.tag] = true;
     }
 
-    bool isPackageAccessible(Package p, Visibility visibility, int flags = 0) nothrow
+    bool isPackageAccessible(Package p, Visibility visibility, SearchOptFlags flags = SearchOpt.all) nothrow
     {
         if (p.tag < accessiblePackages.length && accessiblePackages[p.tag] ||
             visibility.kind == Visibility.Kind.private_ && p.tag < privateAccessiblePackages.length && privateAccessiblePackages[p.tag])
@@ -1272,7 +1265,7 @@  public:
         {
             // only search visible scopes && imported modules should ignore private imports
             if (visibility.kind <= visibilities[i] &&
-                ss.isScopeDsymbol.isPackageAccessible(p, visibility, IgnorePrivateImports))
+                ss.isScopeDsymbol.isPackageAccessible(p, visibility, SearchOpt.ignorePrivateImports))
                 return true;
         }
         return false;
@@ -1371,48 +1364,6 @@  public:
         return false;
     }
 
-    extern (D) alias ForeachDg = int delegate(size_t idx, Dsymbol s);
-
-    /***************************************
-     * Expands attribute declarations in members in depth first
-     * order. Calls dg(size_t symidx, Dsymbol *sym) for each
-     * member.
-     * If dg returns !=0, stops and returns that value else returns 0.
-     * Use this function to avoid the O(N + N^2/2) complexity of
-     * calculating dim and calling N times getNth.
-     * Returns:
-     *  last value returned by dg()
-     */
-    extern (D) static int _foreach(Scope* sc, Dsymbols* members, scope ForeachDg dg, size_t* pn = null)
-    {
-        assert(dg);
-        if (!members)
-            return 0;
-        size_t n = pn ? *pn : 0; // take over index
-        int result = 0;
-        foreach (size_t i; 0 .. members.length)
-        {
-            Dsymbol s = (*members)[i];
-            if (AttribDeclaration a = s.isAttribDeclaration())
-                result = _foreach(sc, a.include(sc), dg, &n);
-            else if (TemplateMixin tm = s.isTemplateMixin())
-                result = _foreach(sc, tm.members, dg, &n);
-            else if (s.isTemplateInstance())
-            {
-            }
-            else if (s.isUnitTestDeclaration())
-            {
-            }
-            else
-                result = dg(n++, s);
-            if (result)
-                break;
-        }
-        if (pn)
-            *pn = n; // update index
-        return result;
-    }
-
     override final inout(ScopeDsymbol) isScopeDsymbol() inout
     {
         return this;
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 15c997027da..d029c00fc1c 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -147,20 +147,21 @@  enum
 
 /* Flags for symbol search
  */
-enum
+typedef uint SearchOptFlags;
+enum class SearchOpt : SearchOptFlags
 {
-    IgnoreNone              = 0x00, // default
-    IgnorePrivateImports    = 0x01, // don't search private imports
-    IgnoreErrors            = 0x02, // don't give error messages
-    IgnoreAmbiguous         = 0x04, // return NULL if ambiguous
-    SearchLocalsOnly        = 0x08, // only look at locals (don't search imports)
-    SearchImportsOnly       = 0x10, // only look in imports
-    SearchUnqualifiedModule = 0x20, // the module scope search is unqualified,
-                                    // meaning don't search imports in that scope,
-                                    // because qualified module searches search
-                                    // their imports
-    IgnoreSymbolVisibility  = 0x80,  // also find private and package protected symbols
-    TagNameSpace            = 0x100, // search ImportC tag symbol table
+    all                    = 0x00, // default
+    ignorePrivateImports   = 0x01, // don't search private imports
+    ignoreErrors           = 0x02, // don't give error messages
+    ignoreAmbiguous        = 0x04, // return NULL if ambiguous
+    localsOnly             = 0x08, // only look at locals (don't search imports)
+    importsOnly            = 0x10, // only look in imports
+    unqualifiedModule      = 0x20, // the module scope search is unqualified,
+                                   // meaning don't search imports in that scope,
+                                   // because qualified module searches search
+                                   // their imports
+    tagNameSpace           = 0x40, // search ImportC tag symbol table
+    ignoreVisibility       = 0x80, // also find private and package protected symbols
 };
 
 struct FieldState
@@ -227,7 +228,6 @@  public:
     virtual const char *kind() const;
     virtual Dsymbol *toAlias();                 // resolve real symbol
     virtual Dsymbol *toAlias2();
-    virtual void importAll(Scope *sc);
     virtual bool overloadInsert(Dsymbol *s);
     virtual uinteger_t size(const Loc &loc);
     virtual bool isforwardRef();
@@ -247,7 +247,6 @@  public:
     virtual Visibility visible();
     virtual Dsymbol *syntaxCopy(Dsymbol *s);    // copy only syntax trees
     virtual bool oneMember(Dsymbol **ps, Identifier *ident);
-    virtual void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
     virtual bool hasPointers();
     virtual bool hasStaticCtorOrDtor();
     virtual void addObjcSymbols(ClassDeclarations *, ClassDeclarations *) { }
@@ -336,7 +335,7 @@  private:
 public:
     ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
     virtual void importScope(Dsymbol *s, Visibility visibility);
-    virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
+    virtual bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
     bool isforwardRef() override final;
     static void multiplyDefined(const Loc &loc, Dsymbol *s1, Dsymbol *s2);
     const char *kind() const override;
@@ -427,6 +426,8 @@  public:
 };
 
 void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
-Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
+Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, SearchOptFlags flags = (SearchOptFlags)SearchOpt::localsOnly);
 bool checkDeprecated(Dsymbol *d, const Loc &loc, Scope *sc);
 void setScope(Dsymbol *d, Scope *sc);
+void importAll(Dsymbol *d, Scope *sc);
+void setFieldOffset(Dsymbol *d, AggregateDeclaration *ad, FieldState& fieldState, bool isunion);
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 060abfe1896..df0a9a536f4 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -246,6 +246,20 @@  bool checkDeprecated(Dsymbol d, const ref Loc loc, Scope* sc)
     return true;
 }
 
+/*********************************
+ * Check type to see if it is based on a deprecated symbol.
+ */
+private void checkDeprecated(Type type, const ref Loc loc, Scope* sc)
+{
+    if (Dsymbol s = type.toDsymbol(sc))
+    {
+        s.checkDeprecated(loc, sc);
+    }
+
+    if (auto tn = type.nextOf())
+        tn.checkDeprecated(loc, sc);
+}
+
 // Returns true if a contract can appear without a function body.
 package bool allowsContractWithoutBody(FuncDeclaration funcdecl)
 {
@@ -304,6 +318,128 @@  bool checkHasBothRvalueAndCpCtor(StructDeclaration sd, CtorDeclaration ctor, Tem
     return false;
 }
 
+/*************************************
+ * Find the `alias this` symbol of e's type.
+ * Params:
+ *      sc = context
+ *      e = expression forming the `this`
+ *      gag = do not print errors, return `null` instead
+ *      findOnly = don't do further processing like resolving properties,
+ *                 i.e. just return plain dotExp() result.
+ * Returns:
+ *      Expression that is `e.aliasthis`
+ */
+Expression resolveAliasThis(Scope* sc, Expression e, bool gag = false, bool findOnly = false)
+{
+    import dmd.typesem : dotExp;
+    for (AggregateDeclaration ad = isAggregate(e.type); ad;)
+    {
+        if (ad.aliasthis)
+        {
+            Loc loc = e.loc;
+            Type tthis = (e.op == EXP.type ? e.type : null);
+            const flags = cast(DotExpFlag) (DotExpFlag.noAliasThis | (gag * DotExpFlag.gag));
+            uint olderrors = gag ? global.startGagging() : 0;
+            e = dotExp(ad.type, sc, e, ad.aliasthis.ident, flags);
+            if (!e || findOnly)
+                return gag && global.endGagging(olderrors) ? null : e;
+
+            if (tthis && ad.aliasthis.sym.needThis())
+            {
+                if (auto ve = e.isVarExp())
+                {
+                    if (auto fd = ve.var.isFuncDeclaration())
+                    {
+                        // https://issues.dlang.org/show_bug.cgi?id=13009
+                        // Support better match for the overloaded alias this.
+                        bool hasOverloads;
+                        if (auto f = fd.overloadModMatch(loc, tthis, hasOverloads))
+                        {
+                            if (!hasOverloads)
+                                fd = f;     // use exact match
+                            e = new VarExp(loc, fd, hasOverloads);
+                            e.type = f.type;
+                            e = new CallExp(loc, e);
+                            goto L1;
+                        }
+                    }
+                }
+                /* non-@property function is not called inside typeof(),
+                 * so resolve it ahead.
+                 */
+                {
+                    int save = sc.intypeof;
+                    sc.intypeof = 1; // bypass "need this" error check
+                    e = resolveProperties(sc, e);
+                    sc.intypeof = save;
+                }
+            L1:
+                e = new TypeExp(loc, new TypeTypeof(loc, e));
+                e = e.expressionSemantic(sc);
+            }
+            e = resolveProperties(sc, e);
+            if (!gag)
+                ad.aliasthis.checkDeprecatedAliasThis(loc, sc);
+            else if (global.endGagging(olderrors))
+                e = null;
+        }
+
+        import dmd.dclass : ClassDeclaration;
+        auto cd = ad.isClassDeclaration();
+        if ((!e || !ad.aliasthis) && cd && cd.baseClass && cd.baseClass != ClassDeclaration.object)
+        {
+            ad = cd.baseClass;
+            continue;
+        }
+        break;
+    }
+    return e;
+}
+
+/**
+ * Check if an `alias this` is deprecated
+ *
+ * Usually one would use `expression.checkDeprecated(scope, aliasthis)` to
+ * check if `expression` uses a deprecated `aliasthis`, but this calls
+ * `toPrettyChars` which lead to the following message:
+ * "Deprecation: alias this `fullyqualified.aggregate.__anonymous` is deprecated"
+ *
+ * Params:
+ *   at  = The `AliasThis` object to check
+ *   loc = `Loc` of the expression triggering the access to `at`
+ *   sc  = `Scope` of the expression
+ *         (deprecations do not trigger in deprecated scopes)
+ *
+ * Returns:
+ *   Whether the alias this was reported as deprecated.
+ */
+private bool checkDeprecatedAliasThis(AliasThis at, const ref Loc loc, Scope* sc)
+{
+    if (global.params.useDeprecated != DiagnosticReporting.off
+        && at.isDeprecated() && !sc.isDeprecated())
+    {
+        const(char)* message = null;
+        for (Dsymbol p = at; p; p = p.parent)
+        {
+            message = p.depdecl ? p.depdecl.getMessage() : null;
+            if (message)
+                break;
+        }
+        if (message)
+            deprecation(loc, "`alias %s this` is deprecated - %s",
+                        at.sym.toChars(), message);
+        else
+            deprecation(loc, "`alias %s this` is deprecated",
+                        at.sym.toChars());
+
+        if (auto ti = sc.parent ? sc.parent.isInstantiated() : null)
+            ti.printInstantiationTrace(Classification.deprecation);
+
+        return true;
+    }
+    return false;
+}
+
 private extern(C++) final class DsymbolSemanticVisitor : Visitor
 {
     alias visit = Visitor.visit;
@@ -359,7 +495,8 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         Dsymbol s = ad.search(dsym.loc, dsym.ident);
         if (!s)
         {
-            s = sc.search(dsym.loc, dsym.ident, null);
+            Dsymbol pscopesym;
+            s = sc.search(dsym.loc, dsym.ident, pscopesym);
             if (s)
                 error(dsym.loc, "`%s` is not a member of `%s`", s.toChars(), ad.toChars());
             else
@@ -449,7 +586,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             printf(" type = %s\n", dsym.type ? dsym.type.toChars() : "null");
             printf(" stc = x%llx\n", dsym.storage_class);
             printf(" storage_class = x%llx\n", dsym.storage_class);
-            printf("linkage = %d\n", dsym.linkage);
+            printf("linkage = %d\n", dsym._linkage);
             //if (strcmp(toChars(), "mul") == 0) assert(0);
         }
         //if (semanticRun > PASS.initial)
@@ -1494,7 +1631,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             {
                 AliasDeclaration ad = imp.aliasdecls[i];
                 //printf("\tImport %s alias %s = %s, scope = %p\n", toPrettyChars(), aliases[i].toChars(), names[i].toChars(), ad._scope);
-                Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], IgnorePrivateImports);
+                Dsymbol sym = imp.mod.search(imp.loc, imp.names[i], SearchOpt.ignorePrivateImports);
                 if (sym)
                 {
                     import dmd.access : symbolIsVisible;
@@ -4121,7 +4258,8 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             // check if `_d_cmain` is defined
             bool cmainTemplateExists()
             {
-                auto rootSymbol = sc.search(funcdecl.loc, Id.empty, null);
+                Dsymbol pscopesym;
+                auto rootSymbol = sc.search(funcdecl.loc, Id.empty, pscopesym);
                 if (auto moduleSymbol = rootSymbol.search(funcdecl.loc, Id.object))
                     if (moduleSymbol.search(funcdecl.loc, Id.CMain))
                         return true;
@@ -7206,7 +7344,7 @@  private void aliasAssignSemantic(AliasAssign ds, Scope* sc)
     AliasDeclaration findAliasDeclaration(AliasAssign ds, Scope* sc)
     {
         Dsymbol scopesym;
-        Dsymbol as = sc.search(ds.loc, ds.ident, &scopesym);
+        Dsymbol as = sc.search(ds.loc, ds.ident, scopesym);
         if (!as)
         {
             .error(ds.loc, "%s `%s` undefined identifier `%s`", ds.kind, ds.toPrettyChars, ds.ident.toChars());
@@ -7833,11 +7971,11 @@  void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
  *  d = dsymbol where ident is searched for
  *  loc = location to print for error messages
  *  ident = identifier to search for
- *  flags = IgnoreXXXX
+ *  flags = search options
  * Returns:
  *  null if not found
  */
-extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, SearchOptFlags flags = SearchOpt.all)
 {
     scope v = new SearchVisitor(loc, ident, flags);
     d.accept(v);
@@ -7862,13 +8000,13 @@  Dsymbol search_correct(Dsymbol d, Identifier ident)
         cost = 0;   // all the same cost
         Dsymbol s = d;
         Module.clearCache();
-        return s.search(Loc.initial, id, IgnoreErrors);
+        return s.search(Loc.initial, id, SearchOpt.ignoreErrors);
     }
 
     if (global.gag)
         return null; // don't do it for speculative compiles; too time consuming
     // search for exact name first
-    if (auto s = d.search(Loc.initial, ident, IgnoreErrors))
+    if (auto s = d.search(Loc.initial, ident, SearchOpt.ignoreErrors))
         return s;
 
     import dmd.root.speller : speller;
@@ -7881,10 +8019,10 @@  private extern(C++) class SearchVisitor : Visitor
 
     const Loc loc;
     Identifier ident;
-    int flags;
+    SearchOptFlags flags;
     Dsymbol result;
 
-    this(const ref Loc loc, Identifier ident, int flags)
+    this(const ref Loc loc, Identifier ident, SearchOptFlags flags)
     {
         this.loc = loc;
         this.ident = ident;
@@ -7908,7 +8046,7 @@  private extern(C++) class SearchVisitor : Visitor
         //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
 
         // Look in symbols declared in this module
-        if (sds.symtab && !(flags & SearchImportsOnly))
+        if (sds.symtab && !(flags & SearchOpt.importsOnly))
         {
             //printf(" look in locals\n");
             auto s1 = sds.symtab.lookup(ident);
@@ -7931,30 +8069,30 @@  private extern(C++) class SearchVisitor : Visitor
         for (size_t i = 0; i < sds.importedScopes.length; i++)
         {
             // If private import, don't search it
-            if ((flags & IgnorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
+            if ((flags & SearchOpt.ignorePrivateImports) && sds.visibilities[i] == Visibility.Kind.private_)
                 continue;
-            int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
+            SearchOptFlags sflags = flags & (SearchOpt.ignoreErrors | SearchOpt.ignoreAmbiguous); // remember these in recursive searches
             Dsymbol ss = (*sds.importedScopes)[i];
             //printf("\tscanning import '%s', visibilities = %d, isModule = %p, isImport = %p\n", ss.toChars(), visibilities[i], ss.isModule(), ss.isImport());
 
             if (ss.isModule())
             {
-                if (flags & SearchLocalsOnly)
+                if (flags & SearchOpt.localsOnly)
                     continue;
             }
             else // mixin template
             {
-                if (flags & SearchImportsOnly)
+                if (flags & SearchOpt.importsOnly)
                     continue;
 
-                sflags |= SearchLocalsOnly;
+                sflags |= SearchOpt.localsOnly;
             }
 
             /* Don't find private members if ss is a module
              */
-            Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
+            Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? SearchOpt.ignorePrivateImports : SearchOpt.all));
             import dmd.access : symbolIsVisible;
-            if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2))
+            if (!s2 || !(flags & SearchOpt.ignoreVisibility) && !symbolIsVisible(sds, s2))
                 continue;
             if (!s)
             {
@@ -8025,7 +8163,7 @@  private extern(C++) class SearchVisitor : Visitor
                             }
                         }
 
-                        if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
+                        if (flags & SearchOpt.ignoreAmbiguous) // if return NULL on ambiguity
                             return setResult(null);
 
                         /* If two imports from C import files, pick first one, as C has global name space
@@ -8033,7 +8171,7 @@  private extern(C++) class SearchVisitor : Visitor
                         if (s.isCsymbol() && s2.isCsymbol())
                             continue;
 
-                        if (!(flags & IgnoreErrors))
+                        if (!(flags & SearchOpt.ignoreErrors))
                             ScopeDsymbol.multiplyDefined(loc, s, s2);
                         break;
                     }
@@ -8060,7 +8198,7 @@  private extern(C++) class SearchVisitor : Visitor
     override void visit(WithScopeSymbol ws)
     {
         //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
-        if (flags & SearchImportsOnly)
+        if (flags & SearchOpt.importsOnly)
             return setResult(null);
         // Acts as proxy to the with class declaration
         Dsymbol s = null;
@@ -8301,7 +8439,7 @@  private extern(C++) class SearchVisitor : Visitor
 
         if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called
         {
-            if (!(flags & IgnoreErrors))
+            if (!(flags & SearchOpt.ignoreErrors))
                 .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars());
             return setResult(null);
         }
@@ -8324,7 +8462,7 @@  private extern(C++) class SearchVisitor : Visitor
     override void visit(Package pkg)
     {
         //printf("%s Package.search('%s', flags = x%x)\n", pkg.toChars(), ident.toChars(), flags);
-        flags &= ~SearchLocalsOnly;  // searching an import is always transitive
+        flags &= ~cast(int)SearchOpt.localsOnly;  // searching an import is always transitive
         if (!pkg.isModule() && pkg.mod)
         {
             // Prefer full package name.
@@ -8351,8 +8489,8 @@  private extern(C++) class SearchVisitor : Visitor
         /* Qualified module searches always search their imports,
          * even if SearchLocalsOnly
          */
-        if (!(flags & SearchUnqualifiedModule))
-            flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+        if (!(flags & SearchOpt.unqualifiedModule))
+            flags &= ~(SearchOpt.unqualifiedModule | SearchOpt.localsOnly);
 
         if (m.searchCacheIdent == ident && m.searchCacheFlags == flags)
         {
@@ -8401,7 +8539,7 @@  private extern(C++) class SearchVisitor : Visitor
         if (!sd.members || !sd.symtab) // opaque or semantic() is not yet called
         {
             // .stringof is always defined (but may be hidden by some other symbol)
-            if(ident != Id.stringof && !(flags & IgnoreErrors) && sd.semanticRun < PASS.semanticdone)
+            if(ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && sd.semanticRun < PASS.semanticdone)
                 .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars());
             return setResult(null);
         }
@@ -8427,7 +8565,7 @@  private extern(C++) class SearchVisitor : Visitor
         if (!cd.members || !cd.symtab) // opaque or addMember is not yet done
         {
             // .stringof is always defined (but may be hidden by some other symbol)
-            if (ident != Id.stringof && !(flags & IgnoreErrors) && cd.semanticRun < PASS.semanticdone)
+            if (ident != Id.stringof && !(flags & SearchOpt.ignoreErrors) && cd.semanticRun < PASS.semanticdone)
                 cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
             //*(char*)0=0;
             return setResult(null);
@@ -8437,7 +8575,7 @@  private extern(C++) class SearchVisitor : Visitor
         auto s = result;
 
         // don't search imports of base classes
-        if (flags & SearchImportsOnly)
+        if (flags & SearchOpt.importsOnly)
             return setResult(s);
 
         if (s)
@@ -8462,7 +8600,7 @@  private extern(C++) class SearchVisitor : Visitor
                 continue;
             else if (s == cd) // happens if s is nested in this and derives from this
                 s = null;
-            else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
+            else if (!(flags & SearchOpt.ignoreVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(cd, s))
                 s = null;
             else
                 break;
@@ -8621,3 +8759,554 @@  private extern(C++) class SetScopeVisitor : Visitor
         visit(cast(AttribDeclaration)uad);
     }
 }
+
+extern(C++) void importAll(Dsymbol d, Scope* sc)
+{
+    scope iav = new ImportAllVisitor(sc);
+    d.accept(iav);
+}
+
+extern(C++) class ImportAllVisitor : Visitor
+{
+    alias visit = typeof(super).visit;
+    Scope* sc;
+
+    this(Scope* sc)
+    {
+        this.sc = sc;
+    }
+
+    override void visit(Dsymbol d) {}
+
+    override void visit(Import imp)
+    {
+        if (imp.mod) return; // Already done
+
+        /*
+         * https://issues.dlang.org/show_bug.cgi?id=15525
+         *
+         * Loading the import has failed,
+         * most likely because of parsing errors.
+         * Therefore we cannot trust the resulting AST.
+         */
+        if (imp.load(sc))
+        {
+            // https://issues.dlang.org/show_bug.cgi?id=23873
+            // For imports that are not at module or function level,
+            // e.g. aggregate level, the import symbol is added to the
+            // symbol table and later semantic is performed on it.
+            // This leads to semantic analysis on an malformed AST
+            // which causes all kinds of segfaults.
+            // The fix is to note that the module has errors and avoid
+            // semantic analysis on it.
+            if(imp.mod)
+                imp.mod.errors = true;
+            return;
+        }
+
+        if (!imp.mod) return; // Failed
+
+        if (sc.stc & STC.static_)
+            imp.isstatic = true;
+        imp.mod.importAll(null);
+        imp.mod.checkImportDeprecation(imp.loc, sc);
+        if (sc.explicitVisibility)
+            imp.visibility = sc.visibility;
+        if (!imp.isstatic && !imp.aliasId && !imp.names.length)
+            sc.scopesym.importScope(imp.mod, imp.visibility);
+        // Enable access to pkgs/mod as soon as posible, because compiler
+        // can traverse them before the import gets semantic (Issue: 21501)
+        if (!imp.aliasId && !imp.names.length)
+            imp.addPackageAccess(sc.scopesym);
+    }
+
+    override void visit(Module m)
+    {
+        //printf("+Module::importAll(this = %p, '%s'): parent = %p\n", m, m.toChars(), m.parent);
+        if (m._scope)
+            return; // already done
+        if (m.filetype == FileType.ddoc)
+        {
+            error(m.loc, "%s `%s` is a Ddoc file, cannot import it", m.kind, m.toPrettyChars);
+            return;
+        }
+
+        /* Note that modules get their own scope, from scratch.
+         * This is so regardless of where in the syntax a module
+         * gets imported, it is unaffected by context.
+         * Ignore prevsc.
+         */
+        Scope* sc = Scope.createGlobal(m, global.errorSink); // create root scope
+
+        if (m.md && m.md.msg)
+            m.md.msg = semanticString(sc, m.md.msg, "deprecation message");
+
+        // Add import of "object", even for the "object" module.
+        // If it isn't there, some compiler rewrites, like
+        //    classinst == classinst -> .object.opEquals(classinst, classinst)
+        // would fail inside object.d.
+        if (m.filetype != FileType.c &&
+            (m.members.length == 0 ||
+             (*m.members)[0].ident != Id.object ||
+             (*m.members)[0].isImport() is null))
+        {
+            auto im = new Import(Loc.initial, null, Id.object, null, 0);
+            m.members.shift(im);
+        }
+        if (!m.symtab)
+        {
+            // Add all symbols into module's symbol table
+            m.symtab = new DsymbolTable();
+            for (size_t i = 0; i < m.members.length; i++)
+            {
+                Dsymbol s = (*m.members)[i];
+                s.addMember(sc, sc.scopesym);
+            }
+        }
+        // anything else should be run after addMember, so version/debug symbols are defined
+        /* Set scope for the symbols so that if we forward reference
+         * a symbol, it can possibly be resolved on the spot.
+         * If this works out well, it can be extended to all modules
+         * before any semantic() on any of them.
+         */
+        m.setScope(sc); // remember module scope for semantic
+        for (size_t i = 0; i < m.members.length; i++)
+        {
+            Dsymbol s = (*m.members)[i];
+            s.setScope(sc);
+        }
+        for (size_t i = 0; i < m.members.length; i++)
+        {
+            Dsymbol s = (*m.members)[i];
+            s.importAll(sc);
+        }
+        sc = sc.pop();
+        sc.pop(); // 2 pops because Scope.createGlobal() created 2
+    }
+
+    override void visit(AttribDeclaration atb)
+    {
+        Dsymbols* d = atb.include(sc);
+        //printf("\tAttribDeclaration::importAll '%s', d = %p\n", toChars(), d);
+        if (d)
+        {
+            Scope* sc2 = atb.newScope(sc);
+            d.foreachDsymbol( s => s.importAll(sc2) );
+            if (sc2 != sc)
+                sc2.pop();
+        }
+    }
+
+    // do not evaluate condition before semantic pass
+    override void visit(StaticIfDeclaration _) {}
+    // do not evaluate aggregate before semantic pass
+    override void visit(StaticForeachDeclaration _) {}
+}
+
+extern(C++) void setFieldOffset(Dsymbol d, AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+{
+    scope v = new SetFieldOffsetVisitor(ad, fieldState, isunion);
+    d.accept(v);
+}
+
+private extern(C++) class SetFieldOffsetVisitor : Visitor
+{
+    alias visit = Visitor.visit;
+
+    AggregateDeclaration ad;
+    FieldState* fieldState;
+    bool isunion;
+
+    this(AggregateDeclaration ad, FieldState* fieldState, bool isunion)
+    {
+        this.ad = ad;
+        this.fieldState = fieldState;
+        this.isunion = isunion;
+    }
+
+    override void visit(Dsymbol d) {}
+
+    override void visit(Nspace ns)
+    {
+        //printf("Nspace::setFieldOffset() %s\n", toChars());
+        if (ns._scope) // if fwd reference
+            dsymbolSemantic(ns, null); // try to resolve it
+        ns.members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+    }
+
+    override void visit(VarDeclaration vd)
+    {
+        //printf("VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), vd.toChars());
+
+        if (vd.aliasTuple)
+        {
+            // If this variable was really a tuple, set the offsets for the tuple fields
+            vd.aliasTuple.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
+            return;
+        }
+
+        if (!vd.isField())
+            return;
+        assert(!(vd.storage_class & (STC.static_ | STC.extern_ | STC.parameter)));
+
+        //printf("+VarDeclaration::setFieldOffset(ad = %s) %s\n", ad.toChars(), toChars());
+
+        /* Fields that are tuples appear both as part of TupleDeclarations and
+         * as members. That means ignore them if they are already a field.
+         */
+        if (vd.offset)
+        {
+            // already a field
+            fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+            return;
+        }
+        for (size_t i = 0; i < ad.fields.length; i++)
+        {
+            if (ad.fields[i] == vd)
+            {
+                // already a field
+                fieldState.offset = ad.structsize; // https://issues.dlang.org/show_bug.cgi?id=13613
+                return;
+            }
+        }
+
+        // Check for forward referenced types which will fail the size() call
+        Type t = vd.type.toBasetype();
+        if (vd.storage_class & STC.ref_)
+        {
+            // References are the size of a pointer
+            t = Type.tvoidptr;
+        }
+        Type tv = t.baseElemOf();
+        if (tv.ty == Tstruct)
+        {
+            auto ts = cast(TypeStruct)tv;
+            assert(ts.sym != ad);   // already checked in ad.determineFields()
+            if (!ts.sym.determineSize(vd.loc))
+            {
+                vd.type = Type.terror;
+                vd.errors = true;
+                return;
+            }
+        }
+
+        // List in ad.fields. Even if the type is error, it's necessary to avoid
+        // pointless error diagnostic "more initializers than fields" on struct literal.
+        ad.fields.push(vd);
+
+        if (t.ty == Terror)
+            return;
+
+        /* If coming after a bit field in progress,
+         * advance past the field
+         */
+        fieldState.inFlight = false;
+
+        const sz = t.size(vd.loc);
+        assert(sz != SIZE_INVALID && sz < uint.max);
+        uint memsize = cast(uint)sz;                // size of member
+        uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
+        vd.offset = placeField(
+            fieldState.offset,
+            memsize, memalignsize, vd.alignment,
+            ad.structsize, ad.alignsize,
+            isunion);
+
+        //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+        //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+    }
+
+    override void visit(BitFieldDeclaration bfd)
+    {
+        enum log = false;
+        static if (log)
+        {
+            printf("BitFieldDeclaration::setFieldOffset(ad: %s, field: %s)\n", ad.toChars(), bfd.toChars());
+            void print(const FieldState* fieldState)
+            {
+                fieldState.print();
+                printf("          fieldWidth   = %d bits\n",    bfd.fieldWidth);
+            }
+            print(fieldState);
+        }
+
+        Type t = bfd.type.toBasetype();
+        const bool anon = bfd.isAnonymous();
+
+        // List in ad.fields. Even if the type is error, it's necessary to avoid
+        // pointless error diagnostic "more initializers than fields" on struct literal.
+        if (!anon)
+            ad.fields.push(bfd);
+
+        if (t.ty == Terror)
+            return;
+
+        const sz = t.size(bfd.loc);
+        assert(sz != SIZE_INVALID && sz < uint.max);
+        uint memsize = cast(uint)sz;                // size of member
+        uint memalignsize = target.fieldalign(t);   // size of member for alignment purposes
+        if (log) printf("          memsize: %u memalignsize: %u\n", memsize, memalignsize);
+
+        if (bfd.fieldWidth == 0 && !anon)
+            error(bfd.loc, "named bit fields cannot have 0 width");
+        if (bfd.fieldWidth > memsize * 8)
+            error(bfd.loc, "bit field width %d is larger than type", bfd.fieldWidth);
+
+        const style = target.c.bitFieldStyle;
+
+        void startNewField()
+        {
+            if (log) printf("startNewField()\n");
+            uint alignsize;
+            if (style == TargetC.BitFieldStyle.Gcc_Clang)
+            {
+                if (bfd.fieldWidth > 32)
+                    alignsize = memalignsize;
+                else if (bfd.fieldWidth > 16)
+                    alignsize = 4;
+                else if (bfd.fieldWidth > 8)
+                    alignsize = 2;
+                else
+                    alignsize = 1;
+            }
+            else
+                alignsize = memsize; // not memalignsize
+
+            uint dummy;
+            bfd.offset = placeField(
+                fieldState.offset,
+                memsize, alignsize, bfd.alignment,
+                ad.structsize,
+                (anon && style == TargetC.BitFieldStyle.Gcc_Clang) ? dummy : ad.alignsize,
+                isunion);
+
+            fieldState.inFlight = true;
+            fieldState.fieldOffset = bfd.offset;
+            fieldState.bitOffset = 0;
+            fieldState.fieldSize = memsize;
+        }
+
+        if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        {
+            if (bfd.fieldWidth == 0)
+            {
+                if (!isunion)
+                {
+                    // Use type of zero width field to align to next field
+                    fieldState.offset = (fieldState.offset + memalignsize - 1) & ~(memalignsize - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
+
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (!anon &&
+                  ad.alignsize < memalignsize)
+                ad.alignsize = memalignsize;
+        }
+        else if (style == TargetC.BitFieldStyle.MS)
+        {
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (bfd.fieldWidth == 0)
+            {
+                if (fieldState.inFlight && !isunion)
+                {
+                    // documentation says align to next int
+                    //const alsz = cast(uint)Type.tint32.size();
+                    const alsz = memsize; // but it really does this
+                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
+        }
+        else if (style == TargetC.BitFieldStyle.DM)
+        {
+            if (anon && bfd.fieldWidth && (!fieldState.inFlight || fieldState.bitOffset == 0))
+                return;  // this probably should be a bug in DMC
+            if (ad.alignsize == 0)
+                ad.alignsize = 1;
+            if (bfd.fieldWidth == 0)
+            {
+                if (fieldState.inFlight && !isunion)
+                {
+                    const alsz = memsize;
+                    fieldState.offset = (fieldState.offset + alsz - 1) & ~(alsz - 1);
+                    ad.structsize = fieldState.offset;
+                }
+
+                fieldState.inFlight = false;
+                return;
+            }
+        }
+
+        if (!fieldState.inFlight)
+        {
+            //printf("not in flight\n");
+            startNewField();
+        }
+        else if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        {
+            // If the bit-field spans more units of alignment than its type,
+            // start a new field at the next alignment boundary.
+            if (fieldState.bitOffset == fieldState.fieldSize * 8 &&
+                fieldState.bitOffset + bfd.fieldWidth > memalignsize * 8)
+            {
+                if (log) printf("more units of alignment than its type\n");
+                startNewField();        // the bit field is full
+            }
+            else
+            {
+                // if alignment boundary is crossed
+                uint start = fieldState.fieldOffset * 8 + fieldState.bitOffset;
+                uint end   = start + bfd.fieldWidth;
+                //printf("%s start: %d end: %d memalignsize: %d\n", ad.toChars(), start, end, memalignsize);
+                if (start / (memalignsize * 8) != (end - 1) / (memalignsize * 8))
+                {
+                    if (log) printf("alignment is crossed\n");
+                    startNewField();
+                }
+            }
+        }
+        else if (style == TargetC.BitFieldStyle.DM ||
+                 style == TargetC.BitFieldStyle.MS)
+        {
+            if (memsize != fieldState.fieldSize ||
+                fieldState.bitOffset + bfd.fieldWidth > fieldState.fieldSize * 8)
+            {
+                //printf("new field\n");
+                startNewField();
+            }
+        }
+        else
+            assert(0);
+
+        bfd.offset = fieldState.fieldOffset;
+        bfd.bitOffset = fieldState.bitOffset;
+
+        const pastField = bfd.bitOffset + bfd.fieldWidth;
+        if (style == TargetC.BitFieldStyle.Gcc_Clang)
+        {
+            auto size = (pastField + 7) / 8;
+            fieldState.fieldSize = size;
+            //printf(" offset: %d, size: %d\n", offset, size);
+            if (isunion)
+            {
+                const newstructsize = bfd.offset + size;
+                if (newstructsize > ad.structsize)
+                    ad.structsize = newstructsize;
+            }
+            else
+                ad.structsize = bfd.offset + size;
+        }
+        else
+            fieldState.fieldSize = memsize;
+        //printf("at end: ad.structsize = %d\n", cast(int)ad.structsize);
+        //print(fieldState);
+
+        if (!isunion)
+        {
+            fieldState.offset = bfd.offset + fieldState.fieldSize;
+            fieldState.bitOffset = pastField;
+        }
+
+        //printf("\t%s: offset = %d bitOffset = %d fieldWidth = %d memsize = %d\n", toChars(), offset, bitOffset, fieldWidth, memsize);
+        //printf("\t%s: memalignsize = %d\n", toChars(), memalignsize);
+        //printf(" addField '%s' to '%s' at offset %d, size = %d\n", toChars(), ad.toChars(), offset, memsize);
+    }
+
+    override void visit(TemplateMixin tm)
+    {
+        //printf("TemplateMixin.setFieldOffset() %s\n", tm.toChars());
+        if (tm._scope) // if fwd reference
+            dsymbolSemantic(tm, null); // try to resolve it
+
+        tm.members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
+    }
+
+    override void visit(AttribDeclaration atd)
+    {
+        atd.include(null).foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
+    }
+
+    override void visit(AnonDeclaration anond)
+    {
+        //printf("\tAnonDeclaration::setFieldOffset %s %p\n", isunion ? "union" : "struct", anond);
+        if (anond.decl)
+        {
+            /* This works by treating an AnonDeclaration as an aggregate 'member',
+             * so in order to place that member we need to compute the member's
+             * size and alignment.
+             */
+            size_t fieldstart = ad.fields.length;
+
+            /* Hackishly hijack ad's structsize and alignsize fields
+             * for use in our fake anon aggregate member.
+             */
+            uint savestructsize = ad.structsize;
+            uint savealignsize = ad.alignsize;
+            ad.structsize = 0;
+            ad.alignsize = 0;
+
+            FieldState fs;
+            anond.decl.foreachDsymbol( (s)
+            {
+                s.setFieldOffset(ad, &fs, anond.isunion);
+                if (anond.isunion)
+                    fs.offset = 0;
+            });
+
+            /* https://issues.dlang.org/show_bug.cgi?id=13613
+             * If the fields in this.members had been already
+             * added in ad.fields, just update *poffset for the subsequent
+             * field offset calculation.
+             */
+            if (fieldstart == ad.fields.length)
+            {
+                ad.structsize = savestructsize;
+                ad.alignsize = savealignsize;
+                fieldState.offset = ad.structsize;
+                return;
+            }
+
+            anond.anonstructsize = ad.structsize;
+            anond.anonalignsize = ad.alignsize;
+            ad.structsize = savestructsize;
+            ad.alignsize = savealignsize;
+
+            // 0 sized structs are set to 1 byte
+            if (anond.anonstructsize == 0)
+            {
+                anond.anonstructsize = 1;
+                anond.anonalignsize = 1;
+            }
+
+            assert(anond._scope);
+            auto alignment = anond._scope.alignment();
+
+            /* Given the anon 'member's size and alignment,
+             * go ahead and place it.
+             */
+            anond.anonoffset = placeField(
+                fieldState.offset,
+                anond.anonstructsize, anond.anonalignsize, alignment,
+                ad.structsize, ad.alignsize,
+                isunion);
+
+            // Add to the anon fields the base offset of this anonymous aggregate
+            //printf("anon fields, anonoffset = %d\n", anonoffset);
+            foreach (const i; fieldstart .. ad.fields.length)
+            {
+                VarDeclaration v = ad.fields[i];
+                //printf("\t[%d] %s %d\n", i, v.toChars(), v.offset);
+                v.offset += anond.anonoffset;
+            }
+        }
+    }
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 326d66364b8..e440b9e2eb6 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -6465,7 +6465,7 @@  extern (C++) class TemplateInstance : ScopeDsymbol
              */
             Identifier id = name;
             Dsymbol scopesym;
-            Dsymbol s = sc.search(loc, id, &scopesym);
+            Dsymbol s = sc.search(loc, id, scopesym);
             if (!s)
             {
                 s = sc.search_correct(id);
@@ -7831,15 +7831,6 @@  extern (C++) final class TemplateMixin : TemplateInstance
         return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
     }
 
-    override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        //printf("TemplateMixin.setFieldOffset() %s\n", toChars());
-        if (_scope) // if fwd reference
-            dsymbolSemantic(this, null); // try to resolve it
-
-        members.foreachDsymbol( (s) { s.setFieldOffset(ad, fieldState, isunion); } );
-    }
-
     override const(char)* toChars() const
     {
         OutBuffer buf;
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 9f855743ef9..ed83a8d9fe1 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -3284,7 +3284,7 @@  ASTCodegen.Dsymbol symbolFromType(ASTCodegen.Type t) @safe
  */
 ASTCodegen.Dsymbol findMember(ASTCodegen.Dsymbol sym, Identifier name)
 {
-    if (auto mem = sym.search(Loc.initial, name, ASTCodegen.IgnoreErrors))
+    if (auto mem = sym.search(Loc.initial, name, ASTCodegen.SearchOpt.ignoreErrors))
         return mem;
 
     // search doesn't work for declarations inside of uninstantiated
diff --git a/gcc/d/dmd/errorsink.d b/gcc/d/dmd/errorsink.d
index ce2351738d6..3811f1d2932 100644
--- a/gcc/d/dmd/errorsink.d
+++ b/gcc/d/dmd/errorsink.d
@@ -60,6 +60,20 @@  class ErrorSinkNull : ErrorSink
     void deprecationSupplemental(const ref Loc loc, const(char)* format, ...) { }
 }
 
+/*****************************************
+ * Ignores the messages, but sets `sawErrors` for any calls to `error()`
+ */
+class ErrorSinkLatch : ErrorSinkNull
+{
+  nothrow:
+  extern (C++):
+  override:
+
+    bool sawErrors;
+
+    void error(const ref Loc loc, const(char)* format, ...) { sawErrors = true; }
+}
+
 /*****************************************
  * Simplest implementation, just sends messages to stderr.
  * See also: ErrorSinkCompiler.
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index cd93e54932c..f51a8b00891 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -21,7 +21,6 @@  import dmd.aggregate;
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
-import dmd.gluelayer;
 import dmd.dclass;
 import dmd.declaration;
 import dmd.dimport;
@@ -2240,7 +2239,7 @@  extern (C++) final class StructLiteralExp : Expression
     // while `sym` is only used in `e2ir/s2ir/tocsym` which comes after
     union
     {
-        Symbol* sym;            /// back end symbol to initialize with literal
+        void* sym;            /// back end symbol to initialize with literal (used as a Symbol*)
 
         /// those fields need to prevent a infinite recursion when one field of struct initialized with 'this' pointer.
         StructLiteralExp inlinecopy;
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index 1664bf22dca..c21b382c71e 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -875,7 +875,7 @@  private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
     Loc loc = ue.loc;
 
     // TODO: merge with Scope.search.searchScopes()
-    Dsymbol searchScopes(int flags)
+    Dsymbol searchScopes(SearchOptFlags flags)
     {
         Dsymbol s = null;
         for (Scope* scx = sc; scx; scx = scx.enclosing)
@@ -883,7 +883,7 @@  private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
             if (!scx.scopesym)
                 continue;
             if (scx.scopesym.isModule())
-                flags |= SearchUnqualifiedModule;    // tell Module.search() that SearchLocalsOnly is to be obeyed
+                flags |= SearchOpt.unqualifiedModule;    // tell Module.search() that SearchOpt.localsOnly is to be obeyed
             s = scx.scopesym.search(loc, ident, flags);
             if (s)
             {
@@ -910,18 +910,18 @@  private Expression searchUFCS(Scope* sc, UnaExp ue, Identifier ident)
         return s;
     }
 
-    int flags = 0;
+    SearchOptFlags flags = SearchOpt.all;
     Dsymbol s;
 
     if (sc.flags & SCOPE.ignoresymbolvisibility)
-        flags |= IgnoreSymbolVisibility;
+        flags |= SearchOpt.ignoreVisibility;
 
     // First look in local scopes
-    s = searchScopes(flags | SearchLocalsOnly);
+    s = searchScopes(flags | SearchOpt.localsOnly);
     if (!s)
     {
         // Second look in imported modules
-        s = searchScopes(flags | SearchImportsOnly);
+        s = searchScopes(flags | SearchOpt.importsOnly);
     }
 
     if (!s)
@@ -3743,7 +3743,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
         }
 
         Dsymbol scopesym;
-        Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+        Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
         if (s)
         {
             if (s.errors)
@@ -6744,7 +6744,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
             if (!sc.insert(s))
             {
-                auto conflict = sc.search(Loc.initial, s.ident, null);
+                Dsymbol pscopesym;
+                auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
                 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
                                   conflict.kind(), conflict.toChars());
@@ -6986,7 +6987,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
              */
             if (!tup && !sc.insert(s))
             {
-                auto conflict = sc.search(Loc.initial, s.ident, null);
+                Dsymbol pscopesym;
+                auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
                 error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
                 errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
                                   conflict.kind(), conflict.toChars());
@@ -7293,7 +7295,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                     s.dsymbolSemantic(sc);
                     if (!sc.insert(s))
                     {
-                        auto conflict = sc.search(Loc.initial, s.ident, null);
+                        Dsymbol pscopesym;
+                        auto conflict = sc.search(Loc.initial, s.ident, pscopesym);
                         error(e.loc, "declaration `%s` is already defined", s.toPrettyChars());
                         errorSupplemental(conflict.loc, "`%s` `%s` is defined here",
                                           conflict.kind(), conflict.toChars());
@@ -14208,15 +14211,15 @@  Expression dotIdSemanticProp(DotIdExp exp, Scope* sc, bool gag)
 
     if (auto ie = eright.isScopeExp()) // also used for template alias's
     {
-        auto flags = SearchLocalsOnly;
+        SearchOptFlags flags = SearchOpt.localsOnly;
         /* Disable access to another module's private imports.
          * The check for 'is sds our current module' is because
          * the current module should have access to its own imports.
          */
         if (ie.sds.isModule() && ie.sds != sc._module)
-            flags |= IgnorePrivateImports;
+            flags |= SearchOpt.ignorePrivateImports;
         if (sc.flags & SCOPE.ignoresymbolvisibility)
-            flags |= IgnoreSymbolVisibility;
+            flags |= SearchOpt.ignoreVisibility;
         Dsymbol s = ie.sds.search(exp.loc, exp.ident, flags);
         /* Check for visibility before resolving aliases because public
          * aliases to private symbols are public.
@@ -16038,7 +16041,8 @@  VarDeclaration makeThis2Argument(const ref Loc loc, Scope* sc, FuncDeclaration f
  */
 bool verifyHookExist(const ref Loc loc, ref Scope sc, Identifier id, string description, Identifier module_ = Id.object)
 {
-    auto rootSymbol = sc.search(loc, Id.empty, null);
+    Dsymbol pscopesym;
+    auto rootSymbol = sc.search(loc, Id.empty, pscopesym);
     if (auto moduleSymbol = rootSymbol.search(loc, module_))
         if (moduleSymbol.search(loc, id))
           return true;
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index 351faa471f2..feaa5bb4d91 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -695,6 +695,7 @@  extern (C++) class FuncDeclaration : Declaration
         int result = 0;
         if (fd.ident == ident)
         {
+            import dmd.typesem : covariant;
             const cov = type.covariant(fd.type);
             if (cov != Covariant.distinct)
             {
@@ -721,6 +722,8 @@  extern (C++) class FuncDeclaration : Declaration
     final int findVtblIndex(Dsymbols* vtbl, int dim)
     {
         //printf("findVtblIndex() %s\n", toChars());
+        import dmd.typesem : covariant;
+
         FuncDeclaration mismatch = null;
         StorageClass mismatchstc = 0;
         int mismatchvi = -1;
@@ -947,6 +950,7 @@  extern (C++) class FuncDeclaration : Declaration
              */
             if (t.ty == Tfunction)
             {
+                import dmd.typesem : covariant;
                 auto tf = cast(TypeFunction)f.type;
                 if (tf.covariant(t) == Covariant.yes &&
                     tf.nextOf().implicitConvTo(t.nextOf()) >= MATCH.constant)
@@ -1157,6 +1161,7 @@  extern (C++) class FuncDeclaration : Declaration
             args.push(e);
         }
 
+        import dmd.typesem : callMatch;
         MATCH m = tg.callMatch(null, ArgumentList(&args, names), 1);
         if (m > MATCH.nomatch)
         {
diff --git a/gcc/d/dmd/globals.d b/gcc/d/dmd/globals.d
index 8d88207a566..9257bc464f4 100644
--- a/gcc/d/dmd/globals.d
+++ b/gcc/d/dmd/globals.d
@@ -167,7 +167,7 @@  extern (C++) struct Param
     bool cov;               // generate code coverage data
     ubyte covPercent;       // 0..100 code coverage percentage required
     bool ctfe_cov = false;  // generate coverage data for ctfe
-    bool ignoreUnsupportedPragmas;  // rather than error on them
+    bool ignoreUnsupportedPragmas = true;  // rather than error on them
     bool useModuleInfo = true;   // generate runtime module information
     bool useTypeInfo = true;     // generate runtime type information
     bool useExceptions = true;   // support exception handling
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index 624cd7406a3..2a02f13ba55 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -41,7 +41,6 @@  public:
     const char *kind() const override;
     Visibility visible() override;
     Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
-    void importAll(Scope *sc) override;
     Dsymbol *toAlias() override;
     bool overloadInsert(Dsymbol *s) override;
 
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index e48410082bd..5aefb0048a6 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -12,21 +12,15 @@ 
 module dmd.init;
 
 import core.stdc.stdio;
-import core.checkedint;
 
 import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
-import dmd.dsymbol;
 import dmd.expression;
-import dmd.globals;
-import dmd.hdrgen;
 import dmd.identifier;
 import dmd.location;
 import dmd.mtype;
-import dmd.common.outbuffer;
 import dmd.rootobject;
-import dmd.tokens;
 import dmd.visitor;
 
 enum NeedInterpret : int
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 6d31f956c8e..19d576d4660 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -606,7 +606,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
             {
                 import dmd.common.outbuffer;
                 OutBuffer buf;
-                HdrGenStage hgs;
+                HdrGenState hgs;
                 toCBuffer(ts.sym, buf, hgs);
                 printf("%s\n", buf.peekChars());
             }
@@ -803,9 +803,6 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         Loop1:
             for (size_t index = 0; index < ci.initializerList.length; )
             {
-                CInitializer cprev;
-                size_t indexprev;
-             L1:
                 DesigInit di = ci.initializerList[index];
                 Designators* dlist = di.designatorList;
                 if (dlist)
@@ -833,15 +830,6 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                             continue Loop1;
                         }
                     }
-                    if (cprev)
-                    {
-                        /* The peeling didn't work, so unpeel it
-                         */
-                        ci = cprev;
-                        index = indexprev;
-                        di = ci.initializerList[index];
-                        goto L2;
-                    }
                     error(ci.loc, "`.%s` is not a field of `%s`\n", id.toChars(), sd.toChars());
                     return err();
                 }
@@ -849,18 +837,55 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                 {
                     if (fieldi == nfields)
                         break;
-                    if (/*index == 0 && ci.initializerList.length == 1 &&*/ di.initializer.isCInitializer())
+
+                    auto ix = di.initializer;
+
+                    /* If a C initializer is wrapped in a C initializer, with no designators,
+                     * peel off the outer one
+                     */
+                    if (ix.isCInitializer())
+                    {
+                        CInitializer cix = ix.isCInitializer();
+                        if (cix.initializerList.length == 1)
+                        {
+                            DesigInit dix = cix.initializerList[0];
+                            if (!dix.designatorList)
+                            {
+                                Initializer inix = dix.initializer;
+                                if (inix.isCInitializer())
+                                    ix = inix;
+                            }
+                        }
+                    }
+
+                    if (auto cix = ix.isCInitializer())
                     {
-                        /* Try peeling off this set of { } and see if it works
+                        /* ImportC loses the structure from anonymous structs, but this is retained
+                         * by the initializer syntax. if a CInitializer has a Designator, it is probably
+                         * a nested anonymous struct
                          */
-                        cprev = ci;
-                        ci = di.initializer.isCInitializer();
-                        indexprev = index;
-                        index = 0;
-                        goto L1;
+                        if (cix.initializerList.length)
+                        {
+                            DesigInit dix = cix.initializerList[0];
+                            Designators* dlistx = dix.designatorList;
+                            if (dlistx && (*dlistx).length == 1 && (*dlistx)[0].ident)
+                            {
+                                auto id = (*dlistx)[0].ident;
+                                foreach (k, f; sd.fields[])         // linear search for now
+                                {
+                                    if (f.ident == id)
+                                    {
+                                        fieldi = k;
+                                        si.addInit(id, dix.initializer);
+                                        ++fieldi;
+                                        ++index;
+                                        continue Loop1;
+                                    }
+                                }
+                            }
+                        }
                     }
 
-                L2:
                     VarDeclaration field;
                     while (1)   // skip field if it overlaps with previously seen fields
                     {
@@ -871,10 +896,11 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
                         if (fieldi == nfields)
                             break;
                     }
+
                     auto tn = field.type.toBasetype();
                     auto tnsa = tn.isTypeSArray();
                     auto tns = tn.isTypeStruct();
-                    auto ix = di.initializer;
+
                     if (tnsa && ix.isExpInitializer())
                     {
                         ExpInitializer ei = ix.isExpInitializer();
@@ -1013,7 +1039,7 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         }
         else
         {
-            error(ci.loc, "unrecognized C initializer `%s`", toChars(ci));
+            error(ci.loc, "unrecognized C initializer `%s` for type `%s`", toChars(ci), t.toChars());
             return err();
         }
     }
@@ -1548,6 +1574,11 @@  Expressions* resolveStructLiteralNamedArgs(StructDeclaration sd, Type t, Scope*
                 cast(int) nfields, nfields != 1 ? "s".ptr : "".ptr);
             return null;
         }
+        if (fieldi >= nfields)
+        {
+            error(argLoc, "trying to initialize past the last field `%s` of `%s`", sd.fields[nfields - 1].toChars(), sd.toChars());
+            return null;
+        }
 
         VarDeclaration vd = sd.fields[fieldi];
         if (elems[fieldi])
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index d19d435f240..c90c36069fd 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -244,7 +244,7 @@  public:
         {
             // we must check what the identifier expression is.
             Dsymbol scopesym;
-            Dsymbol s = sc.search(exp.loc, exp.ident, &scopesym);
+            Dsymbol s = sc.search(exp.loc, exp.ident, scopesym);
             if (s)
             {
                 auto v = s.isVarDeclaration();
diff --git a/gcc/d/dmd/lexer.d b/gcc/d/dmd/lexer.d
index b8faec76d60..2c6a5950569 100644
--- a/gcc/d/dmd/lexer.d
+++ b/gcc/d/dmd/lexer.d
@@ -2008,23 +2008,17 @@  class Lexer
             case 'u':
                 dchar d1;
                 size_t idx;
-                auto msg = utf_decodeChar(str, idx, d1);
-                dchar d2 = 0;
-                if (idx < n && !msg)
-                    msg = utf_decodeChar(str, idx, d2);
-                if (msg)
-                    error(loc, "%.*s", cast(int)msg.length, msg.ptr);
-                else if (idx < n)
-                    error(loc, "max number of chars in 16 bit character literal is 2, had %d",
-                        cast(int)((n + 1) >> 1));
-                else if (d1 > 0x1_0000)
-                    error(loc, "%d does not fit in 16 bits", d1);
-                else if (d2 > 0x1_0000)
-                    error(loc, "%d does not fit in 16 bits", d2);
-                u = d1;
-                if (d2)
-                    u = (d1 << 16) | d2;
-                break;
+                while (idx < n)
+                {
+                    string msg = utf_decodeChar(str, idx, d1);
+                    if (msg)
+                        error(loc, "%.*s", cast(int)msg.length, msg.ptr);
+                }
+                if (d1 >= 0x1_0000)
+                    error(loc, "x%x does not fit in 16 bits", d1);
+                t.unsvalue = d1;
+                t.value = TOK.wcharLiteral; // C11 6.4.4.4-9
+                return;
 
             case 'U':
                 dchar d;
@@ -2035,8 +2029,9 @@  class Lexer
                 else if (idx < n)
                     error(loc, "max number of chars in 32 bit character literal is 1, had %d",
                         cast(int)((n + 3) >> 2));
-                u = d;
-                break;
+                t.unsvalue = d;
+                t.value = TOK.dcharLiteral; // C11 6.4.4.4-9
+                return;
 
             default:
                 assert(0);
@@ -3270,7 +3265,7 @@  class Lexer
         while (1)
         {
             printf("%s ", (*tk).toChars());
-            if (tk.value == TOK.endOfFile)
+            if (tk.value == TOK.endOfFile || tk.value == TOK.endOfLine)
                 break;
             tk = peek(tk);
         }
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index cab0b0a4c1b..80a6ea25965 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -88,7 +88,7 @@  public:
 
     Identifier *searchCacheIdent;
     Dsymbol *searchCacheSymbol; // cached value of search
-    int searchCacheFlags;       // cached flags
+    SearchOptFlags searchCacheFlags;       // cached flags
     d_bool insearch;
 
     // module from command line we're imported from,
@@ -121,9 +121,8 @@  public:
     const char *kind() const override;
     bool read(const Loc &loc); // read file, returns 'true' if succeed, 'false' otherwise.
     Module *parse();    // syntactic parse
-    void importAll(Scope *sc) override;
     int needModuleInfo();
-    bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
+    bool isPackageAccessible(Package *p, Visibility visibility, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all) override;
     Dsymbol *symtabInsert(Dsymbol *s) override;
     static void runDeferredSemantic();
     static void runDeferredSemantic2();
diff --git a/gcc/d/dmd/mtype.d b/gcc/d/dmd/mtype.d
index 8860f143715..626bf7431f0 100644
--- a/gcc/d/dmd/mtype.d
+++ b/gcc/d/dmd/mtype.d
@@ -19,7 +19,6 @@  import core.stdc.string;
 
 import dmd.aggregate;
 import dmd.arraytypes;
-import dmd.attrib;
 import dmd.astenums;
 import dmd.ast_node;
 import dmd.gluelayer;
@@ -35,7 +34,6 @@  import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
 import dmd.hdrgen;
@@ -522,262 +520,6 @@  extern (C++) abstract class Type : ASTNode
         return mcache;
     }
 
-    /*******************************
-     * Covariant means that 'this' can substitute for 't',
-     * i.e. a pure function is a match for an impure type.
-     * Params:
-     *      t = type 'this' is covariant with
-     *      pstc = if not null, store STCxxxx which would make it covariant
-     *      cppCovariant = true if extern(C++) function types should follow C++ covariant rules
-     * Returns:
-     *     An enum value of either `Covariant.yes` or a reason it's not covariant.
-     */
-    final Covariant covariant(Type t, StorageClass* pstc = null, bool cppCovariant = false)
-    {
-        version (none)
-        {
-            printf("Type::covariant(t = %s) %s\n", t.toChars(), toChars());
-            printf("deco = %p, %p\n", deco, t.deco);
-            //    printf("ty = %d\n", next.ty);
-            printf("mod = %x, %x\n", mod, t.mod);
-        }
-        if (pstc)
-            *pstc = 0;
-        StorageClass stc = 0;
-
-        bool notcovariant = false;
-
-        if (equals(t))
-            return Covariant.yes;
-
-        TypeFunction t1 = this.isTypeFunction();
-        TypeFunction t2 = t.isTypeFunction();
-
-        if (!t1 || !t2)
-            goto Ldistinct;
-
-        if (t1.parameterList.varargs != t2.parameterList.varargs)
-            goto Ldistinct;
-
-        if (t1.parameterList.parameters && t2.parameterList.parameters)
-        {
-            if (t1.parameterList.length != t2.parameterList.length)
-                goto Ldistinct;
-
-            foreach (i, fparam1; t1.parameterList)
-            {
-                Parameter fparam2 = t2.parameterList[i];
-                Type tp1 = fparam1.type;
-                Type tp2 = fparam2.type;
-
-                if (!tp1.equals(tp2))
-                {
-                    if (tp1.ty == tp2.ty)
-                    {
-                        if (auto tc1 = tp1.isTypeClass())
-                        {
-                            if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
-                                goto Lcov;
-                        }
-                        else if (auto ts1 = tp1.isTypeStruct())
-                        {
-                            if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
-                                goto Lcov;
-                        }
-                        else if (tp1.ty == Tpointer)
-                        {
-                            if (tp2.implicitConvTo(tp1))
-                                goto Lcov;
-                        }
-                        else if (tp1.ty == Tarray)
-                        {
-                            if (tp2.implicitConvTo(tp1))
-                                goto Lcov;
-                        }
-                        else if (tp1.ty == Tdelegate)
-                        {
-                            if (tp2.implicitConvTo(tp1))
-                                goto Lcov;
-                        }
-                    }
-                    goto Ldistinct;
-                }
-            Lcov:
-                notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
-
-                /* https://issues.dlang.org/show_bug.cgi?id=23135
-                 * extern(C++) mutable parameters are not covariant with const.
-                 */
-                if (t1.linkage == LINK.cpp && cppCovariant)
-                {
-                    notcovariant |= tp1.isNaked() != tp2.isNaked();
-                    if (auto tpn1 = tp1.nextOf())
-                        notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
-                }
-            }
-        }
-        else if (t1.parameterList.parameters != t2.parameterList.parameters)
-        {
-            if (t1.parameterList.length || t2.parameterList.length)
-                goto Ldistinct;
-        }
-
-        // The argument lists match
-        if (notcovariant)
-            goto Lnotcovariant;
-        if (t1.linkage != t2.linkage)
-            goto Lnotcovariant;
-
-        {
-            // Return types
-            Type t1n = t1.next;
-            Type t2n = t2.next;
-
-            if (!t1n || !t2n) // happens with return type inference
-                goto Lnotcovariant;
-
-            if (t1n.equals(t2n))
-                goto Lcovariant;
-            if (t1n.ty == Tclass && t2n.ty == Tclass)
-            {
-                /* If same class type, but t2n is const, then it's
-                 * covariant. Do this test first because it can work on
-                 * forward references.
-                 */
-                if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
-                    goto Lcovariant;
-
-                // If t1n is forward referenced:
-                ClassDeclaration cd = (cast(TypeClass)t1n).sym;
-                if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
-                    cd.dsymbolSemantic(null);
-                if (!cd.isBaseInfoComplete())
-                {
-                    return Covariant.fwdref;
-                }
-            }
-            if (t1n.ty == Tstruct && t2n.ty == Tstruct)
-            {
-                if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
-                    goto Lcovariant;
-            }
-            else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
-            {
-                if (t1.isref && t2.isref)
-                {
-                    // Treat like pointers to t1n and t2n
-                    if (t1n.constConv(t2n) < MATCH.constant)
-                        goto Lnotcovariant;
-                }
-                goto Lcovariant;
-            }
-            else if (t1n.ty == Tnull)
-            {
-                // NULL is covariant with any pointer type, but not with any
-                // dynamic arrays, associative arrays or delegates.
-                // https://issues.dlang.org/show_bug.cgi?id=8589
-                // https://issues.dlang.org/show_bug.cgi?id=19618
-                Type t2bn = t2n.toBasetype();
-                if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
-                    goto Lcovariant;
-            }
-            // bottom type is covariant to any type
-            else if (t1n.ty == Tnoreturn)
-                goto Lcovariant;
-        }
-        goto Lnotcovariant;
-
-    Lcovariant:
-        if (t1.isref != t2.isref)
-            goto Lnotcovariant;
-
-        if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
-        {
-            StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
-            StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
-            if (t1.isreturn)
-            {
-                stc1 |= STC.return_;
-                if (!t1.isScopeQual)
-                    stc1 |= STC.ref_;
-            }
-            if (t2.isreturn)
-            {
-                stc2 |= STC.return_;
-                if (!t2.isScopeQual)
-                    stc2 |= STC.ref_;
-            }
-            if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
-                goto Lnotcovariant;
-        }
-
-        // We can subtract 'return ref' from 'this', but cannot add it
-        else if (t1.isreturn && !t2.isreturn)
-            goto Lnotcovariant;
-
-        /* https://issues.dlang.org/show_bug.cgi?id=23135
-         * extern(C++) mutable member functions are not covariant with const.
-         */
-        if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
-            goto Lnotcovariant;
-
-        /* Can convert mutable to const
-         */
-        if (!MODimplicitConv(t2.mod, t1.mod))
-        {
-            version (none)
-            {
-                //stop attribute inference with const
-                // If adding 'const' will make it covariant
-                if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
-                    stc |= STC.const_;
-                else
-                    goto Lnotcovariant;
-            }
-            else
-            {
-                goto Ldistinct;
-            }
-        }
-
-        /* Can convert pure to impure, nothrow to throw, and nogc to gc
-         */
-        if (!t1.purity && t2.purity)
-            stc |= STC.pure_;
-
-        if (!t1.isnothrow && t2.isnothrow)
-            stc |= STC.nothrow_;
-
-        if (!t1.isnogc && t2.isnogc)
-            stc |= STC.nogc;
-
-        /* Can convert safe/trusted to system
-         */
-        if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
-        {
-            // Should we infer trusted or safe? Go with safe.
-            stc |= STC.safe;
-        }
-
-        if (stc)
-        {
-            if (pstc)
-                *pstc = stc;
-            goto Lnotcovariant;
-        }
-
-        //printf("\tcovaraint: 1\n");
-        return Covariant.yes;
-
-    Ldistinct:
-        //printf("\tcovaraint: 0\n");
-        return Covariant.distinct;
-
-    Lnotcovariant:
-        //printf("\tcovaraint: 2\n");
-        return Covariant.no;
-    }
-
     /********************************
      * For pretty-printing a type.
      */
@@ -1061,17 +803,6 @@  extern (C++) abstract class Type : ASTNode
         return isscalar();
     }
 
-    /*********************************
-     * Check type to see if it is based on a deprecated symbol.
-     */
-    void checkDeprecated(const ref Loc loc, Scope* sc)
-    {
-        if (Dsymbol s = toDsymbol(sc))
-        {
-            s.checkDeprecated(loc, sc);
-        }
-    }
-
     final bool isConst() const nothrow pure @nogc @safe
     {
         return (mod & MODFlags.const_) != 0;
@@ -2825,13 +2556,6 @@  extern (C++) abstract class TypeNext : Type
         this.next = next;
     }
 
-    override final void checkDeprecated(const ref Loc loc, Scope* sc)
-    {
-        Type.checkDeprecated(loc, sc);
-        if (next) // next can be NULL if TypeFunction and auto return type
-            next.checkDeprecated(loc, sc);
-    }
-
     override final int hasWild() const
     {
         if (ty == Tfunction)
@@ -4612,27 +4336,7 @@  extern (C++) final class TypeFunction : TypeNext
         return t.merge();
     }
 
-    // arguments get specially formatted
-    private const(char)* getParamError(Expression arg, Parameter par)
-    {
-        if (global.gag && !global.params.v.showGaggedErrors)
-            return null;
-        // show qualification when toChars() is the same but types are different
-        // https://issues.dlang.org/show_bug.cgi?id=19948
-        // when comparing the type with strcmp, we need to drop the qualifier
-        bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
-            strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
-        auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
-        OutBuffer buf;
-        // only mention rvalue if it's relevant
-        const rv = !arg.isLvalue() && par.isReference();
-        buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
-            rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
-            parameterToChars(par, this, qual));
-        return buf.extractChars();
-    }
-
-    private extern(D) const(char)* getMatchError(A...)(const(char)* format, A args)
+    extern(D) static const(char)* getMatchError(A...)(const(char)* format, A args)
     {
         if (global.gag && !global.params.v.showGaggedErrors)
             return null;
@@ -4641,185 +4345,6 @@  extern (C++) final class TypeFunction : TypeNext
         return buf.extractChars();
     }
 
-    /********************************
-     * 'args' are being matched to function 'this'
-     * Determine match level.
-     * Params:
-     *      tthis = type of `this` pointer, null if not member function
-     *      argumentList = arguments to function call
-     *      flag = 1: performing a partial ordering match
-     *      pMessage = address to store error message, or null
-     *      sc = context
-     * Returns:
-     *      MATCHxxxx
-     */
-    extern (D) MATCH callMatch(Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
-    {
-        //printf("TypeFunction::callMatch() %s\n", toChars());
-        MATCH match = MATCH.exact; // assume exact match
-        ubyte wildmatch = 0;
-
-        if (tthis)
-        {
-            Type t = tthis;
-            if (t.toBasetype().ty == Tpointer)
-                t = t.toBasetype().nextOf(); // change struct* to struct
-            if (t.mod != mod)
-            {
-                if (MODimplicitConv(t.mod, mod))
-                    match = MATCH.constant;
-                else if ((mod & MODFlags.wild) && MODimplicitConv(t.mod, (mod & ~MODFlags.wild) | MODFlags.const_))
-                {
-                    match = MATCH.constant;
-                }
-                else
-                    return MATCH.nomatch;
-            }
-            if (isWild())
-            {
-                if (t.isWild())
-                    wildmatch |= MODFlags.wild;
-                else if (t.isConst())
-                    wildmatch |= MODFlags.const_;
-                else if (t.isImmutable())
-                    wildmatch |= MODFlags.immutable_;
-                else
-                    wildmatch |= MODFlags.mutable;
-            }
-        }
-
-        const nparams = parameterList.length;
-        if (argumentList.length > nparams)
-        {
-            if (parameterList.varargs == VarArg.none)
-            {
-                // suppress early exit if an error message is wanted,
-                // so we can check any matching args are valid
-                if (!pMessage)
-                    return MATCH.nomatch;
-            }
-            // too many args; no match
-            match = MATCH.convert; // match ... with a "conversion" match level
-        }
-
-        // https://issues.dlang.org/show_bug.cgi?id=22997
-        if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
-        {
-            OutBuffer buf;
-            buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
-            if (pMessage)
-                *pMessage = buf.extractChars();
-            return MATCH.nomatch;
-        }
-        auto resolvedArgs = resolveNamedArgs(argumentList, pMessage);
-        Expression[] args;
-        if (!resolvedArgs)
-        {
-            if (!pMessage || *pMessage)
-                return MATCH.nomatch;
-
-            // if no message was provided, it was because of overflow which will be diagnosed below
-            match = MATCH.nomatch;
-            args = argumentList.arguments ? (*argumentList.arguments)[] : null;
-        }
-        else
-        {
-            args = (*resolvedArgs)[];
-        }
-
-        foreach (u, p; parameterList)
-        {
-            if (u >= args.length)
-                break;
-
-            Expression arg = args[u];
-            if (!arg)
-                continue; // default argument
-
-            Type tprm = p.type;
-            Type targ = arg.type;
-
-            if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
-            {
-                const isRef = p.isReference();
-                wildmatch |= targ.deduceWild(tprm, isRef);
-            }
-        }
-        if (wildmatch)
-        {
-            /* Calculate wild matching modifier
-             */
-            if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
-                wildmatch = MODFlags.const_;
-            else if (wildmatch & MODFlags.immutable_)
-                wildmatch = MODFlags.immutable_;
-            else if (wildmatch & MODFlags.wild)
-                wildmatch = MODFlags.wild;
-            else
-            {
-                assert(wildmatch & MODFlags.mutable);
-                wildmatch = MODFlags.mutable;
-            }
-        }
-
-        foreach (u, p; parameterList)
-        {
-            MATCH m;
-
-            assert(p);
-
-            // One or more arguments remain
-            if (u < args.length)
-            {
-                Expression arg = args[u];
-                if (!arg)
-                    continue; // default argument
-                m = argumentMatchParameter(this, p, arg, wildmatch, flag, sc, pMessage);
-            }
-            else if (p.defaultArg)
-                continue;
-
-            /* prefer matching the element type rather than the array
-             * type when more arguments are present with T[]...
-             */
-            if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
-                goto L1;
-
-            //printf("\tm = %d\n", m);
-            if (m == MATCH.nomatch) // if no match
-            {
-            L1:
-                if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
-                {
-                    auto trailingArgs = args[u .. $];
-                    if (auto vmatch = matchTypeSafeVarArgs(this, p, trailingArgs, pMessage))
-                        return vmatch < match ? vmatch : match;
-                    // Error message was already generated in `matchTypeSafeVarArgs`
-                    return MATCH.nomatch;
-                }
-                if (pMessage && u >= args.length)
-                    *pMessage = getMatchError("missing argument for parameter #%d: `%s`",
-                        u + 1, parameterToChars(p, this, false));
-                // If an error happened previously, `pMessage` was already filled
-                else if (pMessage && !*pMessage)
-                    *pMessage = getParamError(args[u], p);
-
-                return MATCH.nomatch;
-            }
-            if (m < match)
-                match = m; // pick worst match
-        }
-
-        if (pMessage && !parameterList.varargs && args.length > nparams)
-        {
-            // all parameters had a match, but there are surplus args
-            *pMessage = getMatchError("expected %d argument(s), not %d", nparams, args.length);
-            return MATCH.nomatch;
-        }
-        //printf("match = %d\n", match);
-        return match;
-    }
-
     /********************************
      * Convert an `argumentList`, which may contain named arguments, into
      * a list of arguments in the order of the parameter list.
@@ -6935,7 +6460,7 @@  extern (C++) final class Parameter : ASTNode
         return isCovariantScope(returnByRef, thisSTC, otherSTC);
     }
 
-    extern (D) private static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
+    extern (D) static bool isCovariantScope(bool returnByRef, StorageClass from, StorageClass to) pure nothrow @nogc @safe
     {
         // Workaround for failing covariance when finding a common type of delegates,
         // some of which have parameters with inferred scope
@@ -7234,328 +6759,6 @@  const(char)* toChars(ScopeRef sr) pure nothrow @nogc @safe
     }
 }
 
-/**
- * Used by `callMatch` to check if the copy constructor may be called to
- * copy the argument
- *
- * This is done by seeing if a call to the copy constructor can be made:
- * ```
- * typeof(tprm) __copytmp;
- * copytmp.__copyCtor(arg);
- * ```
- */
-private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
-    Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
-{
-    auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
-    tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
-    tmp.dsymbolSemantic(sc);
-    Expression ve = new VarExp(arg.loc, tmp);
-    Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
-    e = new CallExp(arg.loc, e, arg);
-    //printf("e = %s\n", e.toChars());
-    if (.trySemantic(e, sc))
-        return true;
-
-    if (pMessage)
-    {
-        /* https://issues.dlang.org/show_bug.cgi?id=22202
-         *
-         * If a function was deduced by semantic on the CallExp,
-         * it means that resolveFuncCall completed succesfully.
-         * Therefore, there exists a callable copy constructor,
-         * however, it cannot be called because scope constraints
-         * such as purity, safety or nogc.
-         */
-        OutBuffer buf;
-        auto callExp = e.isCallExp();
-        if (auto f = callExp.f)
-        {
-            char[] s;
-            if (!f.isPure && sc.func.setImpure())
-                s ~= "pure ";
-            if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
-                s ~= "@safe ";
-            if (!f.isNogc && sc.func.setGC(arg.loc, null))
-                s ~= "nogc ";
-            if (s)
-            {
-                s[$-1] = '\0';
-                buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
-            }
-            else if (f.isGenerated() && f.isDisabled())
-            {
-                /* https://issues.dlang.org/show_bug.cgi?id=23097
-                 * Compiler generated copy constructor failed.
-                 */
-                buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
-                           argStruct.toChars());
-            }
-            else
-            {
-                /* Although a copy constructor may exist, no suitable match was found.
-                 * i.e: `inout` constructor creates `const` object, not mutable.
-                 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
-                 */
-                goto Lnocpctor;
-            }
-        }
-        else
-        {
-        Lnocpctor:
-            buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
-                       argStruct.toChars(), arg.type.toChars(), tprm.toChars());
-        }
-
-        *pMessage = buf.extractChars();
-    }
-    return false;
-}
-
-/**
- * Match a single parameter to an argument.
- *
- * This function is called by `TypeFunction.callMatch` while iterating over
- * the list of parameter. Here we check if `arg` is a match for `p`,
- * which is mostly about checking if `arg.type` converts to `p`'s type
- * and some check about value reference.
- *
- * Params:
- *   tf = The `TypeFunction`, only used for error reporting
- *   p = The parameter of `tf` being matched
- *   arg = Argument being passed (bound) to `p`
- *   wildmatch = Wild (`inout`) matching level, derived from the full argument list
- *   flag = A non-zero value means we're doing a partial ordering check
- *          (no value semantic check)
- *   sc = Scope we are in
- *   pMessage = A buffer to write the error in, or `null`
- *
- * Returns: Whether `trailingArgs` match `p`.
- */
-private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
-    Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
-{
-    //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
-    MATCH m;
-    Type targ = arg.type;
-    Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
-
-    if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
-        m = MATCH.convert;
-    else if (flag)
-    {
-        // for partial ordering, value is an irrelevant mockup, just look at the type
-        m = targ.implicitConvTo(tprm);
-    }
-    else
-    {
-        const isRef = p.isReference();
-        StructDeclaration argStruct, prmStruct;
-
-        // first look for a copy constructor
-        if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
-        {
-            // if the argument and the parameter are of the same unqualified struct type
-            argStruct = (cast(TypeStruct)targ).sym;
-            prmStruct = (cast(TypeStruct)tprm).sym;
-        }
-
-        // check if the copy constructor may be called to copy the argument
-        if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
-        {
-            if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
-                return MATCH.nomatch;
-            m = MATCH.exact;
-        }
-        else
-        {
-            import dmd.dcast : cimplicitConvTo;
-            m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
-        }
-    }
-
-    // Non-lvalues do not match ref or out parameters
-    if (p.isReference())
-    {
-        // https://issues.dlang.org/show_bug.cgi?id=13783
-        // Don't use toBasetype() to handle enum types.
-        Type ta = targ;
-        Type tp = tprm;
-        //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
-
-        if (m && !arg.isLvalue())
-        {
-            if (p.storageClass & STC.out_)
-            {
-                if (pMessage) *pMessage = tf.getParamError(arg, p);
-                return MATCH.nomatch;
-            }
-
-            if (arg.op == EXP.string_ && tp.ty == Tsarray)
-            {
-                if (ta.ty != Tsarray)
-                {
-                    Type tn = tp.nextOf().castMod(ta.nextOf().mod);
-                    dinteger_t dim = (cast(StringExp)arg).len;
-                    ta = tn.sarrayOf(dim);
-                }
-            }
-            else if (arg.op == EXP.slice && tp.ty == Tsarray)
-            {
-                // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
-                if (ta.ty != Tsarray)
-                {
-                    Type tn = ta.nextOf();
-                    dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
-                    ta = tn.sarrayOf(dim);
-                }
-            }
-            else if ((p.storageClass & STC.in_) && global.params.previewIn)
-            {
-                // Allow converting a literal to an `in` which is `ref`
-                if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
-                {
-                    Type tn = tp.nextOf();
-                    dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
-                    ta = tn.sarrayOf(dim);
-                }
-
-                // Need to make this a rvalue through a temporary
-                m = MATCH.convert;
-            }
-            else if (global.params.rvalueRefParam != FeatureState.enabled ||
-                     p.storageClass & STC.out_ ||
-                     !arg.type.isCopyable())  // can't copy to temp for ref parameter
-            {
-                if (pMessage) *pMessage = tf.getParamError(arg, p);
-                return MATCH.nomatch;
-            }
-            else
-            {
-                /* in functionParameters() we'll convert this
-                 * rvalue into a temporary
-                 */
-                m = MATCH.convert;
-            }
-        }
-
-        /* If the match is not already perfect or if the arg
-           is not a lvalue then try the `alias this` chain
-           see  https://issues.dlang.org/show_bug.cgi?id=15674
-           and https://issues.dlang.org/show_bug.cgi?id=21905
-        */
-        if (ta != tp || !arg.isLvalue())
-        {
-            Type firsttab = ta.toBasetype();
-            while (1)
-            {
-                Type tab = ta.toBasetype();
-                Type tat = tab.aliasthisOf();
-                if (!tat || !tat.implicitConvTo(tprm))
-                    break;
-                if (tat == tab || tat == firsttab)
-                    break;
-                ta = tat;
-            }
-        }
-
-        /* A ref variable should work like a head-const reference.
-         * e.g. disallows:
-         *  ref T      <- an lvalue of const(T) argument
-         *  ref T[dim] <- an lvalue of const(T[dim]) argument
-         */
-        if (!ta.constConv(tp))
-        {
-            if (pMessage) *pMessage = tf.getParamError(arg, p);
-            return MATCH.nomatch;
-        }
-    }
-    return m;
-}
-
-/**
- * Match the remaining arguments `trailingArgs` with parameter `p`.
- *
- * Assume we already checked that `p` is the last parameter of `tf`,
- * and we want to know whether the arguments would match `p`.
- *
- * Params:
- *   tf = The `TypeFunction`, only used for error reporting
- *   p = The last parameter of `tf` which is variadic
- *   trailingArgs = The remaining arguments that should match `p`
- *   pMessage = A buffer to write the error in, or `null`
- *
- * Returns: Whether `trailingArgs` match `p`.
- */
-private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
-    Expression[] trailingArgs, const(char)** pMessage)
-{
-    Type tb = p.type.toBasetype();
-
-    switch (tb.ty)
-    {
-    case Tsarray:
-        TypeSArray tsa = cast(TypeSArray)tb;
-        dinteger_t sz = tsa.dim.toInteger();
-        if (sz != trailingArgs.length)
-        {
-            if (pMessage)
-                *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
-                    sz, trailingArgs.length);
-            return MATCH.nomatch;
-        }
-        goto case Tarray;
-    case Tarray:
-    {
-        MATCH match = MATCH.exact;
-        TypeArray ta = cast(TypeArray)tb;
-        foreach (arg; trailingArgs)
-        {
-            MATCH m;
-            assert(arg);
-
-            /* If lazy array of delegates,
-             * convert arg(s) to delegate(s)
-             */
-            Type tret = p.isLazyArray();
-            if (tret)
-            {
-                if (ta.next.equals(arg.type))
-                    m = MATCH.exact;
-                else if (tret.toBasetype().ty == Tvoid)
-                    m = MATCH.convert;
-                else
-                {
-                    m = arg.implicitConvTo(tret);
-                    if (m == MATCH.nomatch)
-                        m = arg.implicitConvTo(ta.next);
-                }
-            }
-            else
-                m = arg.implicitConvTo(ta.next);
-
-            if (m == MATCH.nomatch)
-            {
-                if (pMessage) *pMessage = tf.getParamError(arg, p);
-                return MATCH.nomatch;
-            }
-            if (m < match)
-                match = m;
-        }
-        return match;
-    }
-    case Tclass:
-        // We leave it up to the actual constructor call to do the matching.
-        return MATCH.exact;
-
-    default:
-        // We can have things as `foo(int[int] wat...)` but they only match
-        // with an associative array proper.
-        if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
-        return MATCH.nomatch;
-    }
-}
-
 /**
  * Creates an appropriate vector type for `tv` that will hold one boolean
  * result for each element of the vector type. The result of vector comparisons
@@ -7738,3 +6941,36 @@  TypeIdentifier getException()
     tid.addIdent(Id.Exception);
     return tid;
 }
+
+/**************************************
+ * Check and set 'att' if 't' is a recursive 'alias this' type
+ *
+ * The goal is to prevent endless loops when there is a cycle in the alias this chain.
+ * Since there is no multiple `alias this`, the chain either ends in a leaf,
+ * or it loops back on itself as some point.
+ *
+ * Example: S0 -> (S1 -> S2 -> S3 -> S1)
+ *
+ * `S0` is not a recursive alias this, so this returns `false`, and a rewrite to `S1` can be tried.
+ * `S1` is a recursive alias this type, but since `att` is initialized to `null`,
+ * this still returns `false`, but `att1` is set to `S1`.
+ * A rewrite to `S2` and `S3` can be tried, but when we want to try a rewrite to `S1` again,
+ * we notice `att == t`, so we're back at the start of the loop, and this returns `true`.
+ *
+ * Params:
+ *   att = type reference used to detect recursion. Should be initialized to `null`.
+ *   t   = type of 'alias this' rewrite to attempt
+ *
+ * Returns:
+ *   `false` if the rewrite is safe, `true` if it would loop back around
+ */
+bool isRecursiveAliasThis(ref Type att, Type t)
+{
+    //printf("+isRecursiveAliasThis(att = %s, t = %s)\n", att ? att.toChars() : "null", t.toChars());
+    auto tb = t.toBasetype();
+    if (att && tb.equivalent(att))
+        return true;
+    else if (!att && tb.checkAliasThisRec())
+        att = tb;
+    return false;
+}
diff --git a/gcc/d/dmd/mtype.h b/gcc/d/dmd/mtype.h
index 675e944050b..ef1ce100640 100644
--- a/gcc/d/dmd/mtype.h
+++ b/gcc/d/dmd/mtype.h
@@ -225,7 +225,6 @@  public:
     // kludge for template.isType()
     DYNCAST dyncast() const override final { return DYNCAST_TYPE; }
     size_t getUniqueID() const;
-    Covariant covariant(Type *, StorageClass * = NULL, bool = false);
     const char *toChars() const override;
     char *toPrettyChars(bool QualifyTypes = false);
     static void _init();
@@ -249,7 +248,6 @@  public:
     virtual bool isString();
     virtual bool isAssignable();
     virtual bool isBoolean();
-    virtual void checkDeprecated(const Loc &loc, Scope *sc);
     bool isConst() const       { return (mod & MODconst) != 0; }
     bool isImmutable() const   { return (mod & MODimmutable) != 0; }
     bool isMutable() const     { return (mod & (MODconst | MODimmutable | MODwild)) == 0; }
@@ -364,7 +362,6 @@  class TypeNext : public Type
 public:
     Type *next;
 
-    void checkDeprecated(const Loc &loc, Scope *sc) override final;
     int hasWild() const override final;
     Type *nextOf() override final;
     Type *makeConst() override final;
@@ -929,3 +926,4 @@  public:
 
 // If the type is a class or struct, returns the symbol for it, else null.
 AggregateDeclaration *isAggregate(Type *t);
+Covariant covariant(Type *, Type *, StorageClass * = NULL, bool = false);
diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d
index 22c6e63a465..65f7d2964cb 100644
--- a/gcc/d/dmd/nspace.d
+++ b/gcc/d/dmd/nspace.d
@@ -46,22 +46,14 @@ 
 
 module dmd.nspace;
 
-import dmd.aggregate;
 import dmd.arraytypes;
-import dmd.astenums;
-import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem;
-import dmd.errors;
 import dmd.expression;
-import dmd.globals;
 import dmd.identifier;
 import dmd.location;
 import dmd.visitor;
 import core.stdc.stdio;
 
-private enum LOG = false;
-
 /// Ditto
 extern (C++) final class Nspace : ScopeDsymbol
 {
@@ -91,14 +83,6 @@  extern (C++) final class Nspace : ScopeDsymbol
         return members.foreachDsymbol( (s) { return s.hasPointers(); } ) != 0;
     }
 
-    override void setFieldOffset(AggregateDeclaration ad, ref FieldState fieldState, bool isunion)
-    {
-        //printf("Nspace::setFieldOffset() %s\n", toChars());
-        if (_scope) // if fwd reference
-            dsymbolSemantic(this, null); // try to resolve it
-        members.foreachDsymbol( s => s.setFieldOffset(ad, fieldState, isunion) );
-    }
-
     override const(char)* kind() const
     {
         return "namespace";
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index 701cc935eb5..4a1bd9141ec 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -22,7 +22,6 @@  class Nspace final : public ScopeDsymbol
     Expression *identExp;
     Nspace *syntaxCopy(Dsymbol *s) override;
     bool hasPointers() override;
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
     const char *kind() const override;
     Nspace *isNspace() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index 2cac5f2941b..cceb5a7e3a8 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -130,5 +130,5 @@  struct Scope
     AliasDeclaration *aliasAsg; // if set, then aliasAsg is being assigned a new value,
                                 // do not set wasRead for it
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, int flags = IgnoreNone);
+    Dsymbol *search(const Loc &loc, Identifier *ident, Dsymbol **pscopesym, SearchOptFlags flags = (SearchOptFlags)SearchOpt::all);
 };
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index c255701d767..7498eaf4458 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -520,7 +520,8 @@  private extern(C++) final class Semantic3Visitor : Visitor
                 {
                     Parameter narg = Parameter.getNth(t.arguments, j);
                     assert(narg.ident);
-                    VarDeclaration v = sc2.search(Loc.initial, narg.ident, null).isVarDeclaration();
+                    Dsymbol pscopesym;
+                    VarDeclaration v = sc2.search(Loc.initial, narg.ident, pscopesym).isVarDeclaration();
                     assert(v);
                     (*exps)[j] = new VarExp(v.loc, v);
                 }
diff --git a/gcc/d/dmd/statement.d b/gcc/d/dmd/statement.d
index b5906c8edc3..430454480e1 100644
--- a/gcc/d/dmd/statement.d
+++ b/gcc/d/dmd/statement.d
@@ -20,19 +20,15 @@  import dmd.arraytypes;
 import dmd.astenums;
 import dmd.ast_node;
 import dmd.errors;
-import dmd.gluelayer;
 import dmd.cond;
 import dmd.declaration;
 import dmd.dsymbol;
 import dmd.expression;
 import dmd.func;
-import dmd.globals;
-import dmd.hdrgen;
 import dmd.id;
 import dmd.identifier;
 import dmd.location;
 import dmd.mtype;
-import dmd.common.outbuffer;
 import dmd.rootobject;
 import dmd.sapply;
 import dmd.staticassert;
@@ -333,6 +329,8 @@  extern (C++) final class ErrorStatement : Statement
     extern (D) this()
     {
         super(Loc.initial, STMT.Error);
+
+        import dmd.globals;
         assert(global.gaggedErrors || global.errors);
     }
 
@@ -1773,7 +1771,7 @@  extern (C++) class AsmStatement : Statement
  */
 extern (C++) final class InlineAsmStatement : AsmStatement
 {
-    code* asmcode;
+    void* asmcode;
     uint asmalign;  // alignment of this statement
     uint regs;      // mask of registers modified (must match regm_t in back end)
     bool refparam;  // true if function parameter is referenced
diff --git a/gcc/d/dmd/statement.h b/gcc/d/dmd/statement.h
index ef8423f1cf7..1e493f0d188 100644
--- a/gcc/d/dmd/statement.h
+++ b/gcc/d/dmd/statement.h
@@ -716,7 +716,7 @@  public:
 class InlineAsmStatement final : public AsmStatement
 {
 public:
-    code *asmcode;
+    void *asmcode;
     unsigned asmalign;          // alignment of this statement
     unsigned regs;              // mask of registers modified (must match regm_t in back end)
     d_bool refparam;              // true if function parameter is referenced
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index 3873adc82ee..fcc606b6dd5 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -2261,7 +2261,8 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
                             continue;
                         assert(scx.sw == sw);
 
-                        if (!scx.search(cs.exp.loc, v.ident, null))
+                        Dsymbol pscopesym;
+                        if (!scx.search(cs.exp.loc, v.ident, pscopesym))
                         {
                             error(cs.loc, "`case` variable `%s` declared at %s cannot be declared in `switch` body",
                                 v.toChars(), v.loc.toChars());
@@ -2525,10 +2526,9 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         if (fd.fes)
             fd = fd.fes.func; // fd is now function enclosing foreach
 
-            TypeFunction tf = cast(TypeFunction)fd.type;
-        assert(tf.ty == Tfunction);
+        auto tf = fd.type.isTypeFunction();
 
-        if (rs.exp && rs.exp.op == EXP.variable && (cast(VarExp)rs.exp).var == fd.vresult)
+        if (rs.exp && rs.exp.isVarExp() && rs.exp.isVarExp().var == fd.vresult)
         {
             // return vresult;
             if (sc.fes)
@@ -2616,7 +2616,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
             rs.exp.checkSharedAccess(sc, returnSharedRef);
 
             // for static alias this: https://issues.dlang.org/show_bug.cgi?id=17684
-            if (rs.exp.op == EXP.type)
+            if (rs.exp.isTypeExp())
                 rs.exp = resolveAliasThis(sc, rs.exp);
 
             rs.exp = resolveProperties(sc, rs.exp);
@@ -2632,14 +2632,14 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
 
             // Extract side-effect part
             rs.exp = Expression.extractLast(rs.exp, e0);
-            if (rs.exp.op == EXP.call)
+            if (rs.exp.isCallExp())
                 rs.exp = valueNoDtor(rs.exp);
 
             /* Void-return function can have void / noreturn typed expression
              * on return statement.
              */
             auto texp = rs.exp.type;
-            const convToVoid = texp.ty == Tvoid || texp.ty == Tnoreturn;
+            const convToVoid = texp.ty == Tvoid || texp.isTypeNoreturn();
 
             if (tbret && tbret.ty == Tvoid || convToVoid)
             {
@@ -2688,7 +2688,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
                 {
                     tf.next = rs.exp.type;
                 }
-                else if (tret.ty != Terror && !rs.exp.type.equals(tret))
+                else if (!tret.isTypeError() && !rs.exp.type.equals(tret))
                 {
                     int m1 = rs.exp.type.implicitConvTo(tret);
                     int m2 = tret.implicitConvTo(rs.exp.type);
@@ -2789,7 +2789,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
                 // Found an actual return value before
                 else if (tf.next.ty != Tvoid && !resType.toBasetype().isTypeNoreturn())
                 {
-                    if (tf.next.ty != Terror)
+                    if (!tf.next.isTypeError())
                     {
                         error(rs.loc, "mismatched function return type inference of `void` and `%s`", tf.next.toChars());
                     }
@@ -2807,7 +2807,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
 
             if (tbret.ty != Tvoid && !resType.isTypeNoreturn()) // if non-void return
             {
-                if (tbret.ty != Terror)
+                if (!tbret.isTypeError())
                 {
                     if (e0)
                         error(rs.loc, "expected return type of `%s`, not `%s`", tret.toChars(), resType.toChars());
@@ -2901,7 +2901,7 @@  Statement statementSemanticVisit(Statement s, Scope* sc)
         }
         if (e0)
         {
-            if (e0.op == EXP.declaration || e0.op == EXP.comma)
+            if (e0.isDeclarationExp() || e0.isCommaExp())
             {
                 rs.exp = Expression.combine(e0, rs.exp);
             }
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
index 7f22c4c993a..760c66a415a 100644
--- a/gcc/d/dmd/staticassert.d
+++ b/gcc/d/dmd/staticassert.d
@@ -14,14 +14,11 @@ 
 module dmd.staticassert;
 
 import dmd.arraytypes;
-import dmd.dscope;
 import dmd.dsymbol;
 import dmd.expression;
-import dmd.globals;
 import dmd.location;
 import dmd.id;
 import dmd.identifier;
-import dmd.mtype;
 import dmd.visitor;
 
 /***********************************************************
diff --git a/gcc/d/dmd/template.h b/gcc/d/dmd/template.h
index 44f95ec0ec3..4be136102c2 100644
--- a/gcc/d/dmd/template.h
+++ b/gcc/d/dmd/template.h
@@ -311,7 +311,6 @@  public:
     const char *kind() const override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
     bool hasPointers() override;
-    void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
     const char *toChars() const override;
 
     TemplateMixin *isTemplateMixin() override { return this; }
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 0acadbb4604..aebc0b5512b 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -1665,12 +1665,12 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
             }
             else if (auto ed = sm.isEnumDeclaration())
             {
-                ScopeDsymbol._foreach(null, ed.members, &pushIdentsDg);
+                _foreach(null, ed.members, &pushIdentsDg);
             }
             return 0;
         }
 
-        ScopeDsymbol._foreach(sc, sds.members, &pushIdentsDg);
+        _foreach(sc, sds.members, &pushIdentsDg);
         auto cd = sds.isClassDeclaration();
         if (cd && e.ident == Id.allMembers)
         {
@@ -1684,7 +1684,7 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
                 {
                     auto cb = (*cd.baseclasses)[i].sym;
                     assert(cb);
-                    ScopeDsymbol._foreach(null, cb.members, &pushIdentsDg);
+                    _foreach(null, cb.members, &pushIdentsDg);
                     if (cb.baseclasses.length)
                         pushBaseMembersDg(cb);
                 }
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 2063a954b99..b0e45f4c042 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -228,7 +228,7 @@  private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
 
         Type t = s.getType(); // type symbol, type alias, or type tuple?
         uint errorsave = global.errors;
-        int flags = t is null ? SearchLocalsOnly : IgnorePrivateImports;
+        SearchOptFlags flags = t is null ? SearchOpt.localsOnly : SearchOpt.ignorePrivateImports;
 
         Dsymbol sm = s.searchX(loc, sc, id, flags);
         if (sm)
@@ -380,12 +380,12 @@  private void resolveHelper(TypeQualified mt, const ref Loc loc, Scope* sc, Dsymb
  *  loc = location to print the error messages
  *  sc = the scope where the symbol is located
  *  id = the id of the symbol
- *  flags = the search flags which can be `SearchLocalsOnly` or `IgnorePrivateImports`
+ *  flags = the search flags which can be `SearchLocalsOnly` or `SearchOpt.ignorePrivateImports`
  *
  * Returns:
  *      symbol found, NULL if not
  */
-private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, int flags)
+private Dsymbol searchX(Dsymbol dsym, const ref Loc loc, Scope* sc, RootObject id, SearchOptFlags flags)
 {
     //printf("Dsymbol::searchX(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
     Dsymbol s = dsym.toAlias();
@@ -486,6 +486,529 @@  Expression typeToExpression(Type t)
     }
 }
 
+/********************************
+ * 'args' are being matched to function type 'tf'
+ * Determine match level.
+ * Params:
+ *      tf = function type
+ *      tthis = type of `this` pointer, null if not member function
+ *      argumentList = arguments to function call
+ *      flag = 1: performing a partial ordering match
+ *      pMessage = address to store error message, or null
+ *      sc = context
+ * Returns:
+ *      MATCHxxxx
+ */
+extern (D) MATCH callMatch(TypeFunction tf, Type tthis, ArgumentList argumentList, int flag = 0, const(char)** pMessage = null, Scope* sc = null)
+{
+    //printf("TypeFunction::callMatch() %s\n", tf.toChars());
+    MATCH match = MATCH.exact; // assume exact match
+    ubyte wildmatch = 0;
+
+    if (tthis)
+    {
+        Type t = tthis;
+        if (t.toBasetype().ty == Tpointer)
+            t = t.toBasetype().nextOf(); // change struct* to struct
+        if (t.mod != tf.mod)
+        {
+            if (MODimplicitConv(t.mod, tf.mod))
+                match = MATCH.constant;
+            else if ((tf.mod & MODFlags.wild) && MODimplicitConv(t.mod, (tf.mod & ~MODFlags.wild) | MODFlags.const_))
+            {
+                match = MATCH.constant;
+            }
+            else
+                return MATCH.nomatch;
+        }
+        if (tf.isWild())
+        {
+            if (t.isWild())
+                wildmatch |= MODFlags.wild;
+            else if (t.isConst())
+                wildmatch |= MODFlags.const_;
+            else if (t.isImmutable())
+                wildmatch |= MODFlags.immutable_;
+            else
+                wildmatch |= MODFlags.mutable;
+        }
+    }
+
+    ParameterList* parameterList = &tf.parameterList;
+    const nparams = parameterList.length;
+    if (argumentList.length > nparams)
+    {
+        if (parameterList.varargs == VarArg.none)
+        {
+            // suppress early exit if an error message is wanted,
+            // so we can check any matching args are valid
+            if (!pMessage)
+                return MATCH.nomatch;
+        }
+        // too many args; no match
+        match = MATCH.convert; // match ... with a "conversion" match level
+    }
+
+    // https://issues.dlang.org/show_bug.cgi?id=22997
+    if (parameterList.varargs == VarArg.none && nparams > argumentList.length && !parameterList.hasDefaultArgs)
+    {
+        OutBuffer buf;
+        buf.printf("too few arguments, expected %d, got %d", cast(int)nparams, cast(int)argumentList.length);
+        if (pMessage)
+            *pMessage = buf.extractChars();
+        return MATCH.nomatch;
+    }
+    auto resolvedArgs = tf.resolveNamedArgs(argumentList, pMessage);
+    Expression[] args;
+    if (!resolvedArgs)
+    {
+        if (!pMessage || *pMessage)
+            return MATCH.nomatch;
+
+        // if no message was provided, it was because of overflow which will be diagnosed below
+        match = MATCH.nomatch;
+        args = argumentList.arguments ? (*argumentList.arguments)[] : null;
+    }
+    else
+    {
+        args = (*resolvedArgs)[];
+    }
+
+    foreach (u, p; *parameterList)
+    {
+        if (u >= args.length)
+            break;
+
+        Expression arg = args[u];
+        if (!arg)
+            continue; // default argument
+
+        Type tprm = p.type;
+        Type targ = arg.type;
+
+        if (!(p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid))
+        {
+            const isRef = p.isReference();
+            wildmatch |= targ.deduceWild(tprm, isRef);
+        }
+    }
+    if (wildmatch)
+    {
+        /* Calculate wild matching modifier
+         */
+        if (wildmatch & MODFlags.const_ || wildmatch & (wildmatch - 1))
+            wildmatch = MODFlags.const_;
+        else if (wildmatch & MODFlags.immutable_)
+            wildmatch = MODFlags.immutable_;
+        else if (wildmatch & MODFlags.wild)
+            wildmatch = MODFlags.wild;
+        else
+        {
+            assert(wildmatch & MODFlags.mutable);
+            wildmatch = MODFlags.mutable;
+        }
+    }
+
+    foreach (u, p; *parameterList)
+    {
+        MATCH m;
+
+        assert(p);
+
+        // One or more arguments remain
+        if (u < args.length)
+        {
+            Expression arg = args[u];
+            if (!arg)
+                continue; // default argument
+            m = argumentMatchParameter(tf, p, arg, wildmatch, flag, sc, pMessage);
+        }
+        else if (p.defaultArg)
+            continue;
+
+        /* prefer matching the element type rather than the array
+         * type when more arguments are present with T[]...
+         */
+        if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams && args.length > nparams)
+            goto L1;
+
+        //printf("\tm = %d\n", m);
+        if (m == MATCH.nomatch) // if no match
+        {
+        L1:
+            if (parameterList.varargs == VarArg.typesafe && u + 1 == nparams) // if last varargs param
+            {
+                auto trailingArgs = args[u .. $];
+                if (auto vmatch = matchTypeSafeVarArgs(tf, p, trailingArgs, pMessage))
+                    return vmatch < match ? vmatch : match;
+                // Error message was already generated in `matchTypeSafeVarArgs`
+                return MATCH.nomatch;
+            }
+            if (pMessage && u >= args.length)
+                *pMessage = tf.getMatchError("missing argument for parameter #%d: `%s`",
+                    u + 1, parameterToChars(p, tf, false));
+            // If an error happened previously, `pMessage` was already filled
+            else if (pMessage && !*pMessage)
+                *pMessage = tf.getParamError(args[u], p);
+
+            return MATCH.nomatch;
+        }
+        if (m < match)
+            match = m; // pick worst match
+    }
+
+    if (pMessage && !parameterList.varargs && args.length > nparams)
+    {
+        // all parameters had a match, but there are surplus args
+        *pMessage = tf.getMatchError("expected %d argument(s), not %d", nparams, args.length);
+        return MATCH.nomatch;
+    }
+    //printf("match = %d\n", match);
+    return match;
+}
+
+/**
+ * Used by `callMatch` to check if the copy constructor may be called to
+ * copy the argument
+ *
+ * This is done by seeing if a call to the copy constructor can be made:
+ * ```
+ * typeof(tprm) __copytmp;
+ * copytmp.__copyCtor(arg);
+ * ```
+ */
+private extern(D) bool isCopyConstructorCallable (StructDeclaration argStruct,
+    Expression arg, Type tprm, Scope* sc, const(char)** pMessage)
+{
+    auto tmp = new VarDeclaration(arg.loc, tprm, Identifier.generateId("__copytmp"), null);
+    tmp.storage_class = STC.rvalue | STC.temp | STC.ctfe;
+    tmp.dsymbolSemantic(sc);
+    Expression ve = new VarExp(arg.loc, tmp);
+    Expression e = new DotIdExp(arg.loc, ve, Id.ctor);
+    e = new CallExp(arg.loc, e, arg);
+    //printf("e = %s\n", e.toChars());
+    if (.trySemantic(e, sc))
+        return true;
+
+    if (pMessage)
+    {
+        /* https://issues.dlang.org/show_bug.cgi?id=22202
+         *
+         * If a function was deduced by semantic on the CallExp,
+         * it means that resolveFuncCall completed succesfully.
+         * Therefore, there exists a callable copy constructor,
+         * however, it cannot be called because scope constraints
+         * such as purity, safety or nogc.
+         */
+        OutBuffer buf;
+        auto callExp = e.isCallExp();
+        if (auto f = callExp.f)
+        {
+            char[] s;
+            if (!f.isPure && sc.func.setImpure())
+                s ~= "pure ";
+            if (!f.isSafe() && !f.isTrusted() && sc.setUnsafe())
+                s ~= "@safe ";
+            if (!f.isNogc && sc.func.setGC(arg.loc, null))
+                s ~= "nogc ";
+            if (s)
+            {
+                s[$-1] = '\0';
+                buf.printf("`%s` copy constructor cannot be called from a `%s` context", f.type.toChars(), s.ptr);
+            }
+            else if (f.isGenerated() && f.isDisabled())
+            {
+                /* https://issues.dlang.org/show_bug.cgi?id=23097
+                 * Compiler generated copy constructor failed.
+                 */
+                buf.printf("generating a copy constructor for `struct %s` failed, therefore instances of it are uncopyable",
+                           argStruct.toChars());
+            }
+            else
+            {
+                /* Although a copy constructor may exist, no suitable match was found.
+                 * i.e: `inout` constructor creates `const` object, not mutable.
+                 * Fallback to using the original generic error before https://issues.dlang.org/show_bug.cgi?id=22202.
+                 */
+                goto Lnocpctor;
+            }
+        }
+        else
+        {
+        Lnocpctor:
+            buf.printf("`struct %s` does not define a copy constructor for `%s` to `%s` copies",
+                       argStruct.toChars(), arg.type.toChars(), tprm.toChars());
+        }
+
+        *pMessage = buf.extractChars();
+    }
+    return false;
+}
+
+/**
+ * Match a single parameter to an argument.
+ *
+ * This function is called by `TypeFunction.callMatch` while iterating over
+ * the list of parameter. Here we check if `arg` is a match for `p`,
+ * which is mostly about checking if `arg.type` converts to `p`'s type
+ * and some check about value reference.
+ *
+ * Params:
+ *   tf = The `TypeFunction`, only used for error reporting
+ *   p = The parameter of `tf` being matched
+ *   arg = Argument being passed (bound) to `p`
+ *   wildmatch = Wild (`inout`) matching level, derived from the full argument list
+ *   flag = A non-zero value means we're doing a partial ordering check
+ *          (no value semantic check)
+ *   sc = Scope we are in
+ *   pMessage = A buffer to write the error in, or `null`
+ *
+ * Returns: Whether `trailingArgs` match `p`.
+ */
+private extern(D) MATCH argumentMatchParameter (TypeFunction tf, Parameter p,
+    Expression arg, ubyte wildmatch, int flag, Scope* sc, const(char)** pMessage)
+{
+    //printf("arg: %s, type: %s\n", arg.toChars(), arg.type.toChars());
+    MATCH m;
+    Type targ = arg.type;
+    Type tprm = wildmatch ? p.type.substWildTo(wildmatch) : p.type;
+
+    if (p.isLazy() && tprm.ty == Tvoid && targ.ty != Tvoid)
+        m = MATCH.convert;
+    else if (flag)
+    {
+        // for partial ordering, value is an irrelevant mockup, just look at the type
+        m = targ.implicitConvTo(tprm);
+    }
+    else
+    {
+        const isRef = p.isReference();
+        StructDeclaration argStruct, prmStruct;
+
+        // first look for a copy constructor
+        if (arg.isLvalue() && !isRef && targ.ty == Tstruct && tprm.ty == Tstruct)
+        {
+            // if the argument and the parameter are of the same unqualified struct type
+            argStruct = (cast(TypeStruct)targ).sym;
+            prmStruct = (cast(TypeStruct)tprm).sym;
+        }
+
+        // check if the copy constructor may be called to copy the argument
+        if (argStruct && argStruct == prmStruct && argStruct.hasCopyCtor)
+        {
+            if (!isCopyConstructorCallable(argStruct, arg, tprm, sc, pMessage))
+                return MATCH.nomatch;
+            m = MATCH.exact;
+        }
+        else
+        {
+            import dmd.dcast : cimplicitConvTo;
+            m = (sc && sc.flags & SCOPE.Cfile) ? arg.cimplicitConvTo(tprm) : arg.implicitConvTo(tprm);
+        }
+    }
+
+    // Non-lvalues do not match ref or out parameters
+    if (p.isReference())
+    {
+        // https://issues.dlang.org/show_bug.cgi?id=13783
+        // Don't use toBasetype() to handle enum types.
+        Type ta = targ;
+        Type tp = tprm;
+        //printf("fparam[%d] ta = %s, tp = %s\n", u, ta.toChars(), tp.toChars());
+
+        if (m && !arg.isLvalue())
+        {
+            if (p.storageClass & STC.out_)
+            {
+                if (pMessage) *pMessage = tf.getParamError(arg, p);
+                return MATCH.nomatch;
+            }
+
+            if (arg.op == EXP.string_ && tp.ty == Tsarray)
+            {
+                if (ta.ty != Tsarray)
+                {
+                    Type tn = tp.nextOf().castMod(ta.nextOf().mod);
+                    dinteger_t dim = (cast(StringExp)arg).len;
+                    ta = tn.sarrayOf(dim);
+                }
+            }
+            else if (arg.op == EXP.slice && tp.ty == Tsarray)
+            {
+                // Allow conversion from T[lwr .. upr] to ref T[upr-lwr]
+                if (ta.ty != Tsarray)
+                {
+                    Type tn = ta.nextOf();
+                    dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+                    ta = tn.sarrayOf(dim);
+                }
+            }
+            else if ((p.storageClass & STC.in_) && global.params.previewIn)
+            {
+                // Allow converting a literal to an `in` which is `ref`
+                if (arg.op == EXP.arrayLiteral && tp.ty == Tsarray)
+                {
+                    Type tn = tp.nextOf();
+                    dinteger_t dim = (cast(TypeSArray)tp).dim.toUInteger();
+                    ta = tn.sarrayOf(dim);
+                }
+
+                // Need to make this a rvalue through a temporary
+                m = MATCH.convert;
+            }
+            else if (global.params.rvalueRefParam != FeatureState.enabled ||
+                     p.storageClass & STC.out_ ||
+                     !arg.type.isCopyable())  // can't copy to temp for ref parameter
+            {
+                if (pMessage) *pMessage = tf.getParamError(arg, p);
+                return MATCH.nomatch;
+            }
+            else
+            {
+                /* in functionParameters() we'll convert this
+                 * rvalue into a temporary
+                 */
+                m = MATCH.convert;
+            }
+        }
+
+        /* If the match is not already perfect or if the arg
+           is not a lvalue then try the `alias this` chain
+           see  https://issues.dlang.org/show_bug.cgi?id=15674
+           and https://issues.dlang.org/show_bug.cgi?id=21905
+        */
+        if (ta != tp || !arg.isLvalue())
+        {
+            Type firsttab = ta.toBasetype();
+            while (1)
+            {
+                Type tab = ta.toBasetype();
+                Type tat = tab.aliasthisOf();
+                if (!tat || !tat.implicitConvTo(tprm))
+                    break;
+                if (tat == tab || tat == firsttab)
+                    break;
+                ta = tat;
+            }
+        }
+
+        /* A ref variable should work like a head-const reference.
+         * e.g. disallows:
+         *  ref T      <- an lvalue of const(T) argument
+         *  ref T[dim] <- an lvalue of const(T[dim]) argument
+         */
+        if (!ta.constConv(tp))
+        {
+            if (pMessage) *pMessage = tf.getParamError(arg, p);
+            return MATCH.nomatch;
+        }
+    }
+    return m;
+}
+
+// arguments get specially formatted
+private const(char)* getParamError(TypeFunction tf, Expression arg, Parameter par)
+{
+    if (global.gag && !global.params.v.showGaggedErrors)
+        return null;
+    // show qualification when toChars() is the same but types are different
+    // https://issues.dlang.org/show_bug.cgi?id=19948
+    // when comparing the type with strcmp, we need to drop the qualifier
+    bool qual = !arg.type.mutableOf().equals(par.type.mutableOf()) &&
+        strcmp(arg.type.mutableOf().toChars(), par.type.mutableOf().toChars()) == 0;
+    auto at = qual ? arg.type.toPrettyChars(true) : arg.type.toChars();
+    OutBuffer buf;
+    // only mention rvalue if it's relevant
+    const rv = !arg.isLvalue() && par.isReference();
+    buf.printf("cannot pass %sargument `%s` of type `%s` to parameter `%s`",
+        rv ? "rvalue ".ptr : "".ptr, arg.toChars(), at,
+        parameterToChars(par, tf, qual));
+    return buf.extractChars();
+}
+
+/**
+ * Match the remaining arguments `trailingArgs` with parameter `p`.
+ *
+ * Assume we already checked that `p` is the last parameter of `tf`,
+ * and we want to know whether the arguments would match `p`.
+ *
+ * Params:
+ *   tf = The `TypeFunction`, only used for error reporting
+ *   p = The last parameter of `tf` which is variadic
+ *   trailingArgs = The remaining arguments that should match `p`
+ *   pMessage = A buffer to write the error in, or `null`
+ *
+ * Returns: Whether `trailingArgs` match `p`.
+ */
+private extern(D) MATCH matchTypeSafeVarArgs(TypeFunction tf, Parameter p,
+    Expression[] trailingArgs, const(char)** pMessage)
+{
+    Type tb = p.type.toBasetype();
+
+    switch (tb.ty)
+    {
+    case Tsarray:
+        TypeSArray tsa = cast(TypeSArray)tb;
+        dinteger_t sz = tsa.dim.toInteger();
+        if (sz != trailingArgs.length)
+        {
+            if (pMessage)
+                *pMessage = tf.getMatchError("expected %llu variadic argument(s), not %zu",
+                    sz, trailingArgs.length);
+            return MATCH.nomatch;
+        }
+        goto case Tarray;
+    case Tarray:
+    {
+        MATCH match = MATCH.exact;
+        TypeArray ta = cast(TypeArray)tb;
+        foreach (arg; trailingArgs)
+        {
+            MATCH m;
+            assert(arg);
+
+            /* If lazy array of delegates,
+             * convert arg(s) to delegate(s)
+             */
+            Type tret = p.isLazyArray();
+            if (tret)
+            {
+                if (ta.next.equals(arg.type))
+                    m = MATCH.exact;
+                else if (tret.toBasetype().ty == Tvoid)
+                    m = MATCH.convert;
+                else
+                {
+                    m = arg.implicitConvTo(tret);
+                    if (m == MATCH.nomatch)
+                        m = arg.implicitConvTo(ta.next);
+                }
+            }
+            else
+                m = arg.implicitConvTo(ta.next);
+
+            if (m == MATCH.nomatch)
+            {
+                if (pMessage) *pMessage = tf.getParamError(arg, p);
+                return MATCH.nomatch;
+            }
+            if (m < match)
+                match = m;
+        }
+        return match;
+    }
+    case Tclass:
+        // We leave it up to the actual constructor call to do the matching.
+        return MATCH.exact;
+
+    default:
+        // We can have things as `foo(int[int] wat...)` but they only match
+        // with an associative array proper.
+        if (pMessage && trailingArgs.length) *pMessage = tf.getParamError(trailingArgs[0], p);
+        return MATCH.nomatch;
+    }
+}
+
 /******************************************
  * Perform semantic analysis on a type.
  * Params:
@@ -1878,7 +2401,7 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
         /* look for pre-existing declaration
          */
         Dsymbol scopesym;
-        auto s = sc2.search(mtype.loc, mtype.id, &scopesym, IgnoreErrors | TagNameSpace);
+        auto s = sc2.search(mtype.loc, mtype.id, scopesym, SearchOpt.ignoreErrors | SearchOpt.tagNameSpace);
         if (!s || s.isModule())
         {
             // no pre-existing declaration, so declare it
@@ -2753,7 +3276,7 @@  void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
         }
 
         Dsymbol scopesym;
-        Dsymbol s = sc.search(loc, mt.ident, &scopesym);
+        Dsymbol s = sc.search(loc, mt.ident, scopesym);
         /*
          * https://issues.dlang.org/show_bug.cgi?id=1170
          * https://issues.dlang.org/show_bug.cgi?id=10739
@@ -2776,7 +3299,7 @@  void resolve(Type mt, const ref Loc loc, Scope* sc, out Expression pe, out Type
                         mixinTempl.dsymbolSemantic(sc);
                 }
                 sds.members.foreachDsymbol( s => semanticOnMixin(s) );
-                s = sc.search(loc, mt.ident, &scopesym);
+                s = sc.search(loc, mt.ident, scopesym);
             }
         }
 
@@ -3794,8 +4317,8 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
             return e;
         }
 
-        immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
-        s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+        immutable flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : 0;
+        s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
     L1:
         if (!s)
         {
@@ -4074,8 +4597,8 @@  Expression dotExp(Type mt, Scope* sc, Expression e, Identifier ident, DotExpFlag
             return e;
         }
 
-        int flags = sc.flags & SCOPE.ignoresymbolvisibility ? IgnoreSymbolVisibility : 0;
-        s = mt.sym.search(e.loc, ident, flags | IgnorePrivateImports);
+        SearchOptFlags flags = sc.flags & SCOPE.ignoresymbolvisibility ? SearchOpt.ignoreVisibility : SearchOpt.all;
+        s = mt.sym.search(e.loc, ident, flags | SearchOpt.ignorePrivateImports);
 
     L1:
         if (!s)
@@ -4723,7 +5246,7 @@  Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
         return *pt;
     }
 
-    Dsymbol s = mConfig.searchX(Loc.initial, sc, id, IgnorePrivateImports);
+    Dsymbol s = mConfig.searchX(Loc.initial, sc, id, SearchOpt.ignorePrivateImports);
     if (!s)
     {
         error(loc, "`%s` not found in core.stdc.config", id.toChars());
@@ -4748,6 +5271,263 @@  Type getComplexLibraryType(const ref Loc loc, Scope* sc, TY ty)
     return *pt;
 }
 
+/*******************************
+ * Covariant means that 'src' can substitute for 't',
+ * i.e. a pure function is a match for an impure type.
+ * Params:
+ *      src = source type
+ *      t = type 'src' is covariant with
+ *      pstc = if not null, store STCxxxx which would make it covariant
+ *      cppCovariant = true if extern(C++) function types should follow C++ covariant rules
+ * Returns:
+ *     An enum value of either `Covariant.yes` or a reason it's not covariant.
+ */
+extern (C++) Covariant covariant(Type src, Type t, StorageClass* pstc = null, bool cppCovariant = false)
+{
+    version (none)
+    {
+        printf("Type::covariant(t = %s) %s\n", t.toChars(), src.toChars());
+        printf("deco = %p, %p\n", src.deco, t.deco);
+        //    printf("ty = %d\n", next.ty);
+        printf("mod = %x, %x\n", src.mod, t.mod);
+    }
+    if (pstc)
+        *pstc = 0;
+    StorageClass stc = 0;
+
+    bool notcovariant = false;
+
+    if (src.equals(t))
+        return Covariant.yes;
+
+    TypeFunction t1 = src.isTypeFunction();
+    TypeFunction t2 = t.isTypeFunction();
+
+    if (!t1 || !t2)
+        goto Ldistinct;
+
+    if (t1.parameterList.varargs != t2.parameterList.varargs)
+        goto Ldistinct;
+
+    if (t1.parameterList.parameters && t2.parameterList.parameters)
+    {
+        if (t1.parameterList.length != t2.parameterList.length)
+            goto Ldistinct;
+
+        foreach (i, fparam1; t1.parameterList)
+        {
+            Parameter fparam2 = t2.parameterList[i];
+            Type tp1 = fparam1.type;
+            Type tp2 = fparam2.type;
+
+            if (!tp1.equals(tp2))
+            {
+                if (tp1.ty == tp2.ty)
+                {
+                    if (auto tc1 = tp1.isTypeClass())
+                    {
+                        if (tc1.sym == (cast(TypeClass)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+                            goto Lcov;
+                    }
+                    else if (auto ts1 = tp1.isTypeStruct())
+                    {
+                        if (ts1.sym == (cast(TypeStruct)tp2).sym && MODimplicitConv(tp2.mod, tp1.mod))
+                            goto Lcov;
+                    }
+                    else if (tp1.ty == Tpointer)
+                    {
+                        if (tp2.implicitConvTo(tp1))
+                            goto Lcov;
+                    }
+                    else if (tp1.ty == Tarray)
+                    {
+                        if (tp2.implicitConvTo(tp1))
+                            goto Lcov;
+                    }
+                    else if (tp1.ty == Tdelegate)
+                    {
+                        if (tp2.implicitConvTo(tp1))
+                            goto Lcov;
+                    }
+                }
+                goto Ldistinct;
+            }
+        Lcov:
+            notcovariant |= !fparam1.isCovariant(t1.isref, fparam2);
+
+            /* https://issues.dlang.org/show_bug.cgi?id=23135
+             * extern(C++) mutable parameters are not covariant with const.
+             */
+            if (t1.linkage == LINK.cpp && cppCovariant)
+            {
+                notcovariant |= tp1.isNaked() != tp2.isNaked();
+                if (auto tpn1 = tp1.nextOf())
+                    notcovariant |= tpn1.isNaked() != tp2.nextOf().isNaked();
+            }
+        }
+    }
+    else if (t1.parameterList.parameters != t2.parameterList.parameters)
+    {
+        if (t1.parameterList.length || t2.parameterList.length)
+            goto Ldistinct;
+    }
+
+    // The argument lists match
+    if (notcovariant)
+        goto Lnotcovariant;
+    if (t1.linkage != t2.linkage)
+        goto Lnotcovariant;
+
+    {
+        // Return types
+        Type t1n = t1.next;
+        Type t2n = t2.next;
+
+        if (!t1n || !t2n) // happens with return type inference
+            goto Lnotcovariant;
+
+        if (t1n.equals(t2n))
+            goto Lcovariant;
+        if (t1n.ty == Tclass && t2n.ty == Tclass)
+        {
+            /* If same class type, but t2n is const, then it's
+             * covariant. Do this test first because it can work on
+             * forward references.
+             */
+            if ((cast(TypeClass)t1n).sym == (cast(TypeClass)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+                goto Lcovariant;
+
+            // If t1n is forward referenced:
+            ClassDeclaration cd = (cast(TypeClass)t1n).sym;
+            if (cd.semanticRun < PASS.semanticdone && !cd.isBaseInfoComplete())
+                cd.dsymbolSemantic(null);
+            if (!cd.isBaseInfoComplete())
+            {
+                return Covariant.fwdref;
+            }
+        }
+        if (t1n.ty == Tstruct && t2n.ty == Tstruct)
+        {
+            if ((cast(TypeStruct)t1n).sym == (cast(TypeStruct)t2n).sym && MODimplicitConv(t1n.mod, t2n.mod))
+                goto Lcovariant;
+        }
+        else if (t1n.ty == t2n.ty && t1n.implicitConvTo(t2n))
+        {
+            if (t1.isref && t2.isref)
+            {
+                // Treat like pointers to t1n and t2n
+                if (t1n.constConv(t2n) < MATCH.constant)
+                    goto Lnotcovariant;
+            }
+            goto Lcovariant;
+        }
+        else if (t1n.ty == Tnull)
+        {
+            // NULL is covariant with any pointer type, but not with any
+            // dynamic arrays, associative arrays or delegates.
+            // https://issues.dlang.org/show_bug.cgi?id=8589
+            // https://issues.dlang.org/show_bug.cgi?id=19618
+            Type t2bn = t2n.toBasetype();
+            if (t2bn.ty == Tnull || t2bn.ty == Tpointer || t2bn.ty == Tclass)
+                goto Lcovariant;
+        }
+        // bottom type is covariant to any type
+        else if (t1n.ty == Tnoreturn)
+            goto Lcovariant;
+    }
+    goto Lnotcovariant;
+
+Lcovariant:
+    if (t1.isref != t2.isref)
+        goto Lnotcovariant;
+
+    if (!t1.isref && (t1.isScopeQual || t2.isScopeQual))
+    {
+        StorageClass stc1 = t1.isScopeQual ? STC.scope_ : 0;
+        StorageClass stc2 = t2.isScopeQual ? STC.scope_ : 0;
+        if (t1.isreturn)
+        {
+            stc1 |= STC.return_;
+            if (!t1.isScopeQual)
+                stc1 |= STC.ref_;
+        }
+        if (t2.isreturn)
+        {
+            stc2 |= STC.return_;
+            if (!t2.isScopeQual)
+                stc2 |= STC.ref_;
+        }
+        if (!Parameter.isCovariantScope(t1.isref, stc1, stc2))
+            goto Lnotcovariant;
+    }
+
+    // We can subtract 'return ref' from 'this', but cannot add it
+    else if (t1.isreturn && !t2.isreturn)
+        goto Lnotcovariant;
+
+    /* https://issues.dlang.org/show_bug.cgi?id=23135
+     * extern(C++) mutable member functions are not covariant with const.
+     */
+    if (t1.linkage == LINK.cpp && cppCovariant && t1.isNaked() != t2.isNaked())
+        goto Lnotcovariant;
+
+    /* Can convert mutable to const
+     */
+    if (!MODimplicitConv(t2.mod, t1.mod))
+    {
+        version (none)
+        {
+            //stop attribute inference with const
+            // If adding 'const' will make it covariant
+            if (MODimplicitConv(t2.mod, MODmerge(t1.mod, MODFlags.const_)))
+                stc |= STC.const_;
+            else
+                goto Lnotcovariant;
+        }
+        else
+        {
+            goto Ldistinct;
+        }
+    }
+
+    /* Can convert pure to impure, nothrow to throw, and nogc to gc
+     */
+    if (!t1.purity && t2.purity)
+        stc |= STC.pure_;
+
+    if (!t1.isnothrow && t2.isnothrow)
+        stc |= STC.nothrow_;
+
+    if (!t1.isnogc && t2.isnogc)
+        stc |= STC.nogc;
+
+    /* Can convert safe/trusted to system
+     */
+    if (t1.trust <= TRUST.system && t2.trust >= TRUST.trusted)
+    {
+        // Should we infer trusted or safe? Go with safe.
+        stc |= STC.safe;
+    }
+
+    if (stc)
+    {
+        if (pstc)
+            *pstc = stc;
+        goto Lnotcovariant;
+    }
+
+    //printf("\tcovaraint: 1\n");
+    return Covariant.yes;
+
+Ldistinct:
+    //printf("\tcovaraint: 0\n");
+    return Covariant.distinct;
+
+Lnotcovariant:
+    //printf("\tcovaraint: 2\n");
+    return Covariant.no;
+}
+
 /******************************* Private *****************************************/
 
 private:
diff --git a/gcc/d/gdc.texi b/gcc/d/gdc.texi
index e6a8a906161..fe1c62553cc 100644
--- a/gcc/d/gdc.texi
+++ b/gcc/d/gdc.texi
@@ -740,8 +740,10 @@  arguments like @code{va_start}.
 
 @opindex fignore-unknown-pragmas
 @opindex fno-ignore-unknown-pragmas
-@item -fignore-unknown-pragmas
-Turns off errors for unsupported pragmas.
+@item -fno-ignore-unknown-pragmas
+Do not recognize unsupported pragmas.  Any @code{pragma()} encountered that is
+not part of the D language will result in an error.  This option is now
+deprecated and will be removed in a future release.
 
 @opindex fmax-errors
 @item -fmax-errors=@var{n}
diff --git a/gcc/d/typeinfo.cc b/gcc/d/typeinfo.cc
index f671131413e..257a2abe5d7 100644
--- a/gcc/d/typeinfo.cc
+++ b/gcc/d/typeinfo.cc
@@ -20,6 +20,7 @@  along with GCC; see the file COPYING3.  If not see
 #include "coretypes.h"
 
 #include "dmd/aggregate.h"
+#include "dmd/dsymbol.h"
 #include "dmd/enum.h"
 #include "dmd/errors.h"
 #include "dmd/expression.h"
@@ -205,7 +206,7 @@  make_frontend_typeinfo (Identifier *ident, ClassDeclaration *base = NULL)
 
   /* Create object module in order to complete the semantic.  */
   if (!object_module->_scope)
-    object_module->importAll (NULL);
+    importAll (object_module, NULL);
 
   /* Object class doesn't exist, create a stub one that will cause an error if
      used.  */
diff --git a/gcc/testsuite/gdc.test/compilable/imports/defines.c b/gcc/testsuite/gdc.test/compilable/imports/defines.c
index 6bd07366544..8a5601a2d08 100644
--- a/gcc/testsuite/gdc.test/compilable/imports/defines.c
+++ b/gcc/testsuite/gdc.test/compilable/imports/defines.c
@@ -26,3 +26,7 @@  _Static_assert(F80 == 9.0L, "9");
 
 #define SSS "hello"
 _Static_assert(SSS[0] == 'h', "10");
+
+#define ABC 12
+#define GHI (size) abbadabba
+#define DEF (ABC + 5)
diff --git a/gcc/testsuite/gdc.test/compilable/test9565.d b/gcc/testsuite/gdc.test/compilable/test9565.d
deleted file mode 100644
index 9e3ee6a8170..00000000000
--- a/gcc/testsuite/gdc.test/compilable/test9565.d
+++ /dev/null
@@ -1,86 +0,0 @@ 
-// REQUIRED_ARGS: -o-
-// PERMUTE_ARGS:
-
-template TypeTuple(T...) { alias TypeTuple = T; }
-
-bool startsWith(string s, string m) { return s[0 .. m.length] == m; }
-
-void main()
-{
-    enum string castPrefix = "cast(" ~ size_t.stringof ~ ")";
-
-    // TypeSArray
-    static assert((int[10]).stringof == "int[10]", T.stringof);
-
-    int[] arr;
-
-    // IndexExp
-    {
-        // index == IntegerExp
-        static assert((arr[ 4  ]).stringof == "arr[4]");
-        static assert((arr[ 4U ]).stringof == "arr[4]");
-        static assert((arr[ 4L ]).stringof == "arr[4]");
-        static assert((arr[ 4LU]).stringof == "arr[4]");
-
-        // index == UAddExp
-        static assert((arr[+4  ]).stringof == "arr[4]");
-        static assert((arr[+4U ]).stringof == "arr[4]");
-        static assert((arr[+4L ]).stringof == "arr[4]");
-        static assert((arr[+4LU]).stringof == "arr[4]");
-
-        // index == NegExp
-        static assert((arr[-4  ]).stringof == "arr[" ~ castPrefix ~ "-4]");
-        static assert((arr[-4U ]).stringof == "arr[4294967292]");
-        static assert((arr[int.min] ).stringof == "arr[" ~ castPrefix ~ "-2147483648]");
-      static if (is(size_t == ulong))
-      {
-        static assert((arr[-4L ]).stringof == "arr[" ~ castPrefix ~ "-4L]");
-        static assert((arr[-4LU]).stringof == "arr[-4LU]");
-
-        // IntegerLiteral needs suffix if the value is greater than long.max
-        static assert((arr[long.max + 0]).stringof == "arr[9223372036854775807]");
-        static assert((arr[long.max + 1]).stringof == "arr[" ~ castPrefix ~ "(9223372036854775807L + 1L)]");
-      }
-
-        foreach (Int; TypeTuple!(byte, ubyte, short, ushort, int, uint, long, ulong))
-        {
-            enum Int p4 = +4;
-            enum string result1 = (arr[p4]).stringof;
-            static assert(result1 == "arr[4]");
-
-            enum string result2 = (arr[cast(Int)+4]).stringof;
-            static assert(result2 == "arr[4]");
-        }
-        foreach (Int; TypeTuple!(byte, short, int, long))
-        {
-            // keep "cast(Type)" in the string representation
-
-            enum Int m4 = -4;
-            static if (is(typeof({ size_t x = m4; })))
-            {
-                enum string result1 = (arr[m4]).stringof;
-                static assert(result1.startsWith("arr[" ~ castPrefix));
-            }
-            else
-                static assert(!__traits(compiles, arr[m4]));
-
-            enum string result2 = (arr[cast(Int)-4]).stringof;
-            static assert(result2.startsWith("arr[" ~ castPrefix));
-        }
-    }
-
-    // SliceExp
-    {
-        // lwr,upr == IntegerExp
-        static assert((arr[4   .. 8  ]).stringof == "arr[4..8]");
-        static assert((arr[4U  .. 8U ]).stringof == "arr[4..8]");
-        static assert((arr[4L  .. 8L ]).stringof == "arr[4..8]");
-        static assert((arr[4LU .. 8LU]).stringof == "arr[4..8]");
-
-        // lwr,upr == UAddExp
-        static assert((arr[+4   .. +8  ]).stringof == "arr[4..8]");
-        static assert((arr[+4U  .. +8U ]).stringof == "arr[4..8]");
-        static assert((arr[+4L  .. +8L ]).stringof == "arr[4..8]");
-        static assert((arr[+4LU .. +8LU]).stringof == "arr[4..8]");
-    }
-}
diff --git a/gcc/testsuite/gdc.test/compilable/testdefines.d b/gcc/testsuite/gdc.test/compilable/testdefines.d
index 4507266c751..9dd8cf2af8d 100644
--- a/gcc/testsuite/gdc.test/compilable/testdefines.d
+++ b/gcc/testsuite/gdc.test/compilable/testdefines.d
@@ -12,3 +12,6 @@  static assert(F64 == 8.0);
 static assert(F80 == 9.0L);
 
 static assert(SSS == "hello");
+
+static assert(ABC == 12);
+static assert(DEF == 17);
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
index d4da11604fa..9b984961f33 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890a.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
+fail_compilation/fail19890a.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
index f4a5dada2c8..19081d95871 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail19890b.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
+fail_compilation/fail19890b.d(8): Error: `void[$n$$?:64=LU$]` size 1 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
index 030c47c69ca..04adf13f5e7 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail4611.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32=0x1000000|0x7fffffff$ size limit for static array
+fail_compilation/fail4611.d(15): Error: `Vec[$n$]` size 4 * $n$ exceeds $?:windows+32omf=0x1000000|0x7fffffff$ size limit for static array
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
index 5a4b5d95d07..d967ab5451b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/pragmas.d
@@ -5,7 +5,6 @@  TEST_OUTPUT:
 ---
 fail_compilation/pragmas.d(103): Error: one boolean expression expected for `pragma(inline)`, not 2
 fail_compilation/pragmas.d(108): Error: one boolean expression expected for `pragma(inline)`, not 2
-fail_compilation/pragmas.d(118): Error: unrecognized `pragma(unrecognized)`
 ---
 */
 
@@ -28,5 +27,5 @@  void test3()
 
 void test4()
 {
-    pragma(unrecognized, "string");
+    pragma(unrecognized, "string"); // permitted, just ignored
 }
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 5edcee1c84d..fa7004b7a41 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-2bbf64907cbbb483d003e0a8fcf8b502e4883799
+f1a045928e03239b9477f9497f43f2cf0e61e959
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/libphobos/libdruntime/Makefile.am b/libphobos/libdruntime/Makefile.am
index 5e4c5ac0260..3ef98dcc737 100644
--- a/libphobos/libdruntime/Makefile.am
+++ b/libphobos/libdruntime/Makefile.am
@@ -202,26 +202,26 @@  DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
 	core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
 	core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
 	core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
-	core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
-	core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
-	core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
-	core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
-	core/sync/config.d core/sync/event.d core/sync/exception.d \
-	core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
-	core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
-	core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
-	core/thread/threadgroup.d core/thread/types.d core/time.d \
-	core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
-	gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
-	gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
-	gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
-	gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
-	gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
-	rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
-	rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
-	rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
-	rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
-	rt/util/utility.d
+	core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
+	core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
+	core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
+	core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
+	core/sync/condition.d core/sync/config.d core/sync/event.d \
+	core/sync/exception.d core/sync/mutex.d core/sync/package.d \
+	core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
+	core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
+	core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
+	core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
+	gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
+	gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
+	gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
+	gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
+	gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
+	gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
+	rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
+	rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
+	rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
+	rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
 
 DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
 	core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \
diff --git a/libphobos/libdruntime/Makefile.in b/libphobos/libdruntime/Makefile.in
index 9c29e203467..1d2bd66817d 100644
--- a/libphobos/libdruntime/Makefile.in
+++ b/libphobos/libdruntime/Makefile.in
@@ -225,23 +225,24 @@  am__objects_1 = core/atomic.lo core/attribute.lo core/bitop.lo \
 	core/stdc/config.lo core/stdc/ctype.lo core/stdc/errno.lo \
 	core/stdc/fenv.lo core/stdc/float_.lo core/stdc/inttypes.lo \
 	core/stdc/limits.lo core/stdc/locale.lo core/stdc/math.lo \
-	core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stddef.lo \
-	core/stdc/stdint.lo core/stdc/stdio.lo core/stdc/stdlib.lo \
-	core/stdc/string.lo core/stdc/tgmath.lo core/stdc/time.lo \
-	core/stdc/wchar_.lo core/stdc/wctype.lo core/sync/barrier.lo \
-	core/sync/condition.lo core/sync/config.lo core/sync/event.lo \
-	core/sync/exception.lo core/sync/mutex.lo core/sync/package.lo \
-	core/sync/rwmutex.lo core/sync/semaphore.lo \
-	core/thread/context.lo core/thread/fiber.lo \
-	core/thread/osthread.lo core/thread/package.lo \
-	core/thread/threadbase.lo core/thread/threadgroup.lo \
-	core/thread/types.lo core/time.lo core/vararg.lo \
-	core/volatile.lo etc/valgrind/valgrind.lo gcc/attribute.lo \
-	gcc/attributes.lo gcc/backtrace.lo gcc/builtins.lo gcc/deh.lo \
-	gcc/emutls.lo gcc/gthread.lo gcc/sections/common.lo \
-	gcc/sections/elf.lo gcc/sections/macho.lo \
-	gcc/sections/package.lo gcc/sections/pecoff.lo gcc/simd.lo \
-	gcc/unwind/arm.lo gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
+	core/stdc/signal.lo core/stdc/stdarg.lo core/stdc/stdatomic.lo \
+	core/stdc/stddef.lo core/stdc/stdint.lo core/stdc/stdio.lo \
+	core/stdc/stdlib.lo core/stdc/string.lo core/stdc/tgmath.lo \
+	core/stdc/time.lo core/stdc/wchar_.lo core/stdc/wctype.lo \
+	core/sync/barrier.lo core/sync/condition.lo \
+	core/sync/config.lo core/sync/event.lo core/sync/exception.lo \
+	core/sync/mutex.lo core/sync/package.lo core/sync/rwmutex.lo \
+	core/sync/semaphore.lo core/thread/context.lo \
+	core/thread/fiber.lo core/thread/osthread.lo \
+	core/thread/package.lo core/thread/threadbase.lo \
+	core/thread/threadgroup.lo core/thread/types.lo core/time.lo \
+	core/vararg.lo core/volatile.lo etc/valgrind/valgrind.lo \
+	gcc/attribute.lo gcc/attributes.lo gcc/backtrace.lo \
+	gcc/builtins.lo gcc/deh.lo gcc/emutls.lo gcc/gthread.lo \
+	gcc/sections/common.lo gcc/sections/elf.lo \
+	gcc/sections/macho.lo gcc/sections/package.lo \
+	gcc/sections/pecoff.lo gcc/simd.lo gcc/unwind/arm.lo \
+	gcc/unwind/arm_common.lo gcc/unwind/c6x.lo \
 	gcc/unwind/generic.lo gcc/unwind/package.lo gcc/unwind/pe.lo \
 	object.lo rt/aApply.lo rt/aApplyR.lo rt/aaA.lo rt/adi.lo \
 	rt/arraycat.lo rt/cast_.lo rt/config.lo rt/critical_.lo \
@@ -879,26 +880,26 @@  DRUNTIME_DSOURCES = core/atomic.d core/attribute.d core/bitop.d \
 	core/stdc/ctype.d core/stdc/errno.d core/stdc/fenv.d \
 	core/stdc/float_.d core/stdc/inttypes.d core/stdc/limits.d \
 	core/stdc/locale.d core/stdc/math.d core/stdc/signal.d \
-	core/stdc/stdarg.d core/stdc/stddef.d core/stdc/stdint.d \
-	core/stdc/stdio.d core/stdc/stdlib.d core/stdc/string.d \
-	core/stdc/tgmath.d core/stdc/time.d core/stdc/wchar_.d \
-	core/stdc/wctype.d core/sync/barrier.d core/sync/condition.d \
-	core/sync/config.d core/sync/event.d core/sync/exception.d \
-	core/sync/mutex.d core/sync/package.d core/sync/rwmutex.d \
-	core/sync/semaphore.d core/thread/context.d core/thread/fiber.d \
-	core/thread/osthread.d core/thread/package.d core/thread/threadbase.d \
-	core/thread/threadgroup.d core/thread/types.d core/time.d \
-	core/vararg.d core/volatile.d etc/valgrind/valgrind.d gcc/attribute.d \
-	gcc/attributes.d gcc/backtrace.d gcc/builtins.d gcc/deh.d gcc/emutls.d \
-	gcc/gthread.d gcc/sections/common.d gcc/sections/elf.d \
-	gcc/sections/macho.d gcc/sections/package.d gcc/sections/pecoff.d \
-	gcc/simd.d gcc/unwind/arm.d gcc/unwind/arm_common.d gcc/unwind/c6x.d \
-	gcc/unwind/generic.d gcc/unwind/package.d gcc/unwind/pe.d object.d \
-	rt/aApply.d rt/aApplyR.d rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d \
-	rt/config.d rt/critical_.d rt/deh.d rt/dmain2.d rt/ehalloc.d \
-	rt/invariant.d rt/lifetime.d rt/memory.d rt/minfo.d rt/monitor_.d \
-	rt/profilegc.d rt/sections.d rt/tlsgc.d rt/util/typeinfo.d \
-	rt/util/utility.d
+	core/stdc/stdarg.d core/stdc/stdatomic.d core/stdc/stddef.d \
+	core/stdc/stdint.d core/stdc/stdio.d core/stdc/stdlib.d \
+	core/stdc/string.d core/stdc/tgmath.d core/stdc/time.d \
+	core/stdc/wchar_.d core/stdc/wctype.d core/sync/barrier.d \
+	core/sync/condition.d core/sync/config.d core/sync/event.d \
+	core/sync/exception.d core/sync/mutex.d core/sync/package.d \
+	core/sync/rwmutex.d core/sync/semaphore.d core/thread/context.d \
+	core/thread/fiber.d core/thread/osthread.d core/thread/package.d \
+	core/thread/threadbase.d core/thread/threadgroup.d core/thread/types.d \
+	core/time.d core/vararg.d core/volatile.d etc/valgrind/valgrind.d \
+	gcc/attribute.d gcc/attributes.d gcc/backtrace.d gcc/builtins.d \
+	gcc/deh.d gcc/emutls.d gcc/gthread.d gcc/sections/common.d \
+	gcc/sections/elf.d gcc/sections/macho.d gcc/sections/package.d \
+	gcc/sections/pecoff.d gcc/simd.d gcc/unwind/arm.d \
+	gcc/unwind/arm_common.d gcc/unwind/c6x.d gcc/unwind/generic.d \
+	gcc/unwind/package.d gcc/unwind/pe.d object.d rt/aApply.d rt/aApplyR.d \
+	rt/aaA.d rt/adi.d rt/arraycat.d rt/cast_.d rt/config.d rt/critical_.d \
+	rt/deh.d rt/dmain2.d rt/ehalloc.d rt/invariant.d rt/lifetime.d \
+	rt/memory.d rt/minfo.d rt/monitor_.d rt/profilegc.d rt/sections.d \
+	rt/tlsgc.d rt/util/typeinfo.d rt/util/utility.d
 
 DRUNTIME_DSOURCES_STDCXX = core/stdcpp/allocator.d core/stdcpp/array.d \
 	core/stdcpp/exception.d core/stdcpp/memory.d core/stdcpp/new_.d \
@@ -1316,6 +1317,7 @@  core/stdc/locale.lo: core/stdc/$(am__dirstamp)
 core/stdc/math.lo: core/stdc/$(am__dirstamp)
 core/stdc/signal.lo: core/stdc/$(am__dirstamp)
 core/stdc/stdarg.lo: core/stdc/$(am__dirstamp)
+core/stdc/stdatomic.lo: core/stdc/$(am__dirstamp)
 core/stdc/stddef.lo: core/stdc/$(am__dirstamp)
 core/stdc/stdint.lo: core/stdc/$(am__dirstamp)
 core/stdc/stdio.lo: core/stdc/$(am__dirstamp)
diff --git a/libphobos/libdruntime/core/internal/array/operations.d b/libphobos/libdruntime/core/internal/array/operations.d
index 3e2331484b3..7e5b5f43e9b 100644
--- a/libphobos/libdruntime/core/internal/array/operations.d
+++ b/libphobos/libdruntime/core/internal/array/operations.d
@@ -33,7 +33,7 @@  version (LDC) version = GNU_OR_LDC;
  *
  * Returns: the slice containing the result
  */
-T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted @nogc pure nothrow
+T[] arrayOp(T : T[], Args...)(T[] res, Filter!(isType, Args) args) @trusted
 {
     alias scalarizedExp = staticMap!(toElementType, Args);
     alias check = typeCheck!(true, T, scalarizedExp); // must support all scalar ops
@@ -541,7 +541,7 @@  unittest
 }
 
 // test handling of v op= exp
-unittest
+@nogc nothrow pure @safe unittest
 {
     uint[32] c;
     arrayOp!(uint[], uint, "+=")(c[], 2);
@@ -556,7 +556,7 @@  unittest
 }
 
 // proper error message for UDT lacking certain ops
-unittest
+@nogc nothrow pure @safe unittest
 {
     static assert(!is(typeof(&arrayOp!(int[4][], int[4], "+="))));
     static assert(!is(typeof(&arrayOp!(int[4][], int[4], "u-", "="))));
@@ -585,7 +585,7 @@  unittest
 }
 
 // test mixed type array op
-unittest
+@nogc nothrow pure @safe unittest
 {
     uint[32] a = 0xF;
     float[32] res = 2.0f;
@@ -595,7 +595,7 @@  unittest
 }
 
 // test mixed type array op
-unittest
+@nogc nothrow pure @safe unittest
 {
     static struct S
     {
@@ -613,7 +613,7 @@  unittest
 }
 
 // test scalar after operation argument
-unittest
+@nogc nothrow pure @safe unittest
 {
     float[32] res, a = 2, b = 3;
     float c = 4;
@@ -622,7 +622,7 @@  unittest
         assert(v == 2 * 3 + 4);
 }
 
-unittest
+@nogc nothrow pure @safe unittest
 {
     // https://issues.dlang.org/show_bug.cgi?id=17964
     uint bug(){
@@ -635,7 +635,7 @@  unittest
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=19796
-unittest
+nothrow pure @safe unittest
 {
     double[] data = [0.5];
     double[] result;
@@ -645,7 +645,7 @@  unittest
 }
 
 // https://issues.dlang.org/show_bug.cgi?id=21110
-unittest
+pure unittest
 {
     import core.exception;
 
@@ -668,3 +668,20 @@  unittest
     void func() { dst[] = a[] + b[]; }
     assertThrown!AssertError(func(), "Array operations with mismatched lengths must throw an error");
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=24272
+unittest
+{
+    static struct B
+    {
+        B opOpAssign(string op)(B other)
+        {
+            static int g;
+            g++;
+            throw new Exception("");
+        }
+    }
+
+    B[] bArr;
+    bArr[] += B();
+}
diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d
index eebf94ee29d..3fd5d4a595d 100644
--- a/libphobos/libdruntime/core/internal/atomic.d
+++ b/libphobos/libdruntime/core/internal/atomic.d
@@ -49,6 +49,8 @@  version (DigitalMars)
         enum SizedReg(int reg, T = size_t) = registerNames[reg][RegIndex!T];
     }
 
+    enum IsAtomicLockFree(T) = T.sizeof <= size_t.sizeof * 2;
+
     inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
         if (CanCAS!T)
     {
@@ -649,6 +651,11 @@  version (DigitalMars)
         }
     }
 
+    void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
+    {
+        // no-op, dmd doesn't reorder instructions
+    }
+
     void pause() pure nothrow @nogc @trusted
     {
         version (D_InlineAsm_X86)
@@ -681,37 +688,57 @@  else version (GNU)
     import gcc.builtins;
     import gcc.config;
 
+    // Targets where MemoryOrder.acq_rel is sufficiently cheaper than using
+    // MemoryOrder.seq, used when the MemoryOrder requested is not valid for
+    // a given atomic operation.
+    version (IA64)
+        private enum PreferAcquireRelease = true;
+    else version (PPC)
+        private enum PreferAcquireRelease = true;
+    else version (PPC64)
+        private enum PreferAcquireRelease = true;
+    else
+        private enum PreferAcquireRelease = false;
+
+    enum IsAtomicLockFree(T) = __atomic_is_lock_free(T.sizeof, null);
+
     inout(T) atomicLoad(MemoryOrder order = MemoryOrder.seq, T)(inout(T)* src) pure nothrow @nogc @trusted
         if (CanCAS!T)
     {
+        // MemoryOrder.rel and MemoryOrder.acq_rel are not valid for load.
         static assert(order != MemoryOrder.rel, "invalid MemoryOrder for atomicLoad()");
 
+        static if (order == MemoryOrder.acq_rel)
+            enum smodel = PreferAcquireRelease ? MemoryOrder.acq : MemoryOrder.seq;
+        else
+            enum smodel = order;
+
         static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
         {
             static if (T.sizeof == ubyte.sizeof)
             {
-                ubyte value = __atomic_load_1(cast(shared)src, order);
+                ubyte value = __atomic_load_1(cast(shared)src, smodel);
                 return *cast(typeof(return)*)&value;
             }
             else static if (T.sizeof == ushort.sizeof)
             {
-                ushort value = __atomic_load_2(cast(shared)src, order);
+                ushort value = __atomic_load_2(cast(shared)src, smodel);
                 return *cast(typeof(return)*)&value;
             }
             else static if (T.sizeof == uint.sizeof)
             {
-                uint value = __atomic_load_4(cast(shared)src, order);
+                uint value = __atomic_load_4(cast(shared)src, smodel);
                 return *cast(typeof(return)*)&value;
             }
             else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
             {
-                ulong value = __atomic_load_8(cast(shared)src, order);
+                ulong value = __atomic_load_8(cast(shared)src, smodel);
                 return *cast(typeof(return)*)&value;
             }
             else static if (GNU_Have_LibAtomic)
             {
                 T value;
-                __atomic_load(T.sizeof, cast(shared)src, &value, order);
+                __atomic_load(T.sizeof, cast(shared)src, &value, smodel);
                 return *cast(typeof(return)*)&value;
             }
             else
@@ -728,20 +755,26 @@  else version (GNU)
     void atomicStore(MemoryOrder order = MemoryOrder.seq, T)(T* dest, T value) pure nothrow @nogc @trusted
         if (CanCAS!T)
     {
+        // MemoryOrder.acq and MemoryOrder.acq_rel are not valid for store.
         static assert(order != MemoryOrder.acq, "Invalid MemoryOrder for atomicStore()");
 
+        static if (order == MemoryOrder.acq_rel)
+            enum smodel = PreferAcquireRelease ? MemoryOrder.rel : MemoryOrder.seq;
+        else
+            enum smodel = order;
+
         static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
         {
             static if (T.sizeof == ubyte.sizeof)
-                __atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, order);
+                __atomic_store_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
             else static if (T.sizeof == ushort.sizeof)
-                __atomic_store_2(cast(shared)dest, *cast(ushort*)&value, order);
+                __atomic_store_2(cast(shared)dest, *cast(ushort*)&value, smodel);
             else static if (T.sizeof == uint.sizeof)
-                __atomic_store_4(cast(shared)dest, *cast(uint*)&value, order);
+                __atomic_store_4(cast(shared)dest, *cast(uint*)&value, smodel);
             else static if (T.sizeof == ulong.sizeof && GNU_Have_64Bit_Atomics)
-                __atomic_store_8(cast(shared)dest, *cast(ulong*)&value, order);
+                __atomic_store_8(cast(shared)dest, *cast(ulong*)&value, smodel);
             else static if (GNU_Have_LibAtomic)
-                __atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, order);
+                __atomic_store(T.sizeof, cast(shared)dest, cast(void*)&value, smodel);
             else
                 static assert(0, "Invalid template type specified.");
         }
@@ -814,30 +847,36 @@  else version (GNU)
     {
         static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
         {
+            // MemoryOrder.acq is not valid for exchange.
+            static if (order == MemoryOrder.acq)
+                enum smodel = PreferAcquireRelease ? MemoryOrder.acq_rel : MemoryOrder.seq;
+            else
+                enum smodel = order;
+
             static if (T.sizeof == byte.sizeof)
             {
-                ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, order);
+                ubyte res = __atomic_exchange_1(cast(shared)dest, *cast(ubyte*)&value, smodel);
                 return *cast(typeof(return)*)&res;
             }
             else static if (T.sizeof == short.sizeof)
             {
-                ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, order);
+                ushort res = __atomic_exchange_2(cast(shared)dest, *cast(ushort*)&value, smodel);
                 return *cast(typeof(return)*)&res;
             }
             else static if (T.sizeof == int.sizeof)
             {
-                uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, order);
+                uint res = __atomic_exchange_4(cast(shared)dest, *cast(uint*)&value, smodel);
                 return *cast(typeof(return)*)&res;
             }
             else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
             {
-                ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, order);
+                ulong res = __atomic_exchange_8(cast(shared)dest, *cast(ulong*)&value, smodel);
                 return *cast(typeof(return)*)&res;
             }
             else static if (GNU_Have_LibAtomic)
             {
                 T res = void;
-                __atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, order);
+                __atomic_exchange(T.sizeof, cast(shared)dest, cast(void*)&value, &res, smodel);
                 return res;
             }
             else
@@ -885,21 +924,42 @@  else version (GNU)
 
         static if (GNU_Have_Atomics || GNU_Have_LibAtomic)
         {
+            static if (fail == MemoryOrder.rel || fail == MemoryOrder.acq_rel)
+            {
+                // MemoryOrder.rel and MemoryOrder.acq_rel are not valid failure models.
+                enum smodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
+                        ? MemoryOrder.acq_rel : MemoryOrder.seq;
+                enum fmodel = (succ != MemoryOrder.seq && PreferAcquireRelease)
+                        ? MemoryOrder.raw : MemoryOrder.seq;
+            }
+            else static if (fail > succ)
+            {
+                // Failure memory model cannot be stronger than success.
+                enum smodel = (fail != MemoryOrder.seq && PreferAcquireRelease)
+                        ? MemoryOrder.acq_rel : MemoryOrder.seq;
+                enum fmodel = fail;
+            }
+            else
+            {
+                enum smodel = succ;
+                enum fmodel = fail;
+            }
+
             static if (T.sizeof == byte.sizeof)
                 res = __atomic_compare_exchange_1(cast(shared)dest, compare, *cast(ubyte*)&value,
-                                                  weak, succ, fail);
+                                                  weak, smodel, fmodel);
             else static if (T.sizeof == short.sizeof)
                 res = __atomic_compare_exchange_2(cast(shared)dest, compare, *cast(ushort*)&value,
-                                                  weak, succ, fail);
+                                                  weak, smodel, fmodel);
             else static if (T.sizeof == int.sizeof)
                 res = __atomic_compare_exchange_4(cast(shared)dest, compare, *cast(uint*)&value,
-                                                  weak, succ, fail);
+                                                  weak, smodel, fmodel);
             else static if (T.sizeof == long.sizeof && GNU_Have_64Bit_Atomics)
                 res = __atomic_compare_exchange_8(cast(shared)dest, compare, *cast(ulong*)&value,
-                                                  weak, succ, fail);
+                                                  weak, smodel, fmodel);
             else static if (GNU_Have_LibAtomic)
                 res = __atomic_compare_exchange(T.sizeof, cast(shared)dest, compare, cast(void*)&value,
-                                                succ, fail);
+                                                smodel, fmodel);
             else
                 static assert(0, "Invalid template type specified.");
         }
@@ -945,6 +1005,11 @@  else version (GNU)
         }
     }
 
+    void atomicSignalFence(MemoryOrder order = MemoryOrder.seq)() pure nothrow @nogc @trusted
+    {
+        __atomic_signal_fence(order);
+    }
+
     void pause() pure nothrow @nogc @trusted
     {
         version (X86)
diff --git a/libphobos/libdruntime/core/stdc/stdatomic.d b/libphobos/libdruntime/core/stdc/stdatomic.d
new file mode 100644
index 00000000000..ae17e040da7
--- /dev/null
+++ b/libphobos/libdruntime/core/stdc/stdatomic.d
@@ -0,0 +1,1124 @@ 
+/**
+ * A D implementation of the C stdatomic.h header.
+ *
+ * $(NOTE If it compiles it should produce similar assembly to the system C toolchain
+ *   and should not introduce when optimizing unnecessary behaviors,
+ *   if you do not care about this guarantee use the _impl suffix.)
+ *
+ * $(NOTE The D shared type qualifier is the closest to the _Atomic type qualifier from C. It may be changed from shared in the future.)
+ *
+ * Copyright: Copyright Richard (Rikki) Andrew Cattermole 2023.
+ * License:   $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
+ * Authors:   Richard (Rikki) Andrew cattermole
+ * Source:    $(DRUNTIMESRC core/stdc/stdatomic.d)
+ */
+module core.stdc.stdatomic;
+import core.atomic : MemoryOrder;
+import core.internal.atomic;
+import core.stdc.config;
+import core.stdc.stdint;
+
+@safe nothrow @nogc:
+
+///
+enum memory_order
+{
+    /// No ordering provided
+    memory_order_relaxed = MemoryOrder.raw,
+    /// As per cppreference.com circa 2015 no compiler supports consume memory order and in practice it devolves to acquire.
+    memory_order_consume = MemoryOrder.acq,
+    /// Prevent reordering before operation
+    memory_order_acquire = MemoryOrder.acq,
+    /// Prevent reordering after operation
+    memory_order_release = MemoryOrder.rel,
+    /// Prevent reordering before and after operation
+    memory_order_acq_rel = MemoryOrder.acq_rel,
+    /// Prevent reordering before for read operations and after for writes.
+    memory_order_seq_cst = MemoryOrder.seq
+}
+
+///
+enum
+{
+    ///
+    __STDC_VERSION_STDATOMIC_H__ = 202311,
+
+    ///
+    ATOMIC_BOOL_LOCK_FREE = IsAtomicLockFree!bool ? 2 : 0,
+    ///
+    ATOMIC_CHAR_LOCK_FREE = IsAtomicLockFree!char ? 2 : 0,
+    ///
+    ATOMIC_CHAR16_T_LOCK_FREE = IsAtomicLockFree!wchar ? 2 : 0,
+    ///
+    ATOMIC_CHAR32_T_LOCK_FREE = IsAtomicLockFree!dchar ? 2 : 0,
+    ///
+    ATOMIC_WCHAR_T_LOCK_FREE = ATOMIC_CHAR16_T_LOCK_FREE,
+    ///
+    ATOMIC_SHORT_LOCK_FREE = IsAtomicLockFree!short ? 2 : 0,
+    ///
+    ATOMIC_INT_LOCK_FREE = IsAtomicLockFree!int ? 2 : 0,
+    ///
+    ATOMIC_LONG_LOCK_FREE = IsAtomicLockFree!c_long ? 2 : 0,
+    ///
+    ATOMIC_LLONG_LOCK_FREE = IsAtomicLockFree!ulong ? 2 : 0,
+    ///
+    ATOMIC_POINTER_LOCK_FREE = IsAtomicLockFree!(void*) ? 2 : 0,
+    ///
+    ATOMIC_CHAR8_T_LOCK_FREE = ATOMIC_CHAR_LOCK_FREE,
+}
+
+version (DigitalMars)
+{
+    alias atomic_signal_fence = atomic_signal_fence_impl; ///
+
+    // these all use inline assembly, so will unlikely produce the codegen a user will expect
+    version(none)
+    {
+        alias atomic_flag_clear = atomic_flag_clear_impl; ///
+        alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; ///
+        alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; ///
+        alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; ///
+        alias atomic_thread_fence = atomic_thread_fence_impl; ///
+        alias atomic_store = atomic_store_impl; ///
+        alias atomic_store_explicit = atomic_store_explicit_impl; ///
+        alias atomic_load = atomic_load_impl; ///
+        alias atomic_load_explicit = atomic_load_explicit_impl; ///
+        alias atomic_exchange = atomic_exchange_impl; ///
+        alias atomic_exchange_explicit = atomic_exchange_explicit_impl; ///
+        alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; ///
+        alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; ///
+        alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; ///
+        alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; ///
+        alias atomic_fetch_add = atomic_fetch_add_impl; ///
+        alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; ///
+        alias atomic_fetch_sub = atomic_fetch_sub_impl; ///
+        alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; ///
+        alias atomic_fetch_or = atomic_fetch_or_impl; ///
+        alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; ///
+        alias atomic_fetch_xor = atomic_fetch_xor_impl; ///
+        alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; ///
+        alias atomic_fetch_and = atomic_fetch_and_impl; ///
+        alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; ///
+    }
+}
+else version(GNU)
+{
+    alias atomic_flag_clear = atomic_flag_clear_impl; ///
+    alias atomic_flag_clear_explicit = atomic_flag_clear_explicit_impl; ///
+    alias atomic_flag_test_and_set = atomic_flag_test_and_set_impl; ///
+    alias atomic_flag_test_and_set_explicit = atomic_flag_test_and_set_explicit_impl; ///
+    alias atomic_signal_fence = atomic_signal_fence_impl; ///
+    alias atomic_thread_fence = atomic_thread_fence_impl; ///
+    alias atomic_store = atomic_store_impl; ///
+    alias atomic_store_explicit = atomic_store_explicit_impl; ///
+    alias atomic_load = atomic_load_impl; ///
+    alias atomic_load_explicit = atomic_load_explicit_impl; ///
+    alias atomic_exchange = atomic_exchange_impl; ///
+    alias atomic_exchange_explicit = atomic_exchange_explicit_impl; ///
+    alias atomic_compare_exchange_strong = atomic_compare_exchange_strong_impl; ///
+    alias atomic_compare_exchange_weak = atomic_compare_exchange_weak_impl; ///
+    alias atomic_compare_exchange_strong_explicit = atomic_compare_exchange_strong_explicit_impl; ///
+    alias atomic_compare_exchange_weak_explicit = atomic_compare_exchange_weak_explicit_impl; ///
+    alias atomic_fetch_add = atomic_fetch_add_impl; ///
+    alias atomic_fetch_add_explicit = atomic_fetch_add_explicit_impl; ///
+    alias atomic_fetch_sub = atomic_fetch_sub_impl; ///
+    alias atomic_fetch_sub_explicit = atomic_fetch_sub_explicit_impl; ///
+    alias atomic_fetch_or = atomic_fetch_or_impl; ///
+    alias atomic_fetch_or_explicit = atomic_fetch_or_explicit_impl; ///
+    alias atomic_fetch_xor = atomic_fetch_xor_impl; ///
+    alias atomic_fetch_xor_explicit = atomic_fetch_xor_explicit_impl; ///
+    alias atomic_fetch_and = atomic_fetch_and_impl; ///
+    alias atomic_fetch_and_explicit = atomic_fetch_and_explicit_impl; ///
+}
+
+///
+pragma(inline, true)
+bool atomic_is_lock_free(A)(const shared(A)* obj)
+{
+    return IsAtomicLockFree!A;
+}
+
+/// Guaranteed to be a atomic boolean type
+struct atomic_flag
+{
+    private bool b;
+}
+
+///
+enum ATOMIC_FLAG_INIT = atomic_flag.init;
+
+///
+pragma(inline, true)
+void atomic_flag_clear_impl()(atomic_flag* obj)
+{
+    assert(obj !is null);
+
+    atomicStore(&obj.b, false);
+}
+
+///
+pragma(inline, true)
+void atomic_flag_clear_explicit_impl()(atomic_flag* obj, memory_order order)
+{
+    assert(obj !is null);
+
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            atomicStore!(memory_order.memory_order_relaxed)(&obj.b, false);
+            break;
+
+        case memory_order.memory_order_acquire:
+            // Ideally this would error at compile time but alas it is not an intrinsic.
+            // Note: this is not a valid memory order for this operation.
+            atomicStore!(memory_order.memory_order_seq_cst)(&obj.b, false);
+            break;
+
+        case memory_order.memory_order_release:
+            atomicStore!(memory_order.memory_order_release)(&obj.b, false);
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            atomicStore!(memory_order.memory_order_acq_rel)(&obj.b, false);
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            atomicStore(&obj.b, false);
+            break;
+    }
+}
+
+///
+pragma(inline, true)
+bool atomic_flag_test_and_set_impl()(atomic_flag* obj)
+{
+    assert(obj !is null);
+    return atomicExchange(&obj.b, true);
+}
+
+///
+unittest
+{
+    atomic_flag flag;
+    assert(!atomic_flag_test_and_set_impl(&flag));
+    atomic_flag_clear_impl(&flag);
+}
+
+///
+pragma(inline, true)
+bool atomic_flag_test_and_set_explicit_impl()(atomic_flag* obj, memory_order order)
+{
+    assert(obj !is null);
+
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            return atomicExchange!(memory_order.memory_order_relaxed)(&obj.b, true);
+
+        case memory_order.memory_order_acquire:
+            return atomicExchange!(memory_order.memory_order_acquire)(&obj.b, true);
+
+        case memory_order.memory_order_release:
+            return atomicExchange!(memory_order.memory_order_release)(&obj.b, true);
+
+        case memory_order.memory_order_acq_rel:
+            return atomicExchange!(memory_order.memory_order_acq_rel)(&obj.b, true);
+
+        case memory_order.memory_order_seq_cst:
+            return atomicExchange(&obj.b, true);
+    }
+}
+
+///
+unittest
+{
+    atomic_flag flag;
+    assert(!atomic_flag_test_and_set_explicit_impl(&flag, memory_order.memory_order_seq_cst));
+    atomic_flag_clear_explicit_impl(&flag, memory_order.memory_order_seq_cst);
+}
+
+/**
+ * Initializes an atomic variable, the destination should not have any expression associated with it prior to this call.
+ *
+ * We use an out parameter instead of a pointer for destination in an attempt to communicate to the compiler that it initializers.
+ */
+pragma(inline, true)
+void atomic_init(A, C)(out shared(A) obj, C desired) @trusted
+{
+    obj = cast(shared) desired;
+}
+
+///
+unittest
+{
+    shared int val;
+    atomic_init(val, 2);
+}
+
+/// No-op function, doesn't apply to D
+pragma(inline, true)
+A kill_dependency(A)(A y) @trusted
+{
+    return y;
+}
+
+/// Don't allow reordering, does not emit any instructions.
+pragma(inline, true)
+void atomic_signal_fence_impl()(memory_order order)
+{
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            atomicSignalFence!(memory_order.memory_order_relaxed);
+            break;
+
+        case memory_order.memory_order_acquire:
+            atomicSignalFence!(memory_order.memory_order_acquire);
+            break;
+
+        case memory_order.memory_order_release:
+            atomicSignalFence!(memory_order.memory_order_release);
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            atomicSignalFence!(memory_order.memory_order_acq_rel);
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            atomicSignalFence!(memory_order.memory_order_seq_cst);
+            break;
+    }
+}
+
+///
+unittest
+{
+    atomic_signal_fence_impl(memory_order.memory_order_seq_cst);
+}
+
+/// Don't allow reordering, and emit a fence instruction.
+pragma(inline, true)
+void atomic_thread_fence_impl()(memory_order order)
+{
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            atomicFence!(memory_order.memory_order_relaxed);
+            break;
+
+        case memory_order.memory_order_acquire:
+            atomicFence!(memory_order.memory_order_acquire);
+            break;
+
+        case memory_order.memory_order_release:
+            atomicFence!(memory_order.memory_order_release);
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            atomicFence!(memory_order.memory_order_acq_rel);
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            atomicFence!(memory_order.memory_order_seq_cst);
+            break;
+    }
+}
+
+///
+unittest
+{
+    atomic_thread_fence_impl(memory_order.memory_order_seq_cst);
+}
+
+///
+alias atomic_bool = shared(bool);
+///
+alias atomic_char = shared(char);
+///
+alias atomic_schar = shared(byte);
+///
+alias atomic_uchar = shared(ubyte);
+///
+alias atomic_short = shared(short);
+///
+alias atomic_ushort = shared(ushort);
+///
+alias atomic_int = shared(int);
+///
+alias atomic_uint = shared(uint);
+///
+alias atomic_long = shared(c_long);
+///
+alias atomic_ulong = shared(c_ulong);
+///
+alias atomic_llong = shared(long);
+///
+alias atomic_ullong = shared(ulong);
+///
+alias atomic_char8_t = shared(char);
+///
+alias atomic_char16_t = shared(wchar);
+///
+alias atomic_char32_t = shared(dchar);
+///
+alias atomic_wchar_t = shared(wchar);
+
+///
+alias atomic_int_least8_t = shared(int_least8_t);
+///
+alias atomic_uint_least8_t = shared(uint_least8_t);
+///
+alias atomic_int_least16_t = shared(int_least16_t);
+///
+alias atomic_uint_least16_t = shared(uint_least16_t);
+///
+alias atomic_int_least32_t = shared(int_least32_t);
+///
+alias atomic_uint_least32_t = shared(uint_least32_t);
+///
+alias atomic_int_least64_t = shared(int_least64_t);
+///
+alias atomic_uint_least64_t = shared(uint_least64_t);
+///
+alias atomic_int_fast8_t = shared(int_fast8_t);
+///
+alias atomic_uint_fast8_t = shared(uint_fast8_t);
+///
+alias atomic_int_fast16_t = shared(int_fast16_t);
+///
+alias atomic_uint_fast16_t = shared(uint_fast16_t);
+///
+alias atomic_int_fast32_t = shared(int_fast32_t);
+///
+alias atomic_uint_fast32_t = shared(uint_fast32_t);
+///
+alias atomic_int_fast64_t = shared(int_fast64_t);
+///
+alias atomic_uint_fast64_t = shared(uint_fast64_t);
+///
+alias atomic_intptr_t = shared(intptr_t);
+///
+alias atomic_uintptr_t = shared(uintptr_t);
+///
+alias atomic_size_t = shared(size_t);
+///
+alias atomic_ptrdiff_t = shared(ptrdiff_t);
+///
+alias atomic_intmax_t = shared(intmax_t);
+///
+alias atomic_uintmax_t = shared(uintmax_t);
+
+///
+pragma(inline, true)
+void atomic_store_impl(A, C)(shared(A)* obj, C desired) @trusted
+{
+    assert(obj !is null);
+    atomicStore(obj, cast(A)desired);
+}
+
+///
+unittest
+{
+    shared(int) obj;
+    atomic_store_impl(&obj, 3);
+}
+
+///
+pragma(inline, true)
+void atomic_store_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            atomicStore!(memory_order.memory_order_relaxed)(obj, cast(A)desired);
+            break;
+
+        case memory_order.memory_order_acquire:
+            // Ideally this would error at compile time but alas it is not an intrinsic.
+            // Note: this is not a valid memory order for this operation.
+            atomicStore!(memory_order.memory_order_release)(obj, cast(A)desired);
+            break;
+
+        case memory_order.memory_order_release:
+            atomicStore!(memory_order.memory_order_release)(obj, cast(A)desired);
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            atomicStore!(memory_order.memory_order_acq_rel)(obj, cast(A)desired);
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            atomicStore!(memory_order.memory_order_seq_cst)(obj, cast(A)desired);
+            break;
+    }
+}
+
+///
+unittest
+{
+    shared(int) obj;
+    atomic_store_explicit_impl(&obj, 3, memory_order.memory_order_seq_cst);
+}
+
+///
+pragma(inline, true)
+A atomic_load_impl(A)(const shared(A)* obj) @trusted
+{
+    assert(obj !is null);
+    return atomicLoad(cast(shared(A)*)obj);
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    assert(atomic_load_impl(&obj) == 3);
+}
+
+///
+pragma(inline, true)
+A atomic_load_explicit_impl(A)(const shared(A)* obj, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            return atomicLoad!(memory_order.memory_order_relaxed)(obj);
+
+        case memory_order.memory_order_acquire:
+            return atomicLoad!(memory_order.memory_order_acquire)(obj);
+
+        case memory_order.memory_order_release:
+            // Ideally this would error at compile time but alas it is not an intrinsic.
+            // Note: this is not a valid memory order for this operation.
+            return atomicLoad!(memory_order.memory_order_acquire)(obj);
+
+        case memory_order.memory_order_acq_rel:
+            return atomicLoad!(memory_order.memory_order_acq_rel)(obj);
+
+        case memory_order.memory_order_seq_cst:
+            return atomicLoad!(memory_order.memory_order_seq_cst)(obj);
+    }
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    assert(atomic_load_explicit_impl(&obj, memory_order.memory_order_seq_cst) == 3);
+}
+
+///
+pragma(inline, true)
+A atomic_exchange_impl(A, C)(shared(A)* obj, C desired) @trusted
+{
+    assert(obj !is null);
+    return atomicExchange(cast(shared(A)*)obj, cast(A)desired);
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    assert(atomic_exchange_impl(&obj, 2) == 3);
+}
+
+///
+pragma(inline, true)
+A atomic_exchange_explicit_impl(A, C)(shared(A)* obj, C desired, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    final switch (order)
+    {
+        case memory_order.memory_order_relaxed:
+            return atomicExchange!(memory_order.memory_order_relaxed)(obj, cast(A)desired);
+
+        case memory_order.memory_order_acquire:
+            return atomicExchange!(memory_order.memory_order_acquire)(obj, cast(A)desired);
+
+        case memory_order.memory_order_release:
+            return atomicExchange!(memory_order.memory_order_release)(obj, cast(A)desired);
+
+        case memory_order.memory_order_acq_rel:
+            return atomicExchange!(memory_order.memory_order_acq_rel)(obj, cast(A)desired);
+
+        case memory_order.memory_order_seq_cst:
+            return atomicExchange!(memory_order.memory_order_seq_cst)(obj, cast(A)desired);
+    }
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    assert(atomic_exchange_explicit_impl(&obj, 2, memory_order.memory_order_seq_cst) == 3);
+}
+
+///
+pragma(inline, true)
+bool atomic_compare_exchange_strong_impl(A, C)(shared(A)* obj, A* expected, C desired) @trusted
+{
+    return atomicCompareExchangeStrong(cast(A*)obj, expected, cast(A)desired);
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    int expected = 3;
+    assert(atomic_compare_exchange_strong_impl(&obj, &expected, 2));
+}
+
+///
+pragma(inline, true)
+bool atomic_compare_exchange_weak_impl(A, C)(shared(A)* obj, A* expected, C desired) @trusted
+{
+    return atomicCompareExchangeStrong(cast(A*)obj, expected, cast(A)desired);
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    int expected = 3;
+    static assert(__traits(compiles, {atomic_compare_exchange_weak_impl(&obj, &expected, 2);}));
+}
+
+///
+pragma(inline, true)
+bool atomic_compare_exchange_strong_explicit_impl(A, C)(shared(A)* obj, A* expected, C desired, memory_order succ, memory_order fail) @trusted
+{
+    assert(obj !is null);
+    // We use these giant switch inside switch statements
+    //  because as of 2023 they are capable of being for the most part inlined by gdc & ldc when using literal arguments for memory_order.
+
+    final switch(succ)
+    {
+        case memory_order.memory_order_relaxed:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_relaxed, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_acquire:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acquire, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_release:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_release, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_acq_rel:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_acq_rel, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_seq_cst:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeStrong!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+    }
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    int expected = 3;
+    assert(atomic_compare_exchange_strong_explicit_impl(&obj, &expected, 2, memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst));
+}
+
+///
+pragma(inline, true)
+bool atomic_compare_exchange_weak_explicit_impl(A, C)(shared(A)* obj, A* expected, C desired, memory_order succ, memory_order fail) @trusted
+{
+    assert(obj !is null);
+    // We use these giant switch inside switch statements
+    //  because as of 2023 they are capable of being for the most part inlined by gdc & ldc when using literal arguments for memory_order.
+
+    final switch(succ)
+    {
+        case memory_order.memory_order_relaxed:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_acquire:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_release:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_acq_rel:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+        case memory_order.memory_order_seq_cst:
+            final switch(fail)
+            {
+                case memory_order.memory_order_relaxed:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_relaxed)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acquire:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_acquire)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_release:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_release)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_acq_rel:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_acq_rel)(cast(A*)obj, expected, cast(A)desired);
+                case memory_order.memory_order_seq_cst:
+                    return atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, expected, cast(A)desired);
+            }
+    }
+}
+
+///
+unittest
+{
+    shared(int) obj = 3;
+    int expected = 3;
+    atomic_compare_exchange_weak_explicit_impl(&obj, &expected, 2, memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_add_impl(A, M)(shared(A)* obj, M arg) @trusted
+{
+    assert(obj !is null);
+    return atomicFetchAdd(cast(A*)obj, arg);
+}
+
+///
+unittest
+{
+    shared(int) val;
+    atomic_fetch_add_impl(&val, 3);
+    assert(atomic_load_impl(&val) == 3);
+}
+
+pragma(inline, true)
+A atomic_fetch_sub_impl(A, M)(shared(A)* obj, M arg) @trusted
+{
+    assert(obj !is null);
+    return atomicFetchSub(cast(A*)obj, arg);
+}
+
+///
+unittest
+{
+    shared(int) val = 3;
+    atomic_fetch_sub_impl(&val, 3);
+    assert(atomic_load_impl(&val) == 0);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_add_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    final switch(order)
+    {
+        case memory_order.memory_order_relaxed:
+            return atomicFetchAdd!(memory_order.memory_order_relaxed)(cast(A*)obj, arg);
+        case memory_order.memory_order_acquire:
+            return atomicFetchAdd!(memory_order.memory_order_acquire)(cast(A*)obj, arg);
+        case memory_order.memory_order_release:
+            return atomicFetchAdd!(memory_order.memory_order_release)(cast(A*)obj, arg);
+        case memory_order.memory_order_acq_rel:
+            return atomicFetchAdd!(memory_order.memory_order_acq_rel)(cast(A*)obj, arg);
+        case memory_order.memory_order_seq_cst:
+            return atomicFetchAdd!(memory_order.memory_order_seq_cst)(cast(A*)obj, arg);
+    }
+}
+
+///
+unittest
+{
+    shared(int) val;
+    atomic_fetch_add_explicit_impl(&val, 3, memory_order.memory_order_seq_cst);
+    assert(atomic_load_impl(&val) == 3);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_sub_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    final switch(order)
+    {
+        case memory_order.memory_order_relaxed:
+            return atomicFetchSub!(memory_order.memory_order_relaxed)(cast(A*)obj, arg);
+        case memory_order.memory_order_acquire:
+            return atomicFetchSub!(memory_order.memory_order_acquire)(cast(A*)obj, arg);
+        case memory_order.memory_order_release:
+            return atomicFetchSub!(memory_order.memory_order_release)(cast(A*)obj, arg);
+        case memory_order.memory_order_acq_rel:
+            return atomicFetchSub!(memory_order.memory_order_acq_rel)(cast(A*)obj, arg);
+        case memory_order.memory_order_seq_cst:
+            return atomicFetchSub!(memory_order.memory_order_seq_cst)(cast(A*)obj, arg);
+    }
+}
+
+///
+unittest
+{
+    shared(int) val = 3;
+    atomic_fetch_sub_explicit_impl(&val, 3, memory_order.memory_order_seq_cst);
+    assert(atomic_load_impl(&val) == 0);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_or_impl(A, M)(shared(A)* obj, M arg) @trusted
+{
+    assert(obj !is null);
+
+    // copied from atomicOp
+
+    A set, get = atomicLoad(cast(A*)obj);
+
+    do
+    {
+        set = get | arg;
+    } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_or_impl(&val, 3);
+    assert(atomic_load_impl(&val) == 7);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_or_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    A set, get;
+
+    final switch(order)
+    {
+        case memory_order.memory_order_relaxed:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get | arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acquire:
+            get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj);
+            do
+            {
+                set = get | arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_release:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get | arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj);
+            do
+            {
+                set = get | arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get | arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+            break;
+    }
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_or_explicit_impl(&val, 3, memory_order.memory_order_seq_cst);
+    assert(atomic_load_impl(&val) == 7);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_xor_impl(A, M)(shared(A)* obj, M arg) @trusted
+{
+    assert(obj !is null);
+
+    // copied from atomicOp
+
+    A set, get = atomicLoad(cast(A*)obj);
+
+    do
+    {
+        set = get ^ arg;
+    } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_xor_impl(&val, 3);
+    assert(atomic_load_impl(&val) == 6);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_xor_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    A set, get;
+
+    final switch(order)
+    {
+        case memory_order.memory_order_relaxed:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get ^ arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acquire:
+            get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj);
+            do
+            {
+                set = get ^ arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_release:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get ^ arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj);
+            do
+            {
+                set = get ^ arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get ^ arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+            break;
+    }
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_xor_explicit_impl(&val, 3, memory_order.memory_order_seq_cst);
+    assert(atomic_load_impl(&val) == 6);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_and_impl(A, M)(shared(A)* obj, M arg) @trusted
+{
+    assert(obj !is null);
+
+    // copied from atomicOp
+
+    A set, get = atomicLoad(cast(A*)obj);
+
+    do
+    {
+        set = get & arg;
+    } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_and_impl(&val, 3);
+    assert(atomic_load_impl(&val) == 1);
+}
+
+///
+pragma(inline, true)
+A atomic_fetch_and_explicit_impl(A, M)(shared(A)* obj, M arg, memory_order order) @trusted
+{
+    assert(obj !is null);
+
+    A set, get;
+
+    final switch(order)
+    {
+        case memory_order.memory_order_relaxed:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get & arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_relaxed, memory_order.memory_order_relaxed)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acquire:
+            get = atomicLoad!(memory_order.memory_order_acquire)(cast(A*)obj);
+            do
+            {
+                set = get & arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acquire, memory_order.memory_order_acquire)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_release:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get & arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_release, memory_order.memory_order_release)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_acq_rel:
+            get = atomicLoad!(memory_order.memory_order_acq_rel)(cast(A*)obj);
+            do
+            {
+                set = get & arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_acq_rel, memory_order.memory_order_acq_rel)(cast(A*)obj, &get, cast(A)set));
+            break;
+
+        case memory_order.memory_order_seq_cst:
+            get = atomicLoad!(memory_order.memory_order_relaxed)(cast(A*)obj);
+            do
+            {
+                set = get & arg;
+            } while (!atomicCompareExchangeWeak!(memory_order.memory_order_seq_cst, memory_order.memory_order_seq_cst)(cast(A*)obj, &get, cast(A)set));
+            break;
+    }
+
+    return get;
+}
+
+///
+unittest
+{
+    shared(int) val = 5;
+    atomic_fetch_and_explicit_impl(&val, 3, memory_order.memory_order_seq_cst);
+    assert(atomic_load_impl(&val) == 1);
+}
diff --git a/libphobos/libdruntime/core/thread/osthread.d b/libphobos/libdruntime/core/thread/osthread.d
index 066f39e39c7..9ddc187b374 100644
--- a/libphobos/libdruntime/core/thread/osthread.d
+++ b/libphobos/libdruntime/core/thread/osthread.d
@@ -2129,6 +2129,13 @@  extern (C) void thread_init() @nogc nothrow
         static extern(C) void initChildAfterFork()
         {
             auto thisThread = Thread.getThis();
+            if (!thisThread)
+            {
+                // It is possible that runtime was not properly initialized in the current process or thread -
+                // it may happen after `fork` call when using a dynamically loaded shared library written in D from a multithreaded non-D program.
+                // In such case getThis will return null.
+                return;
+            }
             thisThread.m_addr = pthread_self();
             assert( thisThread.m_addr != thisThread.m_addr.init );
             thisThread.m_tmach = pthread_mach_thread_np( thisThread.m_addr );
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index 5589c0a884f..1b39a27c102 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -526,6 +526,12 @@  unittest
 
 private extern(C) void _d_setSameMutex(shared Object ownee, shared Object owner) nothrow;
 
+/** Makes ownee use owner's mutex.
+ * This will initialize owner's mutex if it hasn't been set yet.
+ * Params:
+ * ownee = object to change
+ * owner = source object
+ */
 void setSameMutex(shared Object ownee, shared Object owner)
 {
     import core.atomic : atomicLoad;