diff mbox series

[committed] d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79.

Message ID 20231121140827.109435-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd ff57fec515, druntime ff57fec515, phobos 17bafda79. | expand

Commit Message

Iain Buclaw Nov. 21, 2023, 2:08 p.m. UTC
This patch merges the D front-end and runtime library with upstream dmd
ff57fec515, and the standard library with phobos 17bafda79.

Synchronizing with the upstream release candidate of v2.106.0.

D front-end changes:

    - Import dmd v2.106.0-rc.1.
    - New'ing multi-dimensional arrays are now are converted to a single
      template call `_d_newarraymTX'.

D runtime changes:

    - Import druntime v2.106.0-rc.1.

Phobos changes:

    - Import phobos v2.106.0-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 ff57fec515.
	* dmd/VERSION: Bump version to v2.106.0-rc.1.
	* expr.cc (ExprVisitor::visit (CatAssignExp *)): Update for new
	front-end interface.
	(ExprVisitor::visit (NewExp *)): Likewise.
	* runtime.def (NEWARRAYMTX): Remove.
	(NEWARRAYMITX): Remove.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime ff57fec515.
	* src/MERGE: Merge upstream phobos 17bafda79.

gcc/testsuite/ChangeLog:

	* gdc.dg/asm1.d: Adjust expected diagnostic.
---
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/VERSION                             |   2 +-
 gcc/d/dmd/aggregate.d                         |   2 +-
 gcc/d/dmd/aggregate.h                         |   2 -
 gcc/d/dmd/astenums.d                          |   1 +
 gcc/d/dmd/attrib.d                            | 111 +-
 gcc/d/dmd/attrib.h                            |   7 -
 gcc/d/dmd/common/outbuffer.d                  |   6 +-
 gcc/d/dmd/cparse.d                            |   7 +
 gcc/d/dmd/ctfeexpr.d                          |  55 +-
 gcc/d/dmd/dcast.d                             |   7 +
 gcc/d/dmd/dclass.d                            |  67 +-
 gcc/d/dmd/declaration.d                       |  12 -
 gcc/d/dmd/declaration.h                       |   1 -
 gcc/d/dmd/denum.d                             |  32 -
 gcc/d/dmd/dimport.d                           |  40 -
 gcc/d/dmd/dmodule.d                           |  65 +-
 gcc/d/dmd/dscope.d                            |  22 +-
 gcc/d/dmd/dstruct.d                           |  17 -
 gcc/d/dmd/dsymbol.d                           | 475 +--------
 gcc/d/dmd/dsymbol.h                           |  16 +-
 gcc/d/dmd/dsymbolsem.d                        | 986 +++++++++++++++++-
 gcc/d/dmd/dtemplate.d                         |   7 +-
 gcc/d/dmd/dtoh.d                              |   1 +
 gcc/d/dmd/dversion.d                          |  75 --
 gcc/d/dmd/enum.h                              |   2 -
 gcc/d/dmd/escape.d                            |  22 +-
 gcc/d/dmd/expression.d                        |   4 +-
 gcc/d/dmd/expression.h                        |   4 +-
 gcc/d/dmd/expressionsem.d                     | 160 +--
 gcc/d/dmd/func.d                              |  61 +-
 gcc/d/dmd/hdrgen.d                            |  21 +-
 gcc/d/dmd/id.d                                |   3 +-
 gcc/d/dmd/import.h                            |   2 -
 gcc/d/dmd/importc.d                           |   1 +
 gcc/d/dmd/init.d                              |  29 +
 gcc/d/dmd/init.h                              |  10 +
 gcc/d/dmd/initsem.d                           |  19 +
 gcc/d/dmd/lambdacomp.d                        |   1 +
 gcc/d/dmd/module.h                            |   2 -
 gcc/d/dmd/nogc.d                              |  16 +-
 gcc/d/dmd/nspace.d                            |  43 -
 gcc/d/dmd/nspace.h                            |   2 -
 gcc/d/dmd/opover.d                            |   1 +
 gcc/d/dmd/optimize.d                          |  12 +-
 gcc/d/dmd/parse.d                             |  67 +-
 gcc/d/dmd/parsetimevisitor.d                  |   1 +
 gcc/d/dmd/scope.h                             |   5 +
 gcc/d/dmd/semantic3.d                         |   2 +-
 gcc/d/dmd/statementsem.d                      |   4 +-
 gcc/d/dmd/staticassert.d                      |   5 -
 gcc/d/dmd/staticassert.h                      |   1 -
 gcc/d/dmd/traits.d                            |  82 +-
 gcc/d/dmd/typesem.d                           |   2 +-
 gcc/d/dmd/version.h                           |   2 -
 gcc/d/dmd/visitor.h                           |   2 +
 gcc/d/expr.cc                                 |  99 +-
 gcc/d/runtime.def                             |   7 -
 gcc/testsuite/gdc.dg/asm1.d                   |   2 +-
 .../gdc.test/compilable/issue16020.d          |   7 +-
 gcc/testsuite/gdc.test/compilable/nogc.d      |   9 +
 .../gdc.test/fail_compilation/b20011.d        |   8 +-
 .../gdc.test/fail_compilation/const_ctor.d    |  26 +
 .../gdc.test/fail_compilation/ctor_attr.d     |  29 +
 .../gdc.test/fail_compilation/diag10415.d     |   2 +-
 .../gdc.test/fail_compilation/diag10862.d     |   4 +-
 .../gdc.test/fail_compilation/diag10926.d     |   2 +-
 .../gdc.test/fail_compilation/diag14102.d     |   8 +-
 .../gdc.test/fail_compilation/diag4596.d      |   4 +-
 .../gdc.test/fail_compilation/diag8101b.d     |   2 +-
 .../fail_compilation/dip1000_deprecation.d    |  56 -
 .../gdc.test/fail_compilation/fail10299.d     |   2 +-
 .../gdc.test/fail_compilation/fail13116.d     |   4 +-
 .../gdc.test/fail_compilation/fail13336a.d    |   2 +-
 .../gdc.test/fail_compilation/fail13336b.d    |   4 +-
 .../gdc.test/fail_compilation/fail17491.d     |  16 +-
 .../gdc.test/fail_compilation/fail21243.d     |  18 +-
 .../gdc.test/fail_compilation/fail217.d       |   2 +-
 .../gdc.test/fail_compilation/fail24224.d     |  22 +
 .../gdc.test/fail_compilation/fail6795.d      |  12 +-
 .../gdc.test/fail_compilation/fail7424d.d     |   2 +-
 .../gdc.test/fail_compilation/fail7424e.d     |   2 +-
 .../gdc.test/fail_compilation/fail7424f.d     |   2 +-
 .../gdc.test/fail_compilation/fail7424i.d     |   2 +-
 .../gdc.test/fail_compilation/fail7603a.d     |   2 +-
 .../gdc.test/fail_compilation/fail7603b.d     |   2 +-
 .../gdc.test/fail_compilation/fail7603c.d     |   2 +-
 .../gdc.test/fail_compilation/fail9537.d      |   2 +-
 .../gdc.test/fail_compilation/fail9773.d      |   2 +-
 .../gdc.test/fail_compilation/fail9891.d      |   2 +-
 .../gdc.test/fail_compilation/fail_arrayop2.d |  12 +-
 .../gdc.test/fail_compilation/fail_scope.d    |   8 +-
 .../gdc.test/fail_compilation/ice10419.d      |   2 +-
 .../gdc.test/fail_compilation/ice12841.d      |   4 +-
 .../gdc.test/fail_compilation/ice13459.d      |   2 +-
 .../gdc.test/fail_compilation/ice20264.d      |   2 +-
 .../gdc.test/fail_compilation/ice9284.d       |   2 +-
 .../fail_compilation/immutable_ctor.d         |  19 +
 .../gdc.test/fail_compilation/issue16020.d    |   8 +-
 .../gdc.test/fail_compilation/issue20704.d    |   8 +-
 .../gdc.test/fail_compilation/test16381.d     |   2 +-
 .../gdc.test/fail_compilation/test22048.d     |   2 +-
 .../gdc.test/fail_compilation/test24157.d     |   4 +-
 .../gdc.test/fail_compilation/test24159.d     |  14 +
 .../fail_compilation/testrvaluecpctor.d       |   4 +-
 .../gdc.test/fail_compilation/tolvalue.d      |  48 +
 .../gdc.test/fail_compilation/vector_cast.d   |  13 +
 gcc/testsuite/gdc.test/runnable/staticaa.d    |  15 +-
 gcc/testsuite/gdc.test/runnable/test24184.d   |  30 +
 libphobos/libdruntime/MERGE                   |   2 +-
 libphobos/libdruntime/core/cpuid.d            |  23 +-
 .../core/internal/array/appending.d           |  83 +-
 .../core/internal/array/construction.d        | 108 ++
 libphobos/libdruntime/core/internal/atomic.d  |   5 +-
 .../core/internal/gc/impl/conservative/gc.d   |   6 +-
 libphobos/libdruntime/core/internal/newaa.d   |  31 +-
 libphobos/libdruntime/core/stdc/fenv.d        |   8 +-
 libphobos/libdruntime/core/stdc/stdarg.d      |   6 +
 libphobos/libdruntime/core/sync/event.d       |  12 +-
 libphobos/libdruntime/core/sys/elf/package.d  |   2 +
 .../libdruntime/core/sys/linux/sys/auxv.d     |  17 +
 .../libdruntime/core/sys/linux/sys/mman.d     |   1 +
 libphobos/libdruntime/core/thread/fiber.d     |  44 +-
 libphobos/libdruntime/core/vararg.d           |   7 +
 libphobos/libdruntime/object.d                |  14 +-
 libphobos/libdruntime/rt/aaA.d                |  25 +-
 libphobos/libdruntime/rt/lifetime.d           |  92 --
 libphobos/src/MERGE                           |   2 +-
 libphobos/src/std/algorithm/iteration.d       |  58 +-
 libphobos/src/std/algorithm/searching.d       | 210 ++--
 libphobos/src/std/array.d                     |   4 +-
 libphobos/src/std/logger/package.d            |   2 +-
 libphobos/src/std/math/hardware.d             |  58 ++
 133 files changed, 2264 insertions(+), 1728 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/const_ctor.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d
 delete mode 100644 gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/fail24224.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/test24159.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/tolvalue.d
 create mode 100644 gcc/testsuite/gdc.test/fail_compilation/vector_cast.d
 create mode 100644 gcc/testsuite/gdc.test/runnable/test24184.d

Comments

Rainer Orth Nov. 21, 2023, 3:59 p.m. UTC | #1
Hi Iain,

> This patch merges the D front-end and runtime library with upstream dmd
> ff57fec515, and the standard library with phobos 17bafda79.
>
> Synchronizing with the upstream release candidate of v2.106.0.
>
> D front-end changes:
>
>     - Import dmd v2.106.0-rc.1.
>     - New'ing multi-dimensional arrays are now are converted to a single
>       template call `_d_newarraymTX'.
>
> D runtime changes:
>
>     - Import druntime v2.106.0-rc.1.
>
> Phobos changes:
>
>     - Import phobos v2.106.0-rc.1.
>
> Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed
> to mainline.

either this patch or the previous one broke D bootstrap with GCC 9.  On
both i386-pc-solaris2.11 with gdc 9.4.0 and sparc-sun-solaris2.11 with
gdc 9.3.0, stage 1 d21 fails to link with

Undefined                       first referenced
 symbol                             in file
_D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue7lstringMFNaNbNiNjZPa d/func.o
_D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toDcharsMxFNaNbNiNjZPxa d/func.o
_D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toStringMxFNaNbNiNjZAxa d/func.o
ld: fatal: symbol referencing errors
collect2: error: ld returned 1 exit status
make[3]: *** [/vol/gcc/src/hg/master/local/gcc/d/Make-lang.in:236: d21] Error 1

I'm now running bootstraps with gdc 11.1.0 instead, which seems to work:
in both cases, stage 1 d21 did link.

If this is intentional, install.texi should be updated accordingly.

	Rainer
Rainer Orth Nov. 21, 2023, 4:03 p.m. UTC | #2
Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> writes:

> either this patch or the previous one broke D bootstrap with GCC 9.  On
> both i386-pc-solaris2.11 with gdc 9.4.0 and sparc-sun-solaris2.11 with
> gdc 9.3.0, stage 1 d21 fails to link with
>
> Undefined                       first referenced
>  symbol                             in file
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue7lstringMFNaNbNiNjZPa d/func.o
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toDcharsMxFNaNbNiNjZPxa d/func.o
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toStringMxFNaNbNiNjZAxa d/func.o
> ld: fatal: symbol referencing errors
> collect2: error: ld returned 1 exit status
> make[3]: *** [/vol/gcc/src/hg/master/local/gcc/d/Make-lang.in:236: d21] Error 1

Same on i686-pc-linux-gnu, btw.

	Rainer
Iain Buclaw Nov. 22, 2023, 6:34 p.m. UTC | #3
Excerpts from Rainer Orth's message of November 21, 2023 4:59 pm:
> Hi Iain,
> 
>> This patch merges the D front-end and runtime library with upstream dmd
>> ff57fec515, and the standard library with phobos 17bafda79.
>>
>> Synchronizing with the upstream release candidate of v2.106.0.
>>
>> D front-end changes:
>>
>>     - Import dmd v2.106.0-rc.1.
>>     - New'ing multi-dimensional arrays are now are converted to a single
>>       template call `_d_newarraymTX'.
>>
>> D runtime changes:
>>
>>     - Import druntime v2.106.0-rc.1.
>>
>> Phobos changes:
>>
>>     - Import phobos v2.106.0-rc.1.
>>
>> Bootstrapped and regression tested on x86_64-linux-gnu/-m32, committed
>> to mainline.
> 
> either this patch or the previous one broke D bootstrap with GCC 9.  On
> both i386-pc-solaris2.11 with gdc 9.4.0 and sparc-sun-solaris2.11 with
> gdc 9.3.0, stage 1 d21 fails to link with
> 
> Undefined                       first referenced
>  symbol                             in file
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue7lstringMFNaNbNiNjZPa d/func.o
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toDcharsMxFNaNbNiNjZPxa d/func.o
> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toStringMxFNaNbNiNjZAxa d/func.o
> ld: fatal: symbol referencing errors
> collect2: error: ld returned 1 exit status
> make[3]: *** [/vol/gcc/src/hg/master/local/gcc/d/Make-lang.in:236: d21] Error 1
> 
> I'm now running bootstraps with gdc 11.1.0 instead, which seems to work:
> in both cases, stage 1 d21 did link.
> 
> If this is intentional, install.texi should be updated accordingly.
> 

Thanks Rainer,

I don't think this should happen if we can help it just yet.  I'll have
a look to see which specific upstream change might have caused it.

Iain.
Iain Buclaw Nov. 22, 2023, 9:11 p.m. UTC | #4
Excerpts from Rainer Orth's message of November 21, 2023 5:03 pm:
> Rainer Orth <ro@CeBiTec.Uni-Bielefeld.DE> writes:
> 
>> either this patch or the previous one broke D bootstrap with GCC 9.  On
>> both i386-pc-solaris2.11 with gdc 9.4.0 and sparc-sun-solaris2.11 with
>> gdc 9.3.0, stage 1 d21 fails to link with
>>
>> Undefined                       first referenced
>>  symbol                             in file
>> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue7lstringMFNaNbNiNjZPa d/func.o
>> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toDcharsMxFNaNbNiNjZPxa d/func.o
>> _D3dmd4root11stringtable34__T11StringValueTC3dmd5mtype4TypeZ11StringValue8toStringMxFNaNbNiNjZAxa d/func.o
>> ld: fatal: symbol referencing errors
>> collect2: error: ld returned 1 exit status
>> make[3]: *** [/vol/gcc/src/hg/master/local/gcc/d/Make-lang.in:236: d21] Error 1
> 
> Same on i686-pc-linux-gnu, btw.
> 

Thanks, I've found the culprit.  There's been quite a few changes in the
import graph upstream.  This looks to have exposed some unfortunate
template emission bugs in older versions of the compiler that as you've
pointed out, work just fine with gdc-11.

I'm err'ing on the side of reverting the individual patches, though if I
get time later, maybe try a partial revert by restoring the old import
statements only.

Iain.
diff mbox series

Patch

diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index 0cf9b5fd4a8..aa0062c10eb 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-65a3da148c0c700a6c928f0e13799b2a7d34fcbe
+ff57fec51558013b25cadb7e83da9f4675915d56
 
 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 b272d4bbe5c..41fdc654b14 100644
--- a/gcc/d/dmd/VERSION
+++ b/gcc/d/dmd/VERSION
@@ -1 +1 @@ 
-v2.106.0-beta.1
+v2.106.0-rc.1
diff --git a/gcc/d/dmd/aggregate.d b/gcc/d/dmd/aggregate.d
index d42ef951085..307bb0171c4 100644
--- a/gcc/d/dmd/aggregate.d
+++ b/gcc/d/dmd/aggregate.d
@@ -663,7 +663,7 @@  extern (C++) abstract class AggregateDeclaration : ScopeDsymbol
      */
     extern (D) final Dsymbol searchCtor()
     {
-        auto s = search(Loc.initial, Id.ctor);
+        auto s = this.search(Loc.initial, Id.ctor);
         if (s)
         {
             if (!(s.isCtorDeclaration() ||
diff --git a/gcc/d/dmd/aggregate.h b/gcc/d/dmd/aggregate.h
index 58a0126de1a..cd8f1a15fbd 100644
--- a/gcc/d/dmd/aggregate.h
+++ b/gcc/d/dmd/aggregate.h
@@ -167,7 +167,6 @@  private:
 public:
     static StructDeclaration *create(const Loc &loc, Identifier *id, bool inObject);
     StructDeclaration *syntaxCopy(Dsymbol *s) override;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
     const char *kind() const override;
     void finalizeSize() override final;
     bool isPOD();
@@ -285,7 +284,6 @@  public:
     virtual bool isBaseOf(ClassDeclaration *cd, int *poffset);
 
     bool isBaseInfoComplete();
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
     void finalizeSize() override;
     bool hasMonitor();
     bool isFuncHidden(FuncDeclaration *fd);
diff --git a/gcc/d/dmd/astenums.d b/gcc/d/dmd/astenums.d
index 77f36f304a5..6a9c0104a72 100644
--- a/gcc/d/dmd/astenums.d
+++ b/gcc/d/dmd/astenums.d
@@ -383,6 +383,7 @@  enum STMT : ubyte
 enum InitKind : ubyte
 {
     void_,
+    default_,
     error,
     struct_,
     array,
diff --git a/gcc/d/dmd/attrib.d b/gcc/d/dmd/attrib.d
index 49fc3082ba8..251e2e88ca5 100644
--- a/gcc/d/dmd/attrib.d
+++ b/gcc/d/dmd/attrib.d
@@ -32,7 +32,7 @@  import dmd.declaration;
 import dmd.dmodule;
 import dmd.dscope;
 import dmd.dsymbol;
-import dmd.dsymbolsem : dsymbolSemantic;
+import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
@@ -123,18 +123,6 @@  extern (C++) abstract class AttribDeclaration : Dsymbol
         return sc;
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        Dsymbols* d = include(sc);
-        if (d)
-        {
-            Scope* sc2 = newScope(sc);
-            d.foreachDsymbol( s => s.addMember(sc2, sds) );
-            if (sc2 != sc)
-                sc2.pop();
-        }
-    }
-
     override void setScope(Scope* sc)
     {
         Dsymbols* d = include(sc);
@@ -295,34 +283,6 @@  extern (C++) class StorageClassDeclaration : AttribDeclaration
         return t;
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        Dsymbols* d = include(sc);
-        if (d)
-        {
-            Scope* sc2 = newScope(sc);
-
-            d.foreachDsymbol( (s)
-            {
-                //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
-                // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
-                if (auto decl = s.isDeclaration())
-                {
-                    decl.storage_class |= stc & STC.local;
-                    if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
-                    {
-                        sdecl.stc |= stc & STC.local;
-                    }
-                }
-                s.addMember(sc2, sds);
-            });
-
-            if (sc2 != sc)
-                sc2.pop();
-        }
-
-    }
-
     override inout(StorageClassDeclaration) isStorageClassDeclaration() inout
     {
         return this;
@@ -640,37 +600,6 @@  extern (C++) final class VisibilityDeclaration : AttribDeclaration
         return createNewScope(sc, sc.stc, sc.linkage, sc.cppmangle, this.visibility, 1, sc.aligndecl, sc.inlining);
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        if (pkg_identifiers)
-        {
-            Dsymbol tmp;
-            Package.resolve(pkg_identifiers, &tmp, null);
-            visibility.pkg = tmp ? tmp.isPackage() : null;
-            pkg_identifiers = null;
-        }
-        if (visibility.kind == Visibility.Kind.package_ && visibility.pkg && sc._module)
-        {
-            Module m = sc._module;
-
-            // https://issues.dlang.org/show_bug.cgi?id=17441
-            // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if
-            // each package's .isModule() properites are equal.
-            //
-            // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
-            // This breaks package declarations of the package in question if they are declared in
-            // the same package.d file, which _do_ have a module associated with them, and hence a non-null
-            // isModule()
-            if (!m.isPackage() || !visibility.pkg.ident.equals(m.isPackage().ident))
-            {
-                Package pkg = m.parent ? m.parent.isPackage() : null;
-                if (!pkg || !visibility.pkg.isAncestorPackageOf(pkg))
-                    .error(loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", kind(), toPrettyChars(false), m.toPrettyChars(true));
-            }
-        }
-        return AttribDeclaration.addMember(sc, sds);
-    }
-
     override const(char)* kind() const
     {
         return "visibility attribute";
@@ -1054,23 +983,6 @@  extern (C++) final class StaticIfDeclaration : ConditionalDeclaration
         }
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        //printf("StaticIfDeclaration::addMember() '%s'\n", toChars());
-        /* This is deferred until the condition evaluated later (by the include() call),
-         * so that expressions in the condition can refer to declarations
-         * in the same scope, such as:
-         *
-         * template Foo(int i)
-         * {
-         *     const int j = i + 1;
-         *     static if (j == 3)
-         *         const int k;
-         * }
-         */
-        this.scopesym = sds;
-    }
-
     override void setScope(Scope* sc)
     {
         // do not evaluate condition before semantic pass
@@ -1186,12 +1098,6 @@  extern (C++) final class StaticForeachDeclaration : AttribDeclaration
         return d;
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        // used only for caching the enclosing symbol
-        this.scopesym = sds;
-    }
-
     override void addComment(const(char)* comment)
     {
         // do nothing
@@ -1266,15 +1172,6 @@  extern(C++) final class ForwardingAttribDeclaration : AttribDeclaration
         return sc.push(sym);
     }
 
-    /***************************************
-     * Lazily initializes the scope to forward to.
-     */
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        sym.parent = sds;
-        return super.addMember(sc, sym);
-    }
-
     override inout(ForwardingAttribDeclaration) isForwardingAttribDeclaration() inout
     {
         return this;
@@ -1312,12 +1209,6 @@  extern (C++) final class MixinDeclaration : AttribDeclaration
         return new MixinDeclaration(loc, Expression.arraySyntaxCopy(exps));
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, memnum);
-        this.scopesym = sds;
-    }
-
     override void setScope(Scope* sc)
     {
         Dsymbol.setScope(sc);
diff --git a/gcc/d/dmd/attrib.h b/gcc/d/dmd/attrib.h
index f47a1f6f836..efea9af950c 100644
--- a/gcc/d/dmd/attrib.h
+++ b/gcc/d/dmd/attrib.h
@@ -26,7 +26,6 @@  public:
 
     virtual Dsymbols *include(Scope *sc);
     virtual Scope *newScope(Scope *sc);
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope *sc) override;
     void importAll(Scope *sc) override;
     void addComment(const utf8_t *comment) override;
@@ -49,7 +48,6 @@  public:
     StorageClassDeclaration *syntaxCopy(Dsymbol *s) override;
     Scope *newScope(Scope *sc) override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override final;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     StorageClassDeclaration *isStorageClassDeclaration() override { return this; }
 
     void accept(Visitor *v) override { v->visit(this); }
@@ -110,7 +108,6 @@  public:
 
     VisibilityDeclaration *syntaxCopy(Dsymbol *s) override;
     Scope *newScope(Scope *sc) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     const char *kind() const override;
     const char *toPrettyChars(bool unused) override;
     VisibilityDeclaration *isVisibilityDeclaration() override { return this; }
@@ -179,7 +176,6 @@  public:
 
     StaticIfDeclaration *syntaxCopy(Dsymbol *s) override;
     Dsymbols *include(Scope *sc) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope *sc) override;
     void importAll(Scope *sc) override;
     StaticIfDeclaration *isStaticIfDeclaration() override { return this; }
@@ -199,7 +195,6 @@  public:
     StaticForeachDeclaration *syntaxCopy(Dsymbol *s) override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
     Dsymbols *include(Scope *sc) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void addComment(const utf8_t *comment) override;
     void setScope(Scope *sc) override;
     void importAll(Scope *sc) override;
@@ -213,7 +208,6 @@  public:
     ForwardingScopeDsymbol *sym;
 
     Scope *newScope(Scope *sc) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     ForwardingAttribDeclaration *isForwardingAttribDeclaration() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
 };
@@ -229,7 +223,6 @@  public:
     d_bool compiled;
 
     MixinDeclaration *syntaxCopy(Dsymbol *s) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope *sc) override;
     const char *kind() const override;
     void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/common/outbuffer.d b/gcc/d/dmd/common/outbuffer.d
index b8ad7851e4d..4e7a82fb565 100644
--- a/gcc/d/dmd/common/outbuffer.d
+++ b/gcc/d/dmd/common/outbuffer.d
@@ -281,7 +281,7 @@  struct OutBuffer
         write(&v, v.sizeof);
     }
 
-    /// NOT zero-terminated
+    /// Buffer will NOT be zero-terminated
     extern (C++) void writestring(const(char)* s) pure nothrow @system
     {
         if (!s)
@@ -302,14 +302,14 @@  struct OutBuffer
         write(s);
     }
 
-    /// NOT zero-terminated, followed by newline
+    /// Buffer will NOT be zero-terminated, followed by newline
     void writestringln(const(char)[] s) pure nothrow @safe
     {
         writestring(s);
         writenl();
     }
 
-    /** Write string to buffer, ensure it is zero terminated
+    /** Write C string AND null byte
      */
     void writeStringz(const(char)* s) pure nothrow @system
     {
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index f0c834972d6..ed5f1f8b9a2 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -2168,6 +2168,7 @@  final class CParser(AST) : Parser!AST
      * C11 Initialization
      * initializer:
      *    assignment-expression
+     *    { }                       // C23 6.7.10 addition
      *    { initializer-list }
      *    { initializer-list , }
      *
@@ -2198,6 +2199,12 @@  final class CParser(AST) : Parser!AST
         nextToken();
         const loc = token.loc;
 
+        if (token.value == TOK.rightCurly)      // { }
+        {
+            nextToken();
+            return new AST.DefaultInitializer(loc);
+        }
+
         /* Collect one or more `designation (opt) initializer`
          * into ci.initializerList, but lazily create ci
          */
diff --git a/gcc/d/dmd/ctfeexpr.d b/gcc/d/dmd/ctfeexpr.d
index c93269fb321..43efc05b5d3 100644
--- a/gcc/d/dmd/ctfeexpr.d
+++ b/gcc/d/dmd/ctfeexpr.d
@@ -28,6 +28,7 @@  import dmd.func;
 import dmd.globals;
 import dmd.location;
 import dmd.mtype;
+import dmd.root.bitarray;
 import dmd.root.complex;
 import dmd.root.ctfloat;
 import dmd.root.port;
@@ -43,14 +44,14 @@  import dmd.visitor;
 extern (D) struct UnionExp
 {
     // yes, default constructor does nothing
-    extern (D) this(Expression e)
+    extern (D) this(Expression e) nothrow
     {
         memcpy(&this, cast(void*)e, e.size);
     }
 
     /* Extract pointer to Expression
      */
-    extern (D) Expression exp() return
+    extern (D) Expression exp() return nothrow
     {
         return cast(Expression)&u;
     }
@@ -109,7 +110,7 @@  void emplaceExp(T : Expression, Args...)(void* p, Args args)
     (cast(T)p).__ctor(args);
 }
 
-void emplaceExp(T : UnionExp)(T* p, Expression e)
+void emplaceExp(T : UnionExp)(T* p, Expression e) nothrow
 {
     memcpy(p, cast(void*)e, e.size);
 }
@@ -134,7 +135,7 @@  void generateUncaughtError(ThrownExceptionExp tee)
  * Returns:
  *    index of the field, or -1 if not found
  */
-int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe
+int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pure @safe nothrow
 {
     foreach (i, field; sd.fields)
     {
@@ -145,7 +146,7 @@  int findFieldIndexByName(const StructDeclaration sd, const VarDeclaration v) pur
 }
 
 // True if 'e' is CTFEExp::cantexp, or an exception
-bool exceptionOrCantInterpret(const Expression e) @safe
+bool exceptionOrCantInterpret(const Expression e) @safe nothrow
 {
     return e && (e.op == EXP.cantExpression || e.op == EXP.thrownException || e.op == EXP.showCtfeContext);
 }
@@ -153,7 +154,7 @@  bool exceptionOrCantInterpret(const Expression e) @safe
 /************** Aggregate literals (AA/string/array/struct) ******************/
 // Given expr, which evaluates to an array/AA/string literal,
 // return true if it needs to be copied
-bool needToCopyLiteral(const Expression expr)
+bool needToCopyLiteral(const Expression expr) nothrow
 {
     Expression e = cast()expr;
     for (;;)
@@ -593,7 +594,7 @@  TypeAArray toBuiltinAAType(Type t)
 
 /************** TypeInfo operations ************************************/
 // Return true if type is TypeInfo_Class
-bool isTypeInfo_Class(const Type type)
+bool isTypeInfo_Class(const Type type) nothrow
 {
     auto tc = cast()type.isTypeClass();
     return tc && (Type.dtypeinfo == tc.sym || Type.dtypeinfo.isBaseOf(tc.sym, null));
@@ -741,14 +742,14 @@  Expression pointerDifference(UnionExp* pue, const ref Loc loc, Type type, Expres
     Expression agg2 = getAggregateFromPointer(e2, &ofs2);
     if (agg1 == agg2)
     {
-        Type pointee = (cast(TypePointer)agg1.type).next;
+        Type pointee = agg1.type.nextOf();
         const sz = pointee.size();
         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
     }
     else if (agg1.op == EXP.string_ && agg2.op == EXP.string_ &&
              agg1.isStringExp().peekString().ptr == agg2.isStringExp().peekString().ptr)
     {
-        Type pointee = (cast(TypePointer)agg1.type).next;
+        Type pointee = agg1.type.nextOf();
         const sz = pointee.size();
         emplaceExp!(IntegerExp)(pue, loc, (ofs1 - ofs2) * sz, type);
     }
@@ -794,14 +795,14 @@  Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
         goto Lcant;
     }
     dinteger_t ofs2 = e2.toInteger();
-    Type pointee = (cast(TypeNext)agg1.type.toBasetype()).next;
+    Type pointee = agg1.type.toBasetype().nextOf();
     dinteger_t sz = pointee.size();
     sinteger_t indx;
     dinteger_t len;
-    if (agg1.op == EXP.symbolOffset)
+    if (auto soe = agg1.isSymOffExp())
     {
         indx = ofs1 / sz;
-        len = (cast(TypeSArray)agg1.isSymOffExp().var.type).dim.toInteger();
+        len = soe.var.type.isTypeSArray().dim.toInteger();
     }
     else
     {
@@ -836,9 +837,9 @@  Expression pointerArithmetic(UnionExp* pue, const ref Loc loc, EXP op, Type type
         error(loc, "CTFE internal error: pointer arithmetic `%s`", agg1.toChars());
         goto Lcant;
     }
-    if (eptr.type.toBasetype().ty == Tsarray)
+    if (auto tsa = eptr.type.toBasetype().isTypeSArray())
     {
-        dinteger_t dim = (cast(TypeSArray)eptr.type.toBasetype()).dim.toInteger();
+        dinteger_t dim = tsa.dim.toInteger();
         // Create a CTFE pointer &agg1[indx .. indx+dim]
         auto se = ctfeEmplaceExp!SliceExp(loc, agg1,
                 ctfeEmplaceExp!IntegerExp(loc, indx, Type.tsize_t),
@@ -978,7 +979,7 @@  bool isCtfeComparable(Expression e)
 }
 
 /// Map EXP comparison ops
-private bool numCmp(N)(EXP op, N n1, N n2)
+private bool numCmp(N)(EXP op, N n1, N n2) nothrow
 {
     switch (op)
     {
@@ -997,25 +998,25 @@  private bool numCmp(N)(EXP op, N n1, N n2)
 }
 
 /// Returns cmp OP 0; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool specificCmp(EXP op, int rawCmp) @safe
+bool specificCmp(EXP op, int rawCmp) @safe nothrow
 {
     return numCmp!int(op, rawCmp, 0);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe
+bool intUnsignedCmp(EXP op, dinteger_t n1, dinteger_t n2) @safe nothrow
 {
     return numCmp!dinteger_t(op, n1, n2);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe
+bool intSignedCmp(EXP op, sinteger_t n1, sinteger_t n2) @safe nothrow
 {
     return numCmp!sinteger_t(op, n1, n2);
 }
 
 /// Returns e1 OP e2; where OP is ==, !=, <, >=, etc. Result is 0 or 1
-bool realCmp(EXP op, real_t r1, real_t r2) @safe
+bool realCmp(EXP op, real_t r1, real_t r2) @safe nothrow
 {
     // Don't rely on compiler, handle NAN arguments separately
     if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
@@ -1105,7 +1106,7 @@  private int ctfeCmpArrays(const ref Loc loc, Expression e1, Expression e2, uinte
 /* Given a delegate expression e, return .funcptr.
  * If e is NullExp, return NULL.
  */
-private FuncDeclaration funcptrOf(Expression e) @safe
+private FuncDeclaration funcptrOf(Expression e) @safe nothrow
 {
     assert(e.type.ty == Tdelegate);
     if (auto de = e.isDelegateExp())
@@ -1116,7 +1117,7 @@  private FuncDeclaration funcptrOf(Expression e) @safe
     return null;
 }
 
-private bool isArray(const Expression e) @safe
+private bool isArray(const Expression e) @safe nothrow
 {
     return e.op == EXP.arrayLiteral || e.op == EXP.string_ || e.op == EXP.slice || e.op == EXP.null_;
 }
@@ -1270,8 +1271,8 @@  private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
         size_t dim = es1.keys.length;
         if (es2.keys.length != dim)
             return 1;
-        bool* used = cast(bool*)mem.xmalloc(bool.sizeof * dim);
-        memset(used, 0, bool.sizeof * dim);
+        BitArray used;
+        used.length = dim;
         foreach (size_t i; 0 .. dim)
         {
             Expression k1 = (*es1.keys)[i];
@@ -1290,11 +1291,9 @@  private int ctfeRawCmp(const ref Loc loc, Expression e1, Expression e2, bool ide
             }
             if (!v2 || ctfeRawCmp(loc, v1, v2, identity))
             {
-                mem.xfree(used);
                 return 1;
             }
         }
-        mem.xfree(used);
         return 0;
     }
     else if (e1.op == EXP.assocArrayLiteral && e2.op == EXP.null_)
@@ -2000,9 +1999,8 @@  void showCtfeExpr(Expression e, int level = 0)
 UnionExp voidInitLiteral(Type t, VarDeclaration var)
 {
     UnionExp ue;
-    if (t.ty == Tsarray)
+    if (auto tsa = t.isTypeSArray())
     {
-        TypeSArray tsa = cast(TypeSArray)t;
         Expression elem = voidInitLiteral(tsa.next, var).copy();
         // For aggregate value types (structs, static arrays) we must
         // create an a separate copy for each element.
@@ -2019,9 +2017,8 @@  UnionExp voidInitLiteral(Type t, VarDeclaration var)
         ArrayLiteralExp ae = ue.exp().isArrayLiteralExp();
         ae.ownedByCtfe = OwnedBy.ctfe;
     }
-    else if (t.ty == Tstruct)
+    else if (auto ts = t.isTypeStruct())
     {
-        TypeStruct ts = cast(TypeStruct)t;
         auto exps = new Expressions(ts.sym.fields.length);
         foreach (size_t i;  0 .. ts.sym.fields.length)
         {
diff --git a/gcc/d/dmd/dcast.d b/gcc/d/dmd/dcast.d
index eb3890bb58f..14c67f062a3 100644
--- a/gcc/d/dmd/dcast.d
+++ b/gcc/d/dmd/dcast.d
@@ -1631,6 +1631,13 @@  Expression castTo(Expression e, Scope* sc, Type t, Type att = null)
         }
         else if (tob.ty == Tvector && t1b.ty != Tvector)
         {
+            if (t1b.ty == Tsarray)
+            {
+                // Casting static array to vector with same size, e.g. `cast(int4) int[4]`
+                if (t1b.size(e.loc) != tob.size(e.loc))
+                    goto Lfail;
+                return new VectorExp(e.loc, e, tob).expressionSemantic(sc);
+            }
             //printf("test1 e = %s, e.type = %s, tob = %s\n", e.toChars(), e.type.toChars(), tob.toChars());
             TypeVector tv = tob.isTypeVector();
             Expression result = new CastExp(e.loc, e, tv.elementType());
diff --git a/gcc/d/dmd/dclass.d b/gcc/d/dmd/dclass.d
index bae942cbd97..72b85cfc64e 100644
--- a/gcc/d/dmd/dclass.d
+++ b/gcc/d/dmd/dclass.d
@@ -180,7 +180,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
     int cppDtorVtblIndex = -1;
 
     /// to prevent recursive attempts
-    private bool inuse;
+    bool inuse;
 
     ThreeState isabstract;
 
@@ -367,7 +367,7 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
         baseok = Baseok.none;
     }
 
-    extern (D) private void classError(const(char)* fmt, const(char)* arg)
+    extern (D) final void classError(const(char)* fmt, const(char)* arg)
     {
         .error(loc, fmt, kind, toPrettyChars, arg);
     }
@@ -468,67 +468,6 @@  extern (C++) class ClassDeclaration : AggregateDeclaration
         return baseok >= Baseok.done;
     }
 
-    override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
-        //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
-        if (_scope && baseok < Baseok.semanticdone)
-        {
-            if (!inuse)
-            {
-                // must semantic on base class/interfaces
-                inuse = true;
-                dsymbolSemantic(this, null);
-                inuse = false;
-            }
-        }
-
-        if (!members || !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) && semanticRun < PASS.semanticdone)
-                classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
-            //*(char*)0=0;
-            return null;
-        }
-
-        auto s = ScopeDsymbol.search(loc, ident, flags);
-
-        // don't search imports of base classes
-        if (flags & SearchImportsOnly)
-            return s;
-
-        if (s)
-            return s;
-
-        // Search bases classes in depth-first, left to right order
-        foreach (b; (*baseclasses)[])
-        {
-            if (!b.sym)
-                continue;
-
-            if (!b.sym.symtab)
-            {
-                classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars());
-                continue;
-            }
-
-            import dmd.access : symbolIsVisible;
-
-            s = b.sym.search(loc, ident, flags);
-            if (!s)
-                continue;
-            else if (s == this) // happens if s is nested in this and derives from this
-                s = null;
-            else if (!(flags & IgnoreSymbolVisibility) && !(s.visible().kind == Visibility.Kind.protected_) && !symbolIsVisible(this, s))
-                s = null;
-            else
-                break;
-        }
-
-        return s;
-    }
-
     /************************************
      * Search base classes in depth-first, left-to-right order for
      * a class or interface named 'ident'.
@@ -675,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 = search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
+        Dsymbol s = this.search(Loc.initial, fd.ident, IgnoreAmbiguous | IgnoreErrors);
         if (!s)
         {
             //printf("not found\n");
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index 76a31f4caf7..0e125fdd001 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -421,18 +421,6 @@  extern (C++) abstract class Declaration : Dsymbol
         return Modifiable.yes;
     }
 
-    override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        Dsymbol s = Dsymbol.search(loc, ident, flags);
-        if (!s && type)
-        {
-            s = type.toDsymbol(_scope);
-            if (s)
-                s = s.search(loc, ident, flags);
-        }
-        return s;
-    }
-
     final bool isStatic() const pure nothrow @nogc @safe
     {
         return (storage_class & STC.static_) != 0;
diff --git a/gcc/d/dmd/declaration.h b/gcc/d/dmd/declaration.h
index 8cd295f1e06..a65fb4467e5 100644
--- a/gcc/d/dmd/declaration.h
+++ b/gcc/d/dmd/declaration.h
@@ -124,7 +124,6 @@  public:
     const char *kind() const override;
     uinteger_t size(const Loc &loc) override final;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override final;
 
     bool isStatic() const { return (storage_class & STCstatic) != 0; }
     LINK resolvedLinkage() const; // returns the linkage, resolving the target-specific `System` one
diff --git a/gcc/d/dmd/denum.d b/gcc/d/dmd/denum.d
index f33b5fd543e..797f6ee0a2d 100644
--- a/gcc/d/dmd/denum.d
+++ b/gcc/d/dmd/denum.d
@@ -83,25 +83,6 @@  extern (C++) final class EnumDeclaration : ScopeDsymbol
         return ed;
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        version (none)
-        {
-            printf("EnumDeclaration::addMember() %s\n", toChars());
-            for (size_t i = 0; i < members.length; i++)
-            {
-                EnumMember em = (*members)[i].isEnumMember();
-                printf("    member %s\n", em.toChars());
-            }
-        }
-        if (!isAnonymous())
-        {
-            ScopeDsymbol.addMember(sc, sds);
-        }
-
-        addEnumMembersToSymtab(this, sc, sds);
-    }
-
     override void setScope(Scope* sc)
     {
         if (semanticRun > PASS.initial)
@@ -126,19 +107,6 @@  extern (C++) final class EnumDeclaration : ScopeDsymbol
         return "enum";
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.EnumDeclaration::search('%s')\n", toChars(), ident.toChars());
-        if (_scope)
-        {
-            // Try one last time to resolve this enum
-            dsymbolSemantic(this, _scope);
-        }
-
-        Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
-        return s;
-    }
-
     // is Dsymbol deprecated?
     override bool isDeprecated() const
     {
diff --git a/gcc/d/dmd/dimport.d b/gcc/d/dmd/dimport.d
index d74c8603420..0132e49cbed 100644
--- a/gcc/d/dmd/dimport.d
+++ b/gcc/d/dmd/dimport.d
@@ -305,33 +305,6 @@  extern (C++) final class Import : Dsymbol
         return this;
     }
 
-    /*****************************
-     * Add import to sd's symbol table.
-     */
-    override void addMember(Scope* sc, ScopeDsymbol sd)
-    {
-        //printf("Import.addMember(this=%s, sd=%s, sc=%p)\n", toChars(), sd.toChars(), sc);
-        if (names.length == 0)
-            return Dsymbol.addMember(sc, sd);
-        if (aliasId)
-            Dsymbol.addMember(sc, sd);
-        /* Instead of adding the import to sd's symbol table,
-         * add each of the alias=name pairs
-         */
-        for (size_t i = 0; i < names.length; i++)
-        {
-            Identifier name = names[i];
-            Identifier _alias = aliases[i];
-            if (!_alias)
-                _alias = name;
-            auto tname = new TypeIdentifier(loc, name);
-            auto ad = new AliasDeclaration(loc, _alias, tname);
-            ad._import = this;
-            ad.addMember(sc, sd);
-            aliasdecls.push(ad);
-        }
-    }
-
     override void setScope(Scope* sc)
     {
         Dsymbol.setScope(sc);
@@ -348,19 +321,6 @@  extern (C++) final class Import : Dsymbol
         }
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.Import.search(ident = '%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
-        if (!pkg)
-        {
-            load(null);
-            mod.importAll(null);
-            mod.dsymbolSemantic(null);
-        }
-        // Forward it to the package/module
-        return pkg.search(loc, ident, flags);
-    }
-
     override bool overloadInsert(Dsymbol s)
     {
         /* Allow multiple imports with the same package base, but disallow
diff --git a/gcc/d/dmd/dmodule.d b/gcc/d/dmd/dmodule.d
index e6dde181fab..5f5de6390fb 100644
--- a/gcc/d/dmd/dmodule.d
+++ b/gcc/d/dmd/dmodule.d
@@ -268,22 +268,6 @@  extern (C++) class Package : ScopeDsymbol
         return isAncestorPackageOf(pkg.parent.isPackage());
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s Package.search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
-        flags &= ~SearchLocalsOnly;  // searching an import is always transitive
-        if (!isModule() && mod)
-        {
-            // Prefer full package name.
-            Dsymbol s = symtab ? symtab.lookup(ident) : null;
-            if (s)
-                return s;
-            //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
-            return mod.search(loc, ident, flags);
-        }
-        return ScopeDsymbol.search(loc, ident, flags);
-    }
-
     override void accept(Visitor v)
     {
         v.visit(this);
@@ -414,10 +398,10 @@  extern (C++) final class Module : Package
         return rootimports == ThreeState.yes;
     }
 
-    private Identifier searchCacheIdent;
-    private Dsymbol searchCacheSymbol;  // cached value of search
-    private int searchCacheFlags;       // cached flags
-    private bool insearch;
+    Identifier searchCacheIdent;
+    Dsymbol searchCacheSymbol;  // cached value of search
+    int searchCacheFlags;       // cached flags
+    bool insearch;
 
     /**
      * A root module is one that will be compiled all the way to
@@ -1036,47 +1020,6 @@  extern (C++) final class Module : Package
         }
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        /* Since modules can be circularly referenced,
-         * need to stop infinite recursive searches.
-         * This is done with the cache.
-         */
-        //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", toChars(), ident.toChars(), flags, insearch);
-        if (insearch)
-            return null;
-
-        /* Qualified module searches always search their imports,
-         * even if SearchLocalsOnly
-         */
-        if (!(flags & SearchUnqualifiedModule))
-            flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
-
-        if (searchCacheIdent == ident && searchCacheFlags == flags)
-        {
-            //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
-            //        toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
-            return searchCacheSymbol;
-        }
-
-        uint errors = global.errors;
-
-        insearch = true;
-        Dsymbol s = ScopeDsymbol.search(loc, ident, flags);
-        insearch = false;
-
-        if (errors == global.errors)
-        {
-            // https://issues.dlang.org/show_bug.cgi?id=10752
-            // Can cache the result only when it does not cause
-            // access error so the side-effect should be reproduced in later search.
-            searchCacheIdent = ident;
-            searchCacheSymbol = s;
-            searchCacheFlags = flags;
-        }
-        return s;
-    }
-
     override bool isPackageAccessible(Package p, Visibility visibility, int flags = 0)
     {
         if (insearch) // don't follow import cycles
diff --git a/gcc/d/dmd/dscope.d b/gcc/d/dmd/dscope.d
index 3853512005c..d68bcdaad40 100644
--- a/gcc/d/dmd/dscope.d
+++ b/gcc/d/dmd/dscope.d
@@ -66,13 +66,15 @@  enum SCOPE
 
     fullinst      = 0x10000,  /// fully instantiate templates
     ctfeBlock     = 0x20000,  /// inside a `if (__ctfe)` block
+    dip1000       = 0x40000,  /// dip1000 errors enabled for this scope
+    dip25         = 0x80000,  /// dip25 errors enabled for this scope
 }
 
 /// Flags that are carried along with a scope push()
 private enum PersistentFlags =
     SCOPE.contract | SCOPE.debug_ | SCOPE.ctfe | SCOPE.compile | SCOPE.constraint |
     SCOPE.noaccesscheck | SCOPE.ignoresymbolvisibility |
-    SCOPE.Cfile | SCOPE.ctfeBlock;
+    SCOPE.Cfile | SCOPE.ctfeBlock | SCOPE.dip1000 | SCOPE.dip25;
 
 extern (C++) struct Scope
 {
@@ -176,6 +178,10 @@  extern (C++) struct Scope
             m = m.parent;
         m.addMember(null, sc.scopesym);
         m.parent = null; // got changed by addMember()
+        if (global.params.useDIP1000 == FeatureState.enabled)
+            sc.flags |= SCOPE.dip1000;
+        if (global.params.useDIP25 == FeatureState.enabled)
+            sc.flags |= SCOPE.dip25;
         if (_module.filetype == FileType.c)
             sc.flags |= SCOPE.Cfile;
         // Create the module scope underneath the global scope
@@ -344,7 +350,7 @@  extern (C++) struct Scope
      * Returns:
      *  symbol if found, null if not
      */
-    extern (D) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
+    extern (C++) Dsymbol search(const ref Loc loc, Identifier ident, Dsymbol* pscopesym, int flags = IgnoreNone)
     {
         version (LOGSEARCH)
         {
@@ -821,4 +827,16 @@  extern (C++) struct Scope
     {
         return (flags & (SCOPE.ctfe | SCOPE.ctfeBlock | SCOPE.compile)) == 0;
     }
+
+    /// Returns: whether to raise DIP1000 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
+    extern (D) FeatureState useDIP1000()
+    {
+        return (flags & SCOPE.dip1000) ? FeatureState.enabled : FeatureState.disabled;
+    }
+
+    /// Returns: whether to raise DIP25 warnings (FeatureStabe.default) or errors (FeatureState.enabled)
+    extern (D) FeatureState useDIP25()
+    {
+        return (flags & SCOPE.dip25) ? FeatureState.enabled : FeatureState.disabled;
+    }
 }
diff --git a/gcc/d/dmd/dstruct.d b/gcc/d/dmd/dstruct.d
index f77a263a894..36e847c3f88 100644
--- a/gcc/d/dmd/dstruct.d
+++ b/gcc/d/dmd/dstruct.d
@@ -263,23 +263,6 @@  extern (C++) class StructDeclaration : AggregateDeclaration
         return sd;
     }
 
-    override final Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", toChars(), ident.toChars(), flags);
-        if (_scope && !symtab)
-            dsymbolSemantic(this, _scope);
-
-        if (!members || !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) && semanticRun < PASS.semanticdone)
-                .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars());
-            return null;
-        }
-
-        return ScopeDsymbol.search(loc, ident, flags);
-    }
-
     override const(char)* kind() const
     {
         return "struct";
diff --git a/gcc/d/dmd/dsymbol.d b/gcc/d/dmd/dsymbol.d
index 914213c1e57..a52745fcc0e 100644
--- a/gcc/d/dmd/dsymbol.d
+++ b/gcc/d/dmd/dsymbol.d
@@ -35,7 +35,6 @@  import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
-import dmd.expressionsem;
 import dmd.func;
 import dmd.globals;
 import dmd.id;
@@ -750,67 +749,6 @@  extern (C++) class Dsymbol : ASTNode
         return toAlias();
     }
 
-    void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        //printf("Dsymbol::addMember('%s')\n", toChars());
-        //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
-        //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
-        parent = sds;
-        if (isAnonymous()) // no name, so can't add it to symbol table
-            return;
-
-        if (!sds.symtabInsert(this)) // if name is already defined
-        {
-            if (isAliasDeclaration() && !_scope)
-                setScope(sc);
-            Dsymbol s2 = sds.symtabLookup(this,ident);
-            /* https://issues.dlang.org/show_bug.cgi?id=17434
-             *
-             * If we are trying to add an import to the symbol table
-             * that has already been introduced, then keep the one with
-             * larger visibility. This is fine for imports because if
-             * we have multiple imports of the same file, if a single one
-             * is public then the symbol is reachable.
-             */
-            if (auto i1 = isImport())
-            {
-                if (auto i2 = s2.isImport())
-                {
-                    if (sc.explicitVisibility && sc.visibility > i2.visibility)
-                        sds.symtab.update(this);
-                }
-            }
-
-            // If using C tag/prototype/forward declaration rules
-            if (sc.flags & SCOPE.Cfile && !this.isImport())
-            {
-                if (handleTagSymbols(*sc, this, s2, sds))
-                    return;
-                if (handleSymbolRedeclarations(*sc, this, s2, sds))
-                    return;
-
-                sds.multiplyDefined(Loc.initial, this, s2);  // ImportC doesn't allow overloading
-                errors = true;
-                return;
-            }
-
-            if (!s2.overloadInsert(this))
-            {
-                sds.multiplyDefined(Loc.initial, this, s2);
-                errors = true;
-            }
-        }
-        if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
-        {
-            if (ident == Id.__sizeof ||
-                !(sc && sc.flags & SCOPE.Cfile) && (ident == Id.__xalignof || ident == Id._mangleof))
-            {
-                .error(loc, "%s `%s` `.%s` property cannot be redefined", kind, toPrettyChars, ident.toChars());
-                errors = true;
-            }
-        }
-    }
-
     /*************************************
      * Set scope for future semantic analysis so we can
      * deal better with forward references.
@@ -831,21 +769,6 @@  extern (C++) class Dsymbol : ASTNode
     {
     }
 
-    /*********************************************
-     * Search for ident as member of s.
-     * Params:
-     *  loc = location to print for error messages
-     *  ident = identifier to search for
-     *  flags = IgnoreXXXX
-     * Returns:
-     *  null if not found
-     */
-    Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
-    {
-        //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", this, toChars(), ident.toChars());
-        return null;
-    }
-
     extern (D) final Dsymbol search_correct(Identifier ident)
     {
         /***************************************************
@@ -870,7 +793,7 @@  extern (C++) class Dsymbol : ASTNode
         if (global.gag)
             return null; // don't do it for speculative compiles; too time consuming
         // search for exact name first
-        if (auto s = search(Loc.initial, ident, IgnoreErrors))
+        if (auto s = this.search(Loc.initial, ident, IgnoreErrors))
             return s;
         return speller!symbol_search_fp(ident.toString());
     }
@@ -1339,12 +1262,12 @@  extern (C++) class ScopeDsymbol : Dsymbol
     Dsymbols* members;          // all Dsymbol's in this scope
     DsymbolTable symtab;        // members[] sorted into table
     uint endlinnum;             // the linnumber of the statement after the scope (0 if unknown)
-
-private:
     /// symbols whose members have been imported, i.e. imported modules and template mixins
     Dsymbols* importedScopes;
     Visibility.Kind* visibilities; // array of Visibility.Kind, one for each import
 
+private:
+
     import dmd.root.bitarray;
     BitArray accessiblePackages, privateAccessiblePackages;// whitelists of accessible (imported) packages
 
@@ -1373,166 +1296,7 @@  public:
         return sds;
     }
 
-    /*****************************************
-     * This function is #1 on the list of functions that eat cpu time.
-     * Be very, very careful about slowing it down.
-     */
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", toChars(), ident.toChars(), flags);
-        //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
-
-        // Look in symbols declared in this module
-        if (symtab && !(flags & SearchImportsOnly))
-        {
-            //printf(" look in locals\n");
-            auto s1 = symtab.lookup(ident);
-            if (s1)
-            {
-                //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
-                return s1;
-            }
-        }
-        //printf(" not found in locals\n");
-
-        // Look in imported scopes
-        if (!importedScopes)
-            return null;
-
-        //printf(" look in imports\n");
-        Dsymbol s = null;
-        OverloadSet a = null;
-        // Look in imported modules
-        for (size_t i = 0; i < importedScopes.length; i++)
-        {
-            // If private import, don't search it
-            if ((flags & IgnorePrivateImports) && visibilities[i] == Visibility.Kind.private_)
-                continue;
-            int sflags = flags & (IgnoreErrors | IgnoreAmbiguous); // remember these in recursive searches
-            Dsymbol ss = (*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)
-                    continue;
-            }
-            else // mixin template
-            {
-                if (flags & SearchImportsOnly)
-                    continue;
-
-                sflags |= SearchLocalsOnly;
-            }
-
-            /* Don't find private members if ss is a module
-             */
-            Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
-            import dmd.access : symbolIsVisible;
-            if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(this, s2))
-                continue;
-            if (!s)
-            {
-                s = s2;
-                if (s && s.isOverloadSet())
-                    a = mergeOverloadSet(ident, a, s);
-            }
-            else if (s2 && s != s2)
-            {
-                if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
-                {
-                    /* After following aliases, we found the same
-                     * symbol, so it's not an ambiguity.  But if one
-                     * alias is deprecated or less accessible, prefer
-                     * the other.
-                     */
-                    if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
-                        s = s2;
-                }
-                else
-                {
-                    /* Two imports of the same module should be regarded as
-                     * the same.
-                     */
-                    Import i1 = s.isImport();
-                    Import i2 = s2.isImport();
-                    if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
-                    {
-                        /* https://issues.dlang.org/show_bug.cgi?id=8668
-                         * Public selective import adds AliasDeclaration in module.
-                         * To make an overload set, resolve aliases in here and
-                         * get actual overload roots which accessible via s and s2.
-                         */
-                        s = s.toAlias();
-                        s2 = s2.toAlias();
-                        /* If both s2 and s are overloadable (though we only
-                         * need to check s once)
-                         */
-
-                        auto so2 = s2.isOverloadSet();
-                        if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
-                        {
-                            if (symbolIsVisible(this, s2))
-                            {
-                                a = mergeOverloadSet(ident, a, s2);
-                            }
-                            if (!symbolIsVisible(this, s))
-                                s = s2;
-                            continue;
-                        }
-
-                        /* Two different overflow sets can have the same members
-                         * https://issues.dlang.org/show_bug.cgi?id=16709
-                         */
-                        auto so = s.isOverloadSet();
-                        if (so && so2)
-                        {
-                            if (so.a.length == so2.a.length)
-                            {
-                                foreach (j; 0 .. so.a.length)
-                                {
-                                    if (so.a[j] !is so2.a[j])
-                                        goto L1;
-                                }
-                                continue;  // the same
-                              L1:
-                                {   } // different
-                            }
-                        }
-
-                        if (flags & IgnoreAmbiguous) // if return NULL on ambiguity
-                            return null;
-
-                        /* If two imports from C import files, pick first one, as C has global name space
-                         */
-                        if (s.isCsymbol() && s2.isCsymbol())
-                            continue;
-
-                        if (!(flags & IgnoreErrors))
-                            ScopeDsymbol.multiplyDefined(loc, s, s2);
-                        break;
-                    }
-                }
-            }
-        }
-        if (s)
-        {
-            /* Build special symbol if we had multiple finds
-             */
-            if (a)
-            {
-                if (!s.isOverloadSet())
-                    a = mergeOverloadSet(ident, a, s);
-                s = a;
-            }
-            //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
-            return s;
-        }
-        //printf(" not found in imports\n");
-        return null;
-    }
-
-    extern (D) private OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
+    extern (D) final OverloadSet mergeOverloadSet(Identifier ident, OverloadSet os, Dsymbol s)
     {
         if (!os)
         {
@@ -1844,40 +1608,6 @@  extern (C++) final class WithScopeSymbol : ScopeDsymbol
         this.withstate = withstate;
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
-        if (flags & SearchImportsOnly)
-            return null;
-        // Acts as proxy to the with class declaration
-        Dsymbol s = null;
-        Expression eold = null;
-        for (Expression e = withstate.exp; e && e != eold; e = resolveAliasThis(_scope, e, true))
-        {
-            if (auto se = e.isScopeExp())
-            {
-                s = se.sds;
-            }
-            else if (e.isTypeExp())
-            {
-                s = e.type.toDsymbol(null);
-            }
-            else
-            {
-                Type t = e.type.toBasetype();
-                s = t.toDsymbol(null);
-            }
-            if (s)
-            {
-                s = s.search(loc, ident, flags);
-                if (s)
-                    return s;
-            }
-            eold = e;
-        }
-        return null;
-    }
-
     override inout(WithScopeSymbol) isWithScopeSymbol() inout
     {
         return this;
@@ -1896,217 +1626,28 @@  extern (C++) final class ArrayScopeSymbol : ScopeDsymbol
 {
     // either a SliceExp, an IndexExp, an ArrayExp, a TypeTuple or a TupleDeclaration.
     // Discriminated using DYNCAST and, for expressions, also EXP
-    private RootObject arrayContent;
-    Scope* sc;
+    RootObject arrayContent;
 
     extern (D) this(Scope* sc, Expression exp) nothrow @safe
     {
         super(exp.loc, null);
         assert(exp.op == EXP.index || exp.op == EXP.slice || exp.op == EXP.array);
-        this.sc = sc;
+        this._scope = sc;
         this.arrayContent = exp;
     }
 
     extern (D) this(Scope* sc, TypeTuple type) nothrow @safe
     {
-        this.sc = sc;
+        this._scope = sc;
         this.arrayContent = type;
     }
 
     extern (D) this(Scope* sc, TupleDeclaration td) nothrow @safe
     {
-        this.sc = sc;
+        this._scope = sc;
         this.arrayContent = td;
     }
 
-    /// This override is used to solve `$`
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = IgnoreNone)
-    {
-        //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
-        if (ident != Id.dollar)
-            return null;
-
-        VarDeclaration* pvar;
-        Expression ce;
-
-        static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
-        {
-
-            /* $ gives the number of type entries in the type tuple
-             */
-            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
-            Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t);
-            v._init = new ExpInitializer(Loc.initial, e);
-            v.storage_class |= STC.temp | STC.static_ | STC.const_;
-            v.dsymbolSemantic(sc);
-            return v;
-        }
-
-        const DYNCAST kind = arrayContent.dyncast();
-        switch (kind) with (DYNCAST)
-        {
-        case dsymbol:
-            TupleDeclaration td = cast(TupleDeclaration) arrayContent;
-            /* $ gives the number of elements in the tuple
-             */
-            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
-            Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t);
-            v._init = new ExpInitializer(Loc.initial, e);
-            v.storage_class |= STC.temp | STC.static_ | STC.const_;
-            v.dsymbolSemantic(sc);
-            return v;
-        case type:
-            return dollarFromTypeTuple(loc, cast(TypeTuple) arrayContent, sc);
-        default:
-            break;
-        }
-        Expression exp = cast(Expression) arrayContent;
-        if (auto ie = exp.isIndexExp())
-        {
-            /* array[index] where index is some function of $
-             */
-            pvar = &ie.lengthVar;
-            ce = ie.e1;
-        }
-        else if (auto se = exp.isSliceExp())
-        {
-            /* array[lwr .. upr] where lwr or upr is some function of $
-             */
-            pvar = &se.lengthVar;
-            ce = se.e1;
-        }
-        else if (auto ae = exp.isArrayExp())
-        {
-            /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
-             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
-             */
-            pvar = &ae.lengthVar;
-            ce = ae.e1;
-        }
-        else
-        {
-            /* Didn't find $, look in enclosing scope(s).
-             */
-            return null;
-        }
-        ce = ce.lastComma();
-        /* If we are indexing into an array that is really a type
-         * tuple, rewrite this as an index into a type tuple and
-         * try again.
-         */
-        if (auto te = ce.isTypeExp())
-        {
-            if (auto ttp = te.type.isTypeTuple())
-                return dollarFromTypeTuple(loc, ttp, sc);
-        }
-        /* *pvar is lazily initialized, so if we refer to $
-         * multiple times, it gets set only once.
-         */
-        if (!*pvar) // if not already initialized
-        {
-            /* Create variable v and set it to the value of $
-             */
-            VarDeclaration v;
-            Type t;
-            if (auto tupexp = ce.isTupleExp())
-            {
-                /* It is for an expression tuple, so the
-                 * length will be a const.
-                 */
-                Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t);
-                v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
-                v.storage_class |= STC.temp | STC.static_ | STC.const_;
-            }
-            else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
-            {
-                // Look for opDollar
-                assert(exp.op == EXP.array || exp.op == EXP.slice);
-                AggregateDeclaration ad = isAggregate(t);
-                assert(ad);
-                Dsymbol s = ad.search(loc, Id.opDollar);
-                if (!s) // no dollar exists -- search in higher scope
-                    return null;
-                s = s.toAlias();
-                Expression e = null;
-                // Check for multi-dimensional opDollar(dim) template.
-                if (TemplateDeclaration td = s.isTemplateDeclaration())
-                {
-                    dinteger_t dim = 0;
-                    if (auto ae = exp.isArrayExp())
-                    {
-                        dim = ae.currentDimension;
-                    }
-                    else if (exp.isSliceExp())
-                    {
-                        dim = 0; // slices are currently always one-dimensional
-                    }
-                    else
-                    {
-                        assert(0);
-                    }
-                    auto tiargs = new Objects();
-                    Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
-                    edim = edim.expressionSemantic(sc);
-                    tiargs.push(edim);
-                    e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
-                }
-                else
-                {
-                    /* opDollar exists, but it's not a template.
-                     * This is acceptable ONLY for single-dimension indexing.
-                     * Note that it's impossible to have both template & function opDollar,
-                     * because both take no arguments.
-                     */
-                    auto ae = exp.isArrayExp();
-                    if (ae && ae.arguments.length != 1)
-                    {
-                        error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
-                        return null;
-                    }
-                    Declaration d = s.isDeclaration();
-                    assert(d);
-                    e = new DotVarExp(loc, ce, d);
-                }
-                e = e.expressionSemantic(sc);
-                if (!e.type)
-                    error(exp.loc, "`%s` has no value", e.toChars());
-                t = e.type.toBasetype();
-                if (t && t.ty == Tfunction)
-                    e = new CallExp(e.loc, e);
-                v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
-                v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
-            }
-            else
-            {
-                /* For arrays, $ will either be a compile-time constant
-                 * (in which case its value in set during constant-folding),
-                 * or a variable (in which case an expression is created in
-                 * toir.c).
-                 */
-
-                // https://issues.dlang.org/show_bug.cgi?id=16213
-                // For static arrays $ is known at compile time,
-                // so declare it as a manifest constant.
-                auto tsa = ce.type ? ce.type.isTypeSArray() : null;
-                if (tsa)
-                {
-                    auto e = new ExpInitializer(loc, tsa.dim);
-                    v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest);
-                }
-                else
-                {
-                    auto e = new VoidInitializer(Loc.initial);
-                    e.type = Type.tsize_t;
-                    v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
-                    v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
-                }
-            }
-            *pvar = v;
-        }
-        (*pvar).dsymbolSemantic(sc);
-        return (*pvar);
-    }
-
     override inout(ArrayScopeSymbol) isArrayScopeSymbol() inout
     {
         return this;
diff --git a/gcc/d/dmd/dsymbol.h b/gcc/d/dmd/dsymbol.h
index 027897532d1..e0c2046bf90 100644
--- a/gcc/d/dmd/dsymbol.h
+++ b/gcc/d/dmd/dsymbol.h
@@ -228,10 +228,8 @@  public:
     virtual const char *kind() const;
     virtual Dsymbol *toAlias();                 // resolve real symbol
     virtual Dsymbol *toAlias2();
-    virtual void addMember(Scope *sc, ScopeDsymbol *sds);
     virtual void setScope(Scope *sc);
     virtual void importAll(Scope *sc);
-    virtual Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone);
     virtual bool overloadInsert(Dsymbol *s);
     virtual uinteger_t size(const Loc &loc);
     virtual bool isforwardRef();
@@ -331,16 +329,14 @@  public:
     Dsymbols *members;          // all Dsymbol's in this scope
     DsymbolTable *symtab;       // members[] sorted into table
     unsigned endlinnum;         // the linnumber of the statement after the scope (0 if unknown)
-
-private:
     Dsymbols *importedScopes;   // imported Dsymbol's
     Visibility::Kind *visibilities;   // array of `Visibility.Kind`, one for each import
 
+private:
     BitArray accessiblePackages, privateAccessiblePackages;
 
 public:
     ScopeDsymbol *syntaxCopy(Dsymbol *s) override;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     virtual void importScope(Dsymbol *s, Visibility visibility);
     virtual bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0);
     bool isforwardRef() override final;
@@ -362,7 +358,6 @@  class WithScopeSymbol final : public ScopeDsymbol
 public:
     WithStatement *withstate;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
 
     WithScopeSymbol *isWithScopeSymbol() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
@@ -372,12 +367,8 @@  public:
 
 class ArrayScopeSymbol final : public ScopeDsymbol
 {
-private:
-    RootObject *arrayContent;
 public:
-    Scope *sc;
-
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = IgnoreNone) override;
+    RootObject *arrayContent;
 
     ArrayScopeSymbol *isArrayScopeSymbol() override { return this; }
     void accept(Visitor *v) override { v->visit(this); }
@@ -437,3 +428,6 @@  public:
     // Number of symbols in symbol table
     size_t length() const;
 };
+
+void addMember(Dsymbol *dsym, Scope *sc, ScopeDsymbol *sds);
+Dsymbol *search(Dsymbol *d, const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly);
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 637edd7bf08..430377ff874 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -23,6 +23,7 @@  import dmd.astenums;
 import dmd.attrib;
 import dmd.blockexit;
 import dmd.clone;
+import dmd.cond;
 import dmd.compiler;
 import dmd.dcast;
 import dmd.dclass;
@@ -1141,7 +1142,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                         else if (auto ale = ex.isArrayLiteralExp())
                         {
                             // or an array literal assigned to a `scope` variable
-                            if (global.params.useDIP1000 == FeatureState.enabled
+                            if (sc.useDIP1000 == FeatureState.enabled
                                 && !dsym.type.nextOf().needsDestruction())
                                 ale.onstack = true;
                         }
@@ -1170,10 +1171,12 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                     // https://issues.dlang.org/show_bug.cgi?id=14166
                     // Don't run CTFE for the temporary variables inside typeof
                     dsym._init = dsym._init.initializerSemantic(sc, dsym.type, sc.intypeof == 1 ? INITnointerpret : INITinterpret);
+                    import dmd.semantic2 : lowerStaticAAs;
+                    lowerStaticAAs(dsym, sc);
                     const init_err = dsym._init.isExpInitializer();
                     if (init_err && init_err.exp.op == EXP.showCtfeContext)
                     {
-                         errorSupplemental(dsym.loc, "compile time context created here");
+                        errorSupplemental(dsym.loc, "compile time context created here");
                     }
                 }
             }
@@ -1979,7 +1982,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
         if (!cd.compiled)
         {
             cd.decl = compileIt(cd);
-            cd.AttribDeclaration.addMember(sc, cd.scopesym);
+            attribAddMember(cd, sc, cd.scopesym);
             cd.compiled = true;
 
             if (cd._scope && cd.decl)
@@ -3385,7 +3388,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
             if (!tf.isNaked() && !(funcdecl.isThis() || funcdecl.isNested()))
             {
-                import core.bitop;
+                import core.bitop : popcnt;
                 auto mods = MODtoChars(tf.mod);
                 .error(funcdecl.loc, "%s `%s` without `this` cannot be `%s`", funcdecl.kind, funcdecl.toPrettyChars, mods);
                 if (tf.next && tf.next.ty != Tvoid && popcnt(tf.mod) == 1)
@@ -5831,6 +5834,365 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
     }
 }
 
+/*
+Adds dsym as a member of scope sds.
+
+Params:
+    dsym = dsymbol to inserted
+    sc = scope where the dsymbol is declared
+    sds = ScopeDsymbol where dsym is inserted
+*/
+extern(C++) void addMember(Dsymbol dsym, Scope* sc, ScopeDsymbol sds)
+{
+    auto addMemberVisitor = new AddMemberVisitor(sc, sds);
+    dsym.accept(addMemberVisitor);
+}
+
+private void attribAddMember(AttribDeclaration atb, Scope* sc, ScopeDsymbol sds)
+{
+    Dsymbols* d = atb.include(sc);
+    if (d)
+    {
+        Scope* sc2 = atb.newScope(sc);
+        d.foreachDsymbol( s => s.addMember(sc2, sds) );
+        if (sc2 != sc)
+            sc2.pop();
+    }
+}
+
+private extern(C++) class AddMemberVisitor : Visitor
+{
+    alias visit = Visitor.visit;
+
+    Scope* sc;
+    ScopeDsymbol sds;
+
+    this(Scope* sc, ScopeDsymbol sds)
+    {
+        this.sc = sc;
+        this.sds = sds;
+    }
+
+    override void visit(Dsymbol dsym)
+    {
+        //printf("Dsymbol::addMember('%s')\n", toChars());
+        //printf("Dsymbol::addMember(this = %p, '%s' scopesym = '%s')\n", this, toChars(), sds.toChars());
+        //printf("Dsymbol::addMember(this = %p, '%s' sds = %p, sds.symtab = %p)\n", this, toChars(), sds, sds.symtab);
+        dsym.parent = sds;
+        if (dsym.isAnonymous()) // no name, so can't add it to symbol table
+            return;
+
+        if (!sds.symtabInsert(dsym)) // if name is already defined
+        {
+            if (dsym.isAliasDeclaration() && !dsym._scope)
+                dsym.setScope(sc);
+            Dsymbol s2 = sds.symtabLookup(dsym, dsym.ident);
+            /* https://issues.dlang.org/show_bug.cgi?id=17434
+             *
+             * If we are trying to add an import to the symbol table
+             * that has already been introduced, then keep the one with
+             * larger visibility. This is fine for imports because if
+             * we have multiple imports of the same file, if a single one
+             * is public then the symbol is reachable.
+             */
+            if (auto i1 = dsym.isImport())
+            {
+                if (auto i2 = s2.isImport())
+                {
+                    if (sc.explicitVisibility && sc.visibility > i2.visibility)
+                        sds.symtab.update(dsym);
+                }
+            }
+
+            // If using C tag/prototype/forward declaration rules
+            if (sc.flags & SCOPE.Cfile && !dsym.isImport())
+            {
+                if (handleTagSymbols(*sc, dsym, s2, sds))
+                    return;
+                if (handleSymbolRedeclarations(*sc, dsym, s2, sds))
+                    return;
+
+                sds.multiplyDefined(Loc.initial, dsym, s2);  // ImportC doesn't allow overloading
+                dsym.errors = true;
+                return;
+            }
+
+            if (!s2.overloadInsert(dsym))
+            {
+                sds.multiplyDefined(Loc.initial, dsym, s2);
+                dsym.errors = true;
+            }
+        }
+        if (sds.isAggregateDeclaration() || sds.isEnumDeclaration())
+        {
+            if (dsym.ident == Id.__sizeof ||
+                !(sc && sc.flags & SCOPE.Cfile) && (dsym.ident == Id.__xalignof || dsym.ident == Id._mangleof))
+            {
+                .error(dsym.loc, "%s `%s` `.%s` property cannot be redefined", dsym.kind, dsym.toPrettyChars, dsym.ident.toChars());
+                dsym.errors = true;
+            }
+        }
+    }
+
+
+    override void visit(StaticAssert _)
+    {
+        // we didn't add anything
+    }
+
+    /*****************************
+     * Add import to sd's symbol table.
+     */
+    override void visit(Import imp)
+    {
+        //printf("Import.addMember(this=%s, sds=%s, sc=%p)\n", imp.toChars(), sds.toChars(), sc);
+        if (imp.names.length == 0)
+            return visit(cast(Dsymbol)imp);
+        if (imp.aliasId)
+            visit(cast(Dsymbol)imp);
+
+        /* Instead of adding the import to sds's symbol table,
+         * add each of the alias=name pairs
+         */
+        for (size_t i = 0; i < imp.names.length; i++)
+        {
+            Identifier name = imp.names[i];
+            Identifier _alias = imp.aliases[i];
+            if (!_alias)
+                _alias = name;
+            auto tname = new TypeIdentifier(imp.loc, name);
+            auto ad = new AliasDeclaration(imp.loc, _alias, tname);
+            ad._import = imp;
+            addMember(ad, sc, sds);
+            imp.aliasdecls.push(ad);
+        }
+    }
+
+    override void visit(AttribDeclaration atb)
+    {
+       attribAddMember(atb, sc, sds);
+    }
+
+    override void visit(StorageClassDeclaration stcd)
+    {
+        Dsymbols* d = stcd.include(sc);
+        if (d)
+        {
+            Scope* sc2 = stcd.newScope(sc);
+
+            d.foreachDsymbol( (s)
+            {
+                //printf("\taddMember %s to %s\n", s.toChars(), sds.toChars());
+                // STC.local needs to be attached before the member is added to the scope (because it influences the parent symbol)
+                if (auto decl = s.isDeclaration())
+                {
+                    decl.storage_class |= stcd.stc & STC.local;
+                    if (auto sdecl = s.isStorageClassDeclaration()) // TODO: why is this not enough to deal with the nested case?
+                    {
+                        sdecl.stc |= stcd.stc & STC.local;
+                    }
+                }
+                s.addMember(sc2, sds);
+            });
+
+            if (sc2 != sc)
+                sc2.pop();
+        }
+    }
+
+    override void visit(VisibilityDeclaration visd)
+    {
+        if (visd.pkg_identifiers)
+        {
+            Dsymbol tmp;
+            Package.resolve(visd.pkg_identifiers, &tmp, null);
+            visd.visibility.pkg = tmp ? tmp.isPackage() : null;
+            visd.pkg_identifiers = null;
+        }
+        if (visd.visibility.kind == Visibility.Kind.package_ && visd.visibility.pkg && sc._module)
+        {
+            Module m = sc._module;
+
+            // https://issues.dlang.org/show_bug.cgi?id=17441
+            // While isAncestorPackageOf does an equality check, the fix for the issue adds a check to see if
+            // each package's .isModule() properites are equal.
+            //
+            // Properties generated from `package(foo)` i.e. visibility.pkg have .isModule() == null.
+            // This breaks package declarations of the package in question if they are declared in
+            // the same package.d file, which _do_ have a module associated with them, and hence a non-null
+            // isModule()
+            if (!m.isPackage() || !visd.visibility.pkg.ident.equals(m.isPackage().ident))
+            {
+                Package pkg = m.parent ? m.parent.isPackage() : null;
+                if (!pkg || !visd.visibility.pkg.isAncestorPackageOf(pkg))
+                    .error(visd.loc, "%s `%s` does not bind to one of ancestor packages of module `%s`", visd.kind(), visd.toPrettyChars(false), m.toPrettyChars(true));
+            }
+        }
+        attribAddMember(visd, sc, sds);
+    }
+
+    override void visit(StaticIfDeclaration sid)
+    {
+        //printf("StaticIfDeclaration::addMember() '%s'\n", sid.toChars());
+        /* This is deferred until the condition evaluated later (by the include() call),
+         * so that expressions in the condition can refer to declarations
+         * in the same scope, such as:
+         *
+         * template Foo(int i)
+         * {
+         *     const int j = i + 1;
+         *     static if (j == 3)
+         *         const int k;
+         * }
+         */
+        sid.scopesym = sds;
+    }
+
+
+    override void visit(StaticForeachDeclaration sfd)
+    {
+        // used only for caching the enclosing symbol
+        sfd.scopesym = sds;
+    }
+
+    /***************************************
+     * Lazily initializes the scope to forward to.
+     */
+    override void visit(ForwardingAttribDeclaration fad)
+    {
+        fad.sym.parent = sds;
+        sds = fad.sym;
+        attribAddMember(fad, sc, fad.sym);
+    }
+
+    override void visit(MixinDeclaration md)
+    {
+        //printf("MixinDeclaration::addMember(sc = %p, sds = %p, memnum = %d)\n", sc, sds, md.memnum);
+        md.scopesym = sds;
+    }
+
+    override void visit(DebugSymbol ds)
+    {
+        //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), ds.toChars());
+        Module m = sds.isModule();
+        // Do not add the member to the symbol table,
+        // just make sure subsequent debug declarations work.
+        if (ds.ident)
+        {
+            if (!m)
+            {
+                .error(ds.loc, "%s `%s` declaration must be at module level", ds.kind, ds.toPrettyChars);
+                ds.errors = true;
+            }
+            else
+            {
+                if (findCondition(m.debugidsNot, ds.ident))
+                {
+                    .error(ds.loc, "%s `%s` defined after use", ds.kind, ds.toPrettyChars);
+                    ds.errors = true;
+                }
+                if (!m.debugids)
+                    m.debugids = new Identifiers();
+                m.debugids.push(ds.ident);
+            }
+        }
+        else
+        {
+            if (!m)
+            {
+                .error(ds.loc, "%s `%s` level declaration must be at module level", ds.kind, ds.toPrettyChars);
+                ds.errors = true;
+            }
+            else
+                m.debuglevel = ds.level;
+        }
+    }
+
+    override void visit(VersionSymbol vs)
+    {
+        //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), vs.toChars());
+        Module m = sds.isModule();
+        // Do not add the member to the symbol table,
+        // just make sure subsequent debug declarations work.
+        if (vs.ident)
+        {
+            VersionCondition.checkReserved(vs.loc, vs.ident.toString());
+            if (!m)
+            {
+                .error(vs.loc, "%s `%s` declaration must be at module level", vs.kind, vs.toPrettyChars);
+                vs.errors = true;
+            }
+            else
+            {
+                if (findCondition(m.versionidsNot, vs.ident))
+                {
+                    .error(vs.loc, "%s `%s` defined after use", vs.kind, vs.toPrettyChars);
+                    vs.errors = true;
+                }
+                if (!m.versionids)
+                    m.versionids = new Identifiers();
+                m.versionids.push(vs.ident);
+            }
+        }
+        else
+        {
+            if (!m)
+            {
+                .error(vs.loc, "%s `%s` level declaration must be at module level", vs.kind, vs.toPrettyChars);
+                vs.errors = true;
+            }
+            else
+                m.versionlevel = vs.level;
+        }
+    }
+
+    override void visit(Nspace ns)
+    {
+        visit(cast(Dsymbol)ns);
+
+        if (ns.members)
+        {
+            if (!ns.symtab)
+                ns.symtab = new DsymbolTable();
+            // The namespace becomes 'imported' into the enclosing scope
+            for (Scope* sce = sc; 1; sce = sce.enclosing)
+            {
+                ScopeDsymbol sds2 = sce.scopesym;
+                if (sds2)
+                {
+                    sds2.importScope(ns, Visibility(Visibility.Kind.public_));
+                    break;
+                }
+            }
+            assert(sc);
+            sc = sc.push(ns);
+            sc.linkage = LINK.cpp; // namespaces default to C++ linkage
+            sc.parent = ns;
+            ns.members.foreachDsymbol(s => s.addMember(sc, ns));
+            sc.pop();
+        }
+    }
+
+    override void visit(EnumDeclaration ed)
+    {
+        version (none)
+        {
+            printf("EnumDeclaration::addMember() %s\n", ed.toChars());
+            for (size_t i = 0; i < ed.members.length; i++)
+            {
+                EnumMember em = (*ed.members)[i].isEnumMember();
+                printf("    member %s\n", em.toChars());
+            }
+        }
+        if (!ed.isAnonymous())
+        {
+            visit(cast(Dsymbol)ed);
+        }
+
+        addEnumMembersToSymtab(ed, sc, sds);
+    }
+}
+
 /*******************************************
  * Add members of EnumDeclaration to the symbol table(s).
  * Params:
@@ -5904,7 +6266,7 @@  private bool isDRuntimeHook(Identifier id)
         id == Id._d_arraysetlengthTImpl || id == Id._d_arraysetlengthT ||
         id == Id._d_arraysetlengthTTrace ||
         id == Id._d_arrayappendT || id == Id._d_arrayappendTTrace ||
-        id == Id._d_arrayappendcTXImpl;
+        id == Id._d_arrayappendcTX;
 }
 
 void templateInstanceSemantic(TemplateInstance tempinst, Scope* sc, ArgumentList argumentList)
@@ -7431,3 +7793,617 @@  void checkPrintfScanfSignature(FuncDeclaration funcdecl, TypeFunction f, Scope*
             p, funcdecl.toChars());
     }
 }
+
+/*********************************************
+ * Search for ident as member of d.
+ * Params:
+ *  d = dsymbol where ident is searched for
+ *  loc = location to print for error messages
+ *  ident = identifier to search for
+ *  flags = IgnoreXXXX
+ * Returns:
+ *  null if not found
+ */
+extern(C++) Dsymbol search(Dsymbol d, const ref Loc loc, Identifier ident, int flags = IgnoreNone)
+{
+    scope v = new SearchVisitor(loc, ident, flags);
+    d.accept(v);
+    return v.result;
+}
+
+private extern(C++) class SearchVisitor : Visitor
+{
+    alias visit = Visitor.visit;
+
+    const Loc loc;
+    Identifier ident;
+    int flags;
+    Dsymbol result;
+
+    this(const ref Loc loc, Identifier ident, int flags)
+    {
+        this.loc = loc;
+        this.ident = ident;
+        this.flags = flags;
+    }
+
+    void setResult(Dsymbol d)
+    {
+        result = d;
+    }
+
+    override void visit(Dsymbol d)
+    {
+        //printf("Dsymbol::search(this=%p,%s, ident='%s')\n", d, d.toChars(), ident.toChars());
+        return setResult(null);
+    }
+
+    override void visit(ScopeDsymbol sds)
+    {
+        //printf("%s.ScopeDsymbol::search(ident='%s', flags=x%x)\n", sds.toChars(), ident.toChars(), flags);
+        //if (strcmp(ident.toChars(),"c") == 0) *(char*)0=0;
+
+        // Look in symbols declared in this module
+        if (sds.symtab && !(flags & SearchImportsOnly))
+        {
+            //printf(" look in locals\n");
+            auto s1 = sds.symtab.lookup(ident);
+            if (s1)
+            {
+                //printf("\tfound in locals = '%s.%s'\n",toChars(),s1.toChars());
+                return setResult(s1);
+            }
+        }
+        //printf(" not found in locals\n");
+
+        // Look in imported scopes
+        if (!sds.importedScopes)
+            return setResult(null);
+
+        //printf(" look in imports\n");
+        Dsymbol s = null;
+        OverloadSet a = null;
+        // Look in imported modules
+        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_)
+                continue;
+            int sflags = flags & (IgnoreErrors | 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)
+                    continue;
+            }
+            else // mixin template
+            {
+                if (flags & SearchImportsOnly)
+                    continue;
+
+                sflags |= SearchLocalsOnly;
+            }
+
+            /* Don't find private members if ss is a module
+             */
+            Dsymbol s2 = ss.search(loc, ident, sflags | (ss.isModule() ? IgnorePrivateImports : IgnoreNone));
+            import dmd.access : symbolIsVisible;
+            if (!s2 || !(flags & IgnoreSymbolVisibility) && !symbolIsVisible(sds, s2))
+                continue;
+            if (!s)
+            {
+                s = s2;
+                if (s && s.isOverloadSet())
+                    a = sds.mergeOverloadSet(ident, a, s);
+            }
+            else if (s2 && s != s2)
+            {
+                if (s.toAlias() == s2.toAlias() || s.getType() == s2.getType() && s.getType())
+                {
+                    /* After following aliases, we found the same
+                     * symbol, so it's not an ambiguity.  But if one
+                     * alias is deprecated or less accessible, prefer
+                     * the other.
+                     */
+                    if (s.isDeprecated() || s.visible() < s2.visible() && s2.visible().kind != Visibility.Kind.none)
+                        s = s2;
+                }
+                else
+                {
+                    /* Two imports of the same module should be regarded as
+                     * the same.
+                     */
+                    Import i1 = s.isImport();
+                    Import i2 = s2.isImport();
+                    if (!(i1 && i2 && (i1.mod == i2.mod || (!i1.parent.isImport() && !i2.parent.isImport() && i1.ident.equals(i2.ident)))))
+                    {
+                        /* https://issues.dlang.org/show_bug.cgi?id=8668
+                         * Public selective import adds AliasDeclaration in module.
+                         * To make an overload set, resolve aliases in here and
+                         * get actual overload roots which accessible via s and s2.
+                         */
+                        s = s.toAlias();
+                        s2 = s2.toAlias();
+                        /* If both s2 and s are overloadable (though we only
+                         * need to check s once)
+                         */
+
+                        auto so2 = s2.isOverloadSet();
+                        if ((so2 || s2.isOverloadable()) && (a || s.isOverloadable()))
+                        {
+                            if (symbolIsVisible(sds, s2))
+                            {
+                                a = sds.mergeOverloadSet(ident, a, s2);
+                            }
+                            if (!symbolIsVisible(sds, s))
+                                s = s2;
+                            continue;
+                        }
+
+                        /* Two different overflow sets can have the same members
+                         * https://issues.dlang.org/show_bug.cgi?id=16709
+                         */
+                        auto so = s.isOverloadSet();
+                        if (so && so2)
+                        {
+                            if (so.a.length == so2.a.length)
+                            {
+                                foreach (j; 0 .. so.a.length)
+                                {
+                                    if (so.a[j] !is so2.a[j])
+                                        goto L1;
+                                }
+                                continue;  // the same
+                              L1:
+                                {   } // different
+                            }
+                        }
+
+                        if (flags & 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
+                         */
+                        if (s.isCsymbol() && s2.isCsymbol())
+                            continue;
+
+                        if (!(flags & IgnoreErrors))
+                            ScopeDsymbol.multiplyDefined(loc, s, s2);
+                        break;
+                    }
+                }
+            }
+        }
+        if (s)
+        {
+            /* Build special symbol if we had multiple finds
+             */
+            if (a)
+            {
+                if (!s.isOverloadSet())
+                    a = sds.mergeOverloadSet(ident, a, s);
+                s = a;
+            }
+            //printf("\tfound in imports %s.%s\n", toChars(), s.toChars());
+            return setResult(s);
+        }
+        //printf(" not found in imports\n");
+        return setResult(null);
+    }
+
+    override void visit(WithScopeSymbol ws)
+    {
+        //printf("WithScopeSymbol.search(%s)\n", ident.toChars());
+        if (flags & SearchImportsOnly)
+            return setResult(null);
+        // Acts as proxy to the with class declaration
+        Dsymbol s = null;
+        Expression eold = null;
+        for (Expression e = ws.withstate.exp; e && e != eold; e = resolveAliasThis(ws._scope, e, true))
+        {
+            if (auto se = e.isScopeExp())
+            {
+                s = se.sds;
+            }
+            else if (e.isTypeExp())
+            {
+                s = e.type.toDsymbol(null);
+            }
+            else
+            {
+                Type t = e.type.toBasetype();
+                s = t.toDsymbol(null);
+            }
+            if (s)
+            {
+                s = s.search(loc, ident, flags);
+                if (s)
+                    return setResult(s);
+            }
+            eold = e;
+        }
+        return setResult(null);
+    }
+
+    override void visit(ArrayScopeSymbol ass)
+    {
+        //printf("ArrayScopeSymbol::search('%s', flags = %d)\n", ident.toChars(), flags);
+        if (ident != Id.dollar)
+            return setResult(null);
+
+        VarDeclaration* pvar;
+        Expression ce;
+
+        static Dsymbol dollarFromTypeTuple(const ref Loc loc, TypeTuple tt, Scope* sc)
+        {
+
+            /* $ gives the number of type entries in the type tuple
+             */
+            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+            Expression e = new IntegerExp(Loc.initial, tt.arguments.length, Type.tsize_t);
+            v._init = new ExpInitializer(Loc.initial, e);
+            v.storage_class |= STC.temp | STC.static_ | STC.const_;
+            v.dsymbolSemantic(sc);
+            return v;
+        }
+
+        const DYNCAST kind = ass.arrayContent.dyncast();
+        switch (kind) with (DYNCAST)
+        {
+        case dsymbol:
+            TupleDeclaration td = cast(TupleDeclaration) ass.arrayContent;
+            /* $ gives the number of elements in the tuple
+             */
+            auto v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, null);
+            Expression e = new IntegerExp(Loc.initial, td.objects.length, Type.tsize_t);
+            v._init = new ExpInitializer(Loc.initial, e);
+            v.storage_class |= STC.temp | STC.static_ | STC.const_;
+            v.dsymbolSemantic(ass._scope);
+            return setResult(v);
+        case type:
+            return setResult(dollarFromTypeTuple(loc, cast(TypeTuple) ass.arrayContent, ass._scope));
+        default:
+            break;
+        }
+        Expression exp = cast(Expression) ass.arrayContent;
+        if (auto ie = exp.isIndexExp())
+        {
+            /* array[index] where index is some function of $
+             */
+            pvar = &ie.lengthVar;
+            ce = ie.e1;
+        }
+        else if (auto se = exp.isSliceExp())
+        {
+            /* array[lwr .. upr] where lwr or upr is some function of $
+             */
+            pvar = &se.lengthVar;
+            ce = se.e1;
+        }
+        else if (auto ae = exp.isArrayExp())
+        {
+            /* array[e0, e1, e2, e3] where e0, e1, e2 are some function of $
+             * $ is a opDollar!(dim)() where dim is the dimension(0,1,2,...)
+             */
+            pvar = &ae.lengthVar;
+            ce = ae.e1;
+        }
+        else
+        {
+            /* Didn't find $, look in enclosing scope(s).
+             */
+            return setResult(null);
+        }
+        ce = ce.lastComma();
+        /* If we are indexing into an array that is really a type
+         * tuple, rewrite this as an index into a type tuple and
+         * try again.
+         */
+        if (auto te = ce.isTypeExp())
+        {
+            if (auto ttp = te.type.isTypeTuple())
+                return setResult(dollarFromTypeTuple(loc, ttp, ass._scope));
+        }
+        /* *pvar is lazily initialized, so if we refer to $
+         * multiple times, it gets set only once.
+         */
+        if (!*pvar) // if not already initialized
+        {
+            /* Create variable v and set it to the value of $
+             */
+            VarDeclaration v;
+            Type t;
+            if (auto tupexp = ce.isTupleExp())
+            {
+                /* It is for an expression tuple, so the
+                 * length will be a const.
+                 */
+                Expression e = new IntegerExp(Loc.initial, tupexp.exps.length, Type.tsize_t);
+                v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, new ExpInitializer(Loc.initial, e));
+                v.storage_class |= STC.temp | STC.static_ | STC.const_;
+            }
+            else if (ce.type && (t = ce.type.toBasetype()) !is null && (t.ty == Tstruct || t.ty == Tclass))
+            {
+                // Look for opDollar
+                assert(exp.op == EXP.array || exp.op == EXP.slice);
+                AggregateDeclaration ad = isAggregate(t);
+                assert(ad);
+                Dsymbol s = ad.search(loc, Id.opDollar);
+                if (!s) // no dollar exists -- search in higher scope
+                    return setResult(null);
+                s = s.toAlias();
+                Expression e = null;
+                // Check for multi-dimensional opDollar(dim) template.
+                if (TemplateDeclaration td = s.isTemplateDeclaration())
+                {
+                    dinteger_t dim = 0;
+                    if (auto ae = exp.isArrayExp())
+                    {
+                        dim = ae.currentDimension;
+                    }
+                    else if (exp.isSliceExp())
+                    {
+                        dim = 0; // slices are currently always one-dimensional
+                    }
+                    else
+                    {
+                        assert(0);
+                    }
+                    auto tiargs = new Objects();
+                    Expression edim = new IntegerExp(Loc.initial, dim, Type.tsize_t);
+                    edim = edim.expressionSemantic(ass._scope);
+                    tiargs.push(edim);
+                    e = new DotTemplateInstanceExp(loc, ce, td.ident, tiargs);
+                }
+                else
+                {
+                    /* opDollar exists, but it's not a template.
+                     * This is acceptable ONLY for single-dimension indexing.
+                     * Note that it's impossible to have both template & function opDollar,
+                     * because both take no arguments.
+                     */
+                    auto ae = exp.isArrayExp();
+                    if (ae && ae.arguments.length != 1)
+                    {
+                        error(exp.loc, "`%s` only defines opDollar for one dimension", ad.toChars());
+                        return setResult(null);
+                    }
+                    Declaration d = s.isDeclaration();
+                    assert(d);
+                    e = new DotVarExp(loc, ce, d);
+                }
+                e = e.expressionSemantic(ass._scope);
+                if (!e.type)
+                    error(exp.loc, "`%s` has no value", e.toChars());
+                t = e.type.toBasetype();
+                if (t && t.ty == Tfunction)
+                    e = new CallExp(e.loc, e);
+                v = new VarDeclaration(loc, null, Id.dollar, new ExpInitializer(Loc.initial, e));
+                v.storage_class |= STC.temp | STC.ctfe | STC.rvalue;
+            }
+            else
+            {
+                /* For arrays, $ will either be a compile-time constant
+                 * (in which case its value in set during constant-folding),
+                 * or a variable (in which case an expression is created in
+                 * toir.c).
+                 */
+
+                // https://issues.dlang.org/show_bug.cgi?id=16213
+                // For static arrays $ is known at compile time,
+                // so declare it as a manifest constant.
+                auto tsa = ce.type ? ce.type.isTypeSArray() : null;
+                if (tsa)
+                {
+                    auto e = new ExpInitializer(loc, tsa.dim);
+                    v = new VarDeclaration(loc, tsa.dim.type, Id.dollar, e, STC.manifest);
+                }
+                else
+                {
+                    auto e = new VoidInitializer(Loc.initial);
+                    e.type = Type.tsize_t;
+                    v = new VarDeclaration(loc, Type.tsize_t, Id.dollar, e);
+                    v.storage_class |= STC.temp | STC.ctfe; // it's never a true static variable
+                }
+            }
+            *pvar = v;
+        }
+        (*pvar).dsymbolSemantic(ass._scope);
+        return setResult((*pvar));
+
+    }
+
+    override void visit(Import imp)
+    {
+        //printf("%s.Import.search(ident = '%s', flags = x%x)\n", imp.toChars(), ident.toChars(), flags);
+        if (!imp.pkg)
+        {
+            imp.load(null);
+            imp.mod.importAll(null);
+            imp.mod.dsymbolSemantic(null);
+        }
+        // Forward it to the package/module
+        return setResult(imp.pkg.search(loc, ident, flags));
+
+    }
+
+    override void visit(Nspace ns)
+    {
+        //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
+        if (ns._scope && !ns.symtab)
+            dsymbolSemantic(ns, ns._scope);
+
+        if (!ns.members || !ns.symtab) // opaque or semantic() is not yet called
+        {
+            if (!(flags & IgnoreErrors))
+                .error(loc, "%s `%s` is forward referenced when looking for `%s`", ns.kind, ns.toPrettyChars, ident.toChars());
+            return setResult(null);
+        }
+
+        visit(cast(ScopeDsymbol)ns);
+    }
+
+    override void visit(EnumDeclaration em)
+    {
+        //printf("%s.EnumDeclaration::search('%s')\n", em.toChars(), ident.toChars());
+        if (em._scope)
+        {
+            // Try one last time to resolve this enum
+            dsymbolSemantic(em, em._scope);
+        }
+
+        visit(cast(ScopeDsymbol)em);
+    }
+
+    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
+        if (!pkg.isModule() && pkg.mod)
+        {
+            // Prefer full package name.
+            Dsymbol s = pkg.symtab ? pkg.symtab.lookup(ident) : null;
+            if (s)
+                return setResult(s);
+            //printf("[%s] through pkdmod: %s\n", loc.toChars(), toChars());
+            return setResult(pkg.mod.search(loc, ident, flags));
+        }
+
+        visit(cast(ScopeDsymbol)pkg);
+    }
+
+    override void visit(Module m)
+    {
+        /* Since modules can be circularly referenced,
+         * need to stop infinite recursive searches.
+         * This is done with the cache.
+         */
+        //printf("%s Module.search('%s', flags = x%x) insearch = %d\n", m.toChars(), ident.toChars(), flags, m.insearch);
+        if (m.insearch)
+            return setResult(null);
+
+        /* Qualified module searches always search their imports,
+         * even if SearchLocalsOnly
+         */
+        if (!(flags & SearchUnqualifiedModule))
+            flags &= ~(SearchUnqualifiedModule | SearchLocalsOnly);
+
+        if (m.searchCacheIdent == ident && m.searchCacheFlags == flags)
+        {
+            //printf("%s Module::search('%s', flags = %d) insearch = %d searchCacheSymbol = %s\n",
+            //        toChars(), ident.toChars(), flags, insearch, searchCacheSymbol ? searchCacheSymbol.toChars() : "null");
+            return setResult(m.searchCacheSymbol);
+        }
+
+        uint errors = global.errors;
+
+        m.insearch = true;
+        visit(cast(ScopeDsymbol)m);
+        Dsymbol s = result;
+        m.insearch = false;
+
+        if (errors == global.errors)
+        {
+            // https://issues.dlang.org/show_bug.cgi?id=10752
+            // Can cache the result only when it does not cause
+            // access error so the side-effect should be reproduced in later search.
+            m.searchCacheIdent = ident;
+            m.searchCacheSymbol = s;
+            m.searchCacheFlags = flags;
+        }
+        return setResult(s);
+    }
+
+    override void visit(Declaration decl)
+    {
+        Dsymbol s = null;
+        if (decl.type)
+        {
+            s = decl.type.toDsymbol(decl._scope);
+            if (s)
+                s = s.search(loc, ident, flags);
+        }
+        return setResult(s);
+    }
+
+    override void visit(StructDeclaration sd)
+    {
+        //printf("%s.StructDeclaration::search('%s', flags = x%x)\n", sd.toChars(), ident.toChars(), flags);
+        if (sd._scope && !sd.symtab)
+            dsymbolSemantic(sd, sd._scope);
+
+        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)
+                .error(loc, "%s `%s` is forward referenced when looking for `%s`", sd.kind, sd.toPrettyChars, ident.toChars());
+            return setResult(null);
+        }
+
+        visit(cast(ScopeDsymbol)sd);
+    }
+
+    override void visit(ClassDeclaration cd)
+    {
+        //printf("%s.ClassDeclaration.search('%s', flags=x%x)\n", cd.toChars(), ident.toChars(), flags);
+        //if (_scope) printf("%s baseok = %d\n", toChars(), baseok);
+        if (cd._scope && cd.baseok < Baseok.semanticdone)
+        {
+            if (!cd.inuse)
+            {
+                // must semantic on base class/interfaces
+                cd.inuse = true;
+                dsymbolSemantic(cd, null);
+                cd.inuse = false;
+            }
+        }
+
+        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)
+                cd.classError("%s `%s` is forward referenced when looking for `%s`", ident.toChars());
+            //*(char*)0=0;
+            return setResult(null);
+        }
+
+        visit(cast(ScopeDsymbol)cd);
+        auto s = result;
+
+        // don't search imports of base classes
+        if (flags & SearchImportsOnly)
+            return setResult(s);
+
+        if (s)
+            return setResult(s);
+
+        // Search bases classes in depth-first, left to right order
+        foreach (b; (*cd.baseclasses)[])
+        {
+            if (!b.sym)
+                continue;
+
+            if (!b.sym.symtab)
+            {
+                cd.classError("%s `%s` base `%s` is forward referenced", b.sym.ident.toChars());
+                continue;
+            }
+
+            import dmd.access : symbolIsVisible;
+
+            s = b.sym.search(loc, ident, flags);
+            if (!s)
+                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))
+                s = null;
+            else
+                break;
+        }
+
+        return setResult(s);
+    }
+}
diff --git a/gcc/d/dmd/dtemplate.d b/gcc/d/dmd/dtemplate.d
index 4cf1bae7537..037e0d01196 100644
--- a/gcc/d/dmd/dtemplate.d
+++ b/gcc/d/dmd/dtemplate.d
@@ -746,7 +746,7 @@  extern (C++) final class TemplateDeclaration : ScopeDsymbol
         OutBuffer buf;
         HdrGenState hgs;
 
-        buf.writestring(ident.toString());
+        buf.writestring(ident == Id.ctor ? "this" : ident.toString());
         buf.writeByte('(');
         foreach (i, const tp; *parameters)
         {
@@ -763,6 +763,11 @@  extern (C++) final class TemplateDeclaration : ScopeDsymbol
             {
                 TypeFunction tf = cast(TypeFunction)fd.type;
                 buf.writestring(parametersTypeToChars(tf.parameterList));
+                if (tf.mod)
+                {
+                    buf.writeByte(' ');
+                    buf.MODtoBuffer(tf.mod);
+                }
             }
         }
 
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 7c76da99d1b..9f855743ef9 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -20,6 +20,7 @@  import dmd.astenums;
 import dmd.arraytypes;
 import dmd.attrib;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.globals;
 import dmd.hdrgen;
diff --git a/gcc/d/dmd/dversion.d b/gcc/d/dmd/dversion.d
index aa22532061e..31725c80b9b 100644
--- a/gcc/d/dmd/dversion.d
+++ b/gcc/d/dmd/dversion.d
@@ -68,43 +68,6 @@  extern (C++) final class DebugSymbol : Dsymbol
         }
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        //printf("DebugSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
-        Module m = sds.isModule();
-        // Do not add the member to the symbol table,
-        // just make sure subsequent debug declarations work.
-        if (ident)
-        {
-            if (!m)
-            {
-                .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars);
-                errors = true;
-            }
-            else
-            {
-                if (findCondition(m.debugidsNot, ident))
-                {
-                    .error(loc, "%s `%s` defined after use", kind, toPrettyChars);
-                    errors = true;
-                }
-                if (!m.debugids)
-                    m.debugids = new Identifiers();
-                m.debugids.push(ident);
-            }
-        }
-        else
-        {
-            if (!m)
-            {
-                .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars);
-                errors = true;
-            }
-            else
-                m.debuglevel = level;
-        }
-    }
-
     override const(char)* kind() const nothrow
     {
         return "debug";
@@ -162,44 +125,6 @@  extern (C++) final class VersionSymbol : Dsymbol
         }
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        //printf("VersionSymbol::addMember('%s') %s\n", sds.toChars(), toChars());
-        Module m = sds.isModule();
-        // Do not add the member to the symbol table,
-        // just make sure subsequent debug declarations work.
-        if (ident)
-        {
-            VersionCondition.checkReserved(loc, ident.toString());
-            if (!m)
-            {
-                .error(loc, "%s `%s` declaration must be at module level", kind, toPrettyChars);
-                errors = true;
-            }
-            else
-            {
-                if (findCondition(m.versionidsNot, ident))
-                {
-                    .error(loc, "%s `%s` defined after use", kind, toPrettyChars);
-                    errors = true;
-                }
-                if (!m.versionids)
-                    m.versionids = new Identifiers();
-                m.versionids.push(ident);
-            }
-        }
-        else
-        {
-            if (!m)
-            {
-                .error(loc, "%s `%s` level declaration must be at module level", kind, toPrettyChars);
-                errors = true;
-            }
-            else
-                m.versionlevel = level;
-        }
-    }
-
     override const(char)* kind() const nothrow
     {
         return "version";
diff --git a/gcc/d/dmd/enum.h b/gcc/d/dmd/enum.h
index be12c65e6d6..e17e8cf5b0a 100644
--- a/gcc/d/dmd/enum.h
+++ b/gcc/d/dmd/enum.h
@@ -46,12 +46,10 @@  public:
     bool inuse(bool v);
 
     EnumDeclaration *syntaxCopy(Dsymbol *s) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope *sc) override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
     Type *getType() override;
     const char *kind() const override;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     bool isDeprecated() const override;       // is Dsymbol deprecated?
     Visibility visible() override;
     bool isSpecial() const;
diff --git a/gcc/d/dmd/escape.d b/gcc/d/dmd/escape.d
index 3f85ea08320..e25fc84234e 100644
--- a/gcc/d/dmd/escape.d
+++ b/gcc/d/dmd/escape.d
@@ -25,7 +25,7 @@  import dmd.dsymbol;
 import dmd.errors;
 import dmd.expression;
 import dmd.func;
-import dmd.globals;
+import dmd.globals : FeatureState;
 import dmd.id;
 import dmd.identifier;
 import dmd.init;
@@ -169,7 +169,7 @@  bool checkMutableArguments(Scope* sc, FuncDeclaration fd, TypeFunction tf,
         if (!(eb.isMutable || eb2.isMutable))
             return;
 
-        if (!tf.islive && !(global.params.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
+        if (!tf.islive && !(sc.useDIP1000 == FeatureState.enabled && sc.func && sc.func.setUnsafe()))
             return;
 
         if (!gag)
@@ -377,7 +377,7 @@  bool checkParamArgumentEscape(Scope* sc, FuncDeclaration fdc, Identifier parId,
             sc.setUnsafeDIP1000(gag, arg.loc, msg, v, parId ? parId : fdc, fdc))
         {
             result = true;
-            printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), global.params.useDIP1000), vPar, 10);
+            printScopeFailure(previewSupplementalFunc(sc.isDeprecated(), sc.useDIP1000), vPar, 10);
         }
     }
 
@@ -1094,7 +1094,7 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
         {
             if (p == sc.func)
             {
-                result |= escapingRef(v, global.params.useDIP1000);
+                result |= escapingRef(v, sc.useDIP1000);
                 continue;
             }
         }
@@ -1110,7 +1110,7 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
         {
             //printf("escaping reference to local ref variable %s\n", v.toChars());
             //printf("storage class = x%llx\n", v.storage_class);
-            result |= escapingRef(v, global.params.useDIP25);
+            result |= escapingRef(v, sc.useDIP25);
             continue;
         }
         // Don't need to be concerned if v's parent does not return a ref
@@ -1125,12 +1125,12 @@  bool checkNewEscape(Scope* sc, Expression e, bool gag)
             const(char)* msg = "storing reference to outer local variable `%s` into allocated memory causes it to escape";
             if (!gag)
             {
-                previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+                previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
             }
 
             // If -preview=dip25 is used, the user wants an error
             // Otherwise, issue a deprecation
-            result |= (global.params.useDIP25 == FeatureState.enabled);
+            result |= (sc.useDIP25 == FeatureState.enabled);
         }
     }
 
@@ -1264,7 +1264,7 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                     // https://issues.dlang.org/show_bug.cgi?id=23191
                     if (!gag)
                     {
-                        previewErrorFunc(sc.isDeprecated(), global.params.useDIP1000)(e.loc,
+                        previewErrorFunc(sc.isDeprecated(), sc.useDIP1000)(e.loc,
                             "scope parameter `%s` may not be returned", v.toChars()
                         );
                         result = true;
@@ -1403,7 +1403,7 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                 {
                     //printf("escaping reference to local ref variable %s\n", v.toChars());
                     //printf("storage class = x%llx\n", v.storage_class);
-                    escapingRef(v, global.params.useDIP25);
+                    escapingRef(v, sc.useDIP25);
                     continue;
                 }
                 // Don't need to be concerned if v's parent does not return a ref
@@ -1415,7 +1415,7 @@  private bool checkReturnEscapeImpl(Scope* sc, Expression e, bool refs, bool gag)
                     {
                         const(char)* msg = "escaping reference to outer local variable `%s`";
                         if (!gag)
-                            previewErrorFunc(sc.isDeprecated(), global.params.useDIP25)(e.loc, msg, v.toChars());
+                            previewErrorFunc(sc.isDeprecated(), sc.useDIP25)(e.loc, msg, v.toChars());
                         result = true;
                         continue;
                     }
@@ -2588,7 +2588,7 @@  public
 bool setUnsafeDIP1000(Scope* sc, bool gag, Loc loc, const(char)* msg,
     RootObject arg0 = null, RootObject arg1 = null, RootObject arg2 = null)
 {
-    return setUnsafePreview(sc, global.params.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
+    return setUnsafePreview(sc, sc.useDIP1000, gag, loc, msg, arg0, arg1, arg2);
 }
 
 /***************************************
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index 47902213504..cd93e54932c 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -4617,7 +4617,9 @@  extern (C++) final class UshrAssignExp : BinAssignExp
  */
 extern (C++) class CatAssignExp : BinAssignExp
 {
-    extern (D) this(const ref Loc loc, Expression e1, Expression e2) @safe
+    Expression lowering;    // lowered druntime hook `_d_arrayappend{cTX,T}`
+
+    extern (D) this(const ref Loc loc, Expression e1, Expression e2)
     {
         super(loc, EXP.concatenateAssign, e1, e2);
     }
diff --git a/gcc/d/dmd/expression.h b/gcc/d/dmd/expression.h
index 12ca6b4566c..b4ace74b496 100644
--- a/gcc/d/dmd/expression.h
+++ b/gcc/d/dmd/expression.h
@@ -52,7 +52,7 @@  void expandTuples(Expressions *exps, Identifiers *names = nullptr);
 StringExp *toUTF8(StringExp *se, Scope *sc);
 Expression *resolveLoc(Expression *exp, const Loc &loc, Scope *sc);
 MATCH implicitConvTo(Expression *e, Type *t);
-Expression *toLvalue(Expression *_this, Scope *sc);
+Expression *toLvalue(Expression *_this, Scope *sc, const char* action);
 Expression *modifiableLvalue(Expression* exp, Scope *sc);
 
 typedef unsigned char OwnedBy;
@@ -1114,6 +1114,8 @@  public:
 class CatAssignExp : public BinAssignExp
 {
 public:
+    Expression *lowering;   // lowered druntime hook `_d_arrayappend{cTX,T}`
+
     void accept(Visitor *v) override { v->visit(this); }
 };
 
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index d55ab3bcb26..e6b90183b51 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -2150,7 +2150,7 @@  private bool checkNogc(FuncDeclaration f, ref Loc loc, Scope* sc)
      * verified instead. This is to keep errors related to the original code
      * and not the lowering.
      */
-    if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT)
+    if (f.ident == Id._d_newitemT || f.ident == Id._d_newarrayT || f.ident == Id._d_newarraymTX)
         return false;
 
     if (!f.isNogc())
@@ -3129,7 +3129,7 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
                     arg = ev.expressionSemantic(sc);
                 }
-                arg = arg.toLvalue(sc);
+                arg = arg.toLvalue(sc, "create `in` parameter from");
 
                 // Look for mutable misaligned pointer, etc., in @safe mode
                 err |= checkUnsafeAccess(sc, arg, false, true);
@@ -3147,7 +3147,7 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
                     ev = new CommaExp(arg.loc, ev, new VarExp(arg.loc, v));
                     arg = ev.expressionSemantic(sc);
                 }
-                arg = arg.toLvalue(sc);
+                arg = arg.toLvalue(sc, "create `ref` parameter from");
 
                 // Look for mutable misaligned pointer, etc., in @safe mode
                 err |= checkUnsafeAccess(sc, arg, false, true);
@@ -3166,7 +3166,7 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
                     err |= checkUnsafeAccess(sc, arg, false, true);
                     err |= checkDefCtor(arg.loc, t); // t must be default constructible
                 }
-                arg = arg.toLvalue(sc);
+                arg = arg.toLvalue(sc, "create `out` parameter from");
             }
             else if (p.isLazy())
             {
@@ -3209,7 +3209,7 @@  private bool functionParameters(const ref Loc loc, Scope* sc,
             const explicitScope = p.isLazy() ||
                 ((p.storageClass & STC.scope_) && !(p.storageClass & STC.scopeinferred));
             if ((pStc & (STC.scope_ | STC.lazy_)) &&
-                ((global.params.useDIP1000 == FeatureState.enabled) || explicitScope) &&
+                ((sc.useDIP1000 == FeatureState.enabled) || explicitScope) &&
                 !(pStc & STC.return_))
             {
                 /* Argument value cannot escape from the called function.
@@ -5115,23 +5115,23 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 tb = tb.isTypeDArray().next.toBasetype();
             }
 
-            if (nargs == 1)
-            {
-                if (global.params.betterC || !sc.needsCodegen())
+            if (global.params.betterC || !sc.needsCodegen())
                     goto LskipNewArrayLowering;
 
-                /* Class types may inherit base classes that have errors.
-                 * This may leak errors from the base class to the derived one
-                 * and then to the hook. Semantic analysis is performed eagerly
-                 * to a void this.
-                 */
-                if (auto tc = exp.type.nextOf.isTypeClass())
-                {
-                    tc.sym.dsymbolSemantic(sc);
-                    if (tc.sym.errors)
-                        goto LskipNewArrayLowering;
-                }
+            /* Class types may inherit base classes that have errors.
+                * This may leak errors from the base class to the derived one
+                * and then to the hook. Semantic analysis is performed eagerly
+                * to a void this.
+                */
+            if (auto tc = exp.type.nextOf.isTypeClass())
+            {
+                tc.sym.dsymbolSemantic(sc);
+                if (tc.sym.errors)
+                    goto LskipNewArrayLowering;
+            }
 
+            if (nargs == 1)
+            {
                 auto hook = global.params.tracegc ? Id._d_newarrayTTrace : Id._d_newarrayT;
                 if (!verifyHookExist(exp.loc, *sc, hook, "new array"))
                     goto LskipNewArrayLowering;
@@ -5163,6 +5163,45 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 arguments.push((*exp.arguments)[0]);
                 arguments.push(new IntegerExp(exp.loc, isShared, Type.tbool));
 
+                lowering = new CallExp(exp.loc, lowering, arguments);
+                exp.lowering = lowering.expressionSemantic(sc);
+            }
+            else
+            {
+                auto hook = global.params.tracegc ? Id._d_newarraymTXTrace : Id._d_newarraymTX;
+                if (!verifyHookExist(exp.loc, *sc, hook, "new multi-dimensional array"))
+                    goto LskipNewArrayLowering;
+
+                /* Lower the memory allocation and initialization of `new T[][]...[](n1, n2, ...)`
+                 * to `_d_newarraymTX!(T[][]...[], T)([n1, n2, ...])`.
+                 */
+                Expression lowering = new IdentifierExp(exp.loc, Id.empty);
+                lowering = new DotIdExp(exp.loc, lowering, Id.object);
+
+                auto tbn = exp.type.nextOf();
+                while (tbn.ty == Tarray)
+                    tbn = tbn.nextOf();
+                auto unqualTbn = tbn.unqualify(MODFlags.wild | MODFlags.const_ |
+                    MODFlags.immutable_ | MODFlags.shared_);
+
+                auto tiargs = new Objects();
+                tiargs.push(exp.type);
+                tiargs.push(unqualTbn);
+                lowering = new DotTemplateInstanceExp(exp.loc, lowering, hook, tiargs);
+
+                auto arguments = new Expressions();
+                if (global.params.tracegc)
+                {
+                    auto funcname = (sc.callsc && sc.callsc.func) ?
+                        sc.callsc.func.toPrettyChars() : sc.func.toPrettyChars();
+                    arguments.push(new StringExp(exp.loc, exp.loc.filename.toDString()));
+                    arguments.push(new IntegerExp(exp.loc, exp.loc.linnum, Type.tint32));
+                    arguments.push(new StringExp(exp.loc, funcname.toDString()));
+                }
+
+                arguments.push(new ArrayLiteralExp(exp.loc, Type.tsize_t.sarrayOf(nargs), exp.arguments));
+                arguments.push(new IntegerExp(exp.loc, tbn.isShared(), Type.tbool));
+
                 lowering = new CallExp(exp.loc, lowering, arguments);
                 exp.lowering = lowering.expressionSemantic(sc);
             }
@@ -8295,7 +8334,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 else
                 {
                     // `toLvalue` call further below is upon exp.e1, omitting & from the error message
-                    exp.toLvalue(sc);
+                    exp.toLvalue(sc, "take address of");
                     return setError();
                 }
             }
@@ -8385,7 +8424,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             }
         }
 
-        exp.e1 = exp.e1.toLvalue(sc);
+        exp.e1 = exp.e1.toLvalue(sc, "take address of");
         if (exp.e1.op == EXP.error)
         {
             result = exp.e1;
@@ -9017,14 +9056,6 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 return setError();
         }
 
-        // Look for casting to a vector type
-        if (tob.ty == Tvector && t1b.ty != Tvector)
-        {
-            result = new VectorExp(exp.loc, exp.e1, exp.to);
-            result = result.expressionSemantic(sc);
-            return;
-        }
-
         Expression ex = exp.e1.castTo(sc, exp.to);
         if (ex.op == EXP.error)
         {
@@ -11727,8 +11758,7 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
 
         result = res;
 
-        if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) &&
-            sc.needsCodegen())
+        if ((exp.op == EXP.concatenateAssign || exp.op == EXP.concatenateElemAssign) && sc.needsCodegen())
         {
             // if aa ordering is triggered, `res` will be a CommaExp
             // and `.e2` will be the rewritten original expression.
@@ -11772,7 +11802,9 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 arguments.push(exp.e1);
                 arguments.push(exp.e2);
                 Expression ce = new CallExp(exp.loc, id, arguments);
-                *output = ce.expressionSemantic(sc);
+
+                exp.lowering = ce.expressionSemantic(sc);
+                *output = exp;
             }
             else if (exp.op == EXP.concatenateElemAssign)
             {
@@ -11792,15 +11824,12 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 }
 
                 Identifier hook = global.params.tracegc ? Id._d_arrayappendcTXTrace : Id._d_arrayappendcTX;
-                if (!verifyHookExist(exp.loc, *sc, Id._d_arrayappendcTXImpl, "appending element to arrays", Id.object))
+                if (!verifyHookExist(exp.loc, *sc, hook, "appending element to arrays", Id.object))
                     return setError();
 
-                // Lower to object._d_arrayappendcTXImpl!(typeof(e1))._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
+                // Lower to object._d_arrayappendcTX{,Trace}(e1, 1), e1[$-1]=e2
                 Expression id = new IdentifierExp(exp.loc, Id.empty);
                 id = new DotIdExp(exp.loc, id, Id.object);
-                auto tiargs = new Objects();
-                tiargs.push(exp.e1.type);
-                id = new DotTemplateInstanceExp(exp.loc, id, Id._d_arrayappendcTXImpl, tiargs);
                 id = new DotIdExp(exp.loc, id, hook);
 
                 auto arguments = new Expressions();
@@ -11827,11 +11856,10 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 {
                     /* Before the template hook, this check was performed in e2ir.d
                      * for expressions like `a ~= a[$-1]`. Here, $ will be modified
-                     * by calling `_d_arrayappendcT`, so we need to save `a[$-1]` in
+                     * by calling `_d_arrayappendcTX`, so we need to save `a[$-1]` in
                      * a temporary variable.
                      */
                     value2 = extractSideEffect(sc, "__appendtmp", eValue2, value2, true);
-                    exp.e2 = value2;
 
                     // `__appendtmp*` will be destroyed together with the array `exp.e1`.
                     auto vd = eValue2.isDeclarationExp().declaration.isVarDeclaration();
@@ -11847,13 +11875,12 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 auto e0 = Expression.combine(ce, ae).expressionSemantic(sc);
                 e0 = Expression.combine(e0, value1);
                 e0 = Expression.combine(eValue1, e0);
-
                 e0 = Expression.combine(eValue2, e0);
 
-                *output = e0.expressionSemantic(sc);
+                exp.lowering = e0.expressionSemantic(sc);
+                *output = exp;
             }
         }
-
     }
 
     override void visit(AddExp exp)
@@ -15210,15 +15237,21 @@  Expression addDtorHook(Expression e, Scope* sc)
  * Params:
  *     _this = expression to convert
  *     sc = scope
+ *     action = for error messages, what the lvalue is needed for (e.g. take address of for `&x`, modify for `x++`)
  * Returns: converted expression, or `ErrorExp` on error
 */
-extern(C++) Expression toLvalue(Expression _this, Scope* sc)
+extern(C++) Expression toLvalue(Expression _this, Scope* sc, const(char)* action)
 {
-    return toLvalueImpl(_this, sc, _this);
+    return toLvalueImpl(_this, sc, action, _this);
 }
 
 // e = original un-lowered expression for error messages, in case of recursive calls
-private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
+private Expression toLvalueImpl(Expression _this, Scope* sc, const(char)* action, Expression e)
+{
+    if (!action)
+        action = "create lvalue of";
+
+    assert(e);
     Expression visit(Expression _this)
     {
         // BinaryAssignExp does not have an EXP associated
@@ -15230,9 +15263,11 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
             _this.loc = e.loc;
 
         if (e.op == EXP.type)
-            error(_this.loc, "`%s` is a `%s` definition and cannot be modified", e.type.toChars(), e.type.kind());
+            error(_this.loc, "cannot %s type `%s`", action, e.type.toChars());
+        else if (e.op == EXP.template_)
+            error(_this.loc, "cannot %s template `%s`, perhaps instantiate it first", action, e.toChars());
         else
-            error(_this.loc, "`%s` is not an lvalue and cannot be modified", e.toChars());
+            error(_this.loc, "cannot %s expression `%s` because it is not an lvalue", action, e.toChars());
 
         return ErrorExp.get();
     }
@@ -15241,7 +15276,7 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
     {
         if (!_this.loc.isValid())
             _this.loc = e.loc;
-        error(e.loc, "cannot modify constant `%s`", e.toChars());
+        error(e.loc, "cannot %s constant `%s`", action, e.toChars());
         return ErrorExp.get();
     }
 
@@ -15285,22 +15320,22 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
         auto var = _this.var;
         if (var.storage_class & STC.manifest)
         {
-            error(_this.loc, "manifest constant `%s` cannot be modified", var.toChars());
+            error(_this.loc, "cannot %s manifest constant `%s`", action, var.toChars());
             return ErrorExp.get();
         }
         if (var.storage_class & STC.lazy_ && !_this.delegateWasExtracted)
         {
-            error(_this.loc, "lazy variable `%s` cannot be modified", var.toChars());
+            error(_this.loc, "cannot %s lazy variable `%s`", action, var.toChars());
             return ErrorExp.get();
         }
         if (var.ident == Id.ctfe)
         {
-            error(_this.loc, "cannot modify compiler-generated variable `__ctfe`");
+            error(_this.loc, "cannot %s compiler-generated variable `__ctfe`", action);
             return ErrorExp.get();
         }
         if (var.ident == Id.dollar) // https://issues.dlang.org/show_bug.cgi?id=13574
         {
-            error(_this.loc, "cannot modify operator `$`");
+            error(_this.loc, "cannot %s operator `$`", action);
             return ErrorExp.get();
         }
         return _this;
@@ -15370,7 +15405,7 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
 
     Expression visitVectorArray(VectorArrayExp _this)
     {
-        _this.e1 = _this.e1.toLvalueImpl(sc, e);
+        _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
         return _this;
     }
 
@@ -15389,19 +15424,19 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
 
     Expression visitComma(CommaExp _this)
     {
-        _this.e2 = _this.e2.toLvalue(sc);
+        _this.e2 = _this.e2.toLvalue(sc, action);
         return _this;
     }
 
     Expression visitDelegatePointer(DelegatePtrExp _this)
     {
-        _this.e1 = _this.e1.toLvalueImpl(sc, e);
+        _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
         return _this;
     }
 
     Expression visitDelegateFuncptr(DelegateFuncptrExp _this)
     {
-        _this.e1 = _this.e1.toLvalueImpl(sc, e);
+        _this.e1 = _this.e1.toLvalueImpl(sc, action, e);
         return _this;
     }
 
@@ -15430,8 +15465,8 @@  private Expression toLvalueImpl(Expression _this, Scope* sc, Expression e) {
     {
         // convert (econd ? e1 : e2) to *(econd ? &e1 : &e2)
         CondExp e = cast(CondExp)(_this.copy());
-        e.e1 = _this.e1.toLvalue(sc).addressOf();
-        e.e2 = _this.e2.toLvalue(sc).addressOf();
+        e.e1 = _this.e1.toLvalue(sc, action).addressOf();
+        e.e2 = _this.e2.toLvalue(sc, action).addressOf();
         e.type = _this.type.pointerTo();
         return new PtrExp(_this.loc, e, _this.type);
 
@@ -15634,12 +15669,13 @@  extern(C++) Expression modifiableLvalue(Expression _this, Scope* sc)
 // e = original / un-lowered expression to print in error messages
 private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression e)
 {
+    assert(e);
     Expression visit(Expression exp)
     {
         //printf("Expression::modifiableLvalue() %s, type = %s\n", exp.toChars(), exp.type.toChars());
         // See if this expression is a modifiable lvalue (i.e. not const)
         if (exp.isBinAssignExp())
-            return exp.toLvalue(sc);
+            return exp.toLvalue(sc, "modify");
 
         auto type = exp.type;
         if (checkModifiable(exp, sc) == Modifiable.yes)
@@ -15672,7 +15708,7 @@  private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
                 return ErrorExp.get();
             }
         }
-        return exp.toLvalueImpl(sc, e);
+        return exp.toLvalueImpl(sc, "modify", e);
     }
 
     Expression visitString(StringExp exp)
@@ -15762,7 +15798,7 @@  private Expression modifiableLvalueImpl(Expression _this, Scope* sc, Expression
         }
         exp.e1 = exp.e1.modifiableLvalue(sc);
         exp.e2 = exp.e2.modifiableLvalue(sc);
-        return exp.toLvalue(sc);
+        return exp.toLvalue(sc, "modify");
     }
 
     switch(_this.op)
@@ -15803,7 +15839,7 @@  bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
     }
     if (sc.func && !sc.intypeof && !v.isDataseg())
     {
-        if (global.params.useDIP1000 != FeatureState.enabled &&
+        if (sc.useDIP1000 != FeatureState.enabled &&
             !(v.storage_class & STC.temp) &&
             sc.setUnsafe(false, exp.loc, "cannot take address of local `%s` in `@safe` function `%s`", v, sc.func))
         {
diff --git a/gcc/d/dmd/func.d b/gcc/d/dmd/func.d
index edf113e2160..351faa471f2 100644
--- a/gcc/d/dmd/func.d
+++ b/gcc/d/dmd/func.d
@@ -3241,13 +3241,6 @@  unittest
     assert(mismatches.isMutable);
 }
 
-private const(char)* prependSpace(const(char)* str)
-{
-    if (!str || !*str) return "";
-
-    return (" " ~ str.toDString() ~ "\0").ptr;
-}
-
 /// Flag used by $(LREF resolveFuncCall).
 enum FuncResolveFlag : ubyte
 {
@@ -3361,14 +3354,11 @@  FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
         const(char)* lastprms = parametersTypeToChars(tf1.parameterList);
         const(char)* nextprms = parametersTypeToChars(tf2.parameterList);
 
-        const(char)* mod1 = prependSpace(MODtoChars(tf1.mod));
-        const(char)* mod2 = prependSpace(MODtoChars(tf2.mod));
-
         .error(loc, "`%s.%s` called with argument types `%s` matches both:\n%s:     `%s%s%s`\nand:\n%s:     `%s%s%s`",
             s.parent.toPrettyChars(), s.ident.toChars(),
             fargsBuf.peekChars(),
-            m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, mod1,
-            m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, mod2);
+            m.lastf.loc.toChars(), m.lastf.toPrettyChars(), lastprms, tf1.modToChars(),
+            m.nextf.loc.toChars(), m.nextf.toPrettyChars(), nextprms, tf2.modToChars());
         return null;
     }
 
@@ -3422,15 +3412,25 @@  FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
     if (!tf)
         tf = fd.originalType.toTypeFunction();
 
-    if (tthis && !MODimplicitConv(tthis.mod, tf.mod)) // modifier mismatch
+    // modifier mismatch
+    if (tthis && (fd.isCtorDeclaration() ?
+        !MODimplicitConv(tf.mod, tthis.mod) :
+        !MODimplicitConv(tthis.mod, tf.mod)))
     {
         OutBuffer thisBuf, funcBuf;
         MODMatchToBuffer(&thisBuf, tthis.mod, tf.mod);
         auto mismatches = MODMatchToBuffer(&funcBuf, tf.mod, tthis.mod);
         if (hasOverloads)
         {
-            .error(loc, "none of the overloads of `%s` are callable using a %sobject",
-                   fd.ident.toChars(), thisBuf.peekChars());
+            OutBuffer buf;
+            buf.argExpTypesToCBuffer(fargs);
+            if (fd.isCtorDeclaration())
+                .error(loc, "none of the overloads of `%s` can construct a %sobject with argument types `(%s)`",
+                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+            else
+                .error(loc, "none of the overloads of `%s` are callable using a %sobject with argument types `(%s)`",
+                    fd.toChars(), thisBuf.peekChars(), buf.peekChars());
+
             if (!global.gag || global.params.v.showGaggedErrors)
                 printCandidates(loc, fd, sc.isDeprecated());
             return null;
@@ -3447,8 +3447,12 @@  FuncDeclaration resolveFuncCall(const ref Loc loc, Scope* sc, Dsymbol s,
             return null;
         }
 
-        .error(loc, "%smethod `%s` is not callable using a %sobject",
-               funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
+        if (fd.isCtorDeclaration())
+            .error(loc, "%s%s `%s` cannot construct a %sobject",
+                   funcBuf.peekChars(), fd.kind(), fd.toPrettyChars(), thisBuf.peekChars());
+        else
+            .error(loc, "%smethod `%s` is not callable using a %sobject",
+                   funcBuf.peekChars(), fd.toPrettyChars(), thisBuf.peekChars());
 
         if (mismatches.isNotShared)
             .errorSupplemental(fd.loc, "Consider adding `shared` here");
@@ -3535,11 +3539,17 @@  if (is(Decl == TemplateDeclaration) || is(Decl == FuncDeclaration))
             if (!print)
                 return true;
             auto tf = cast(TypeFunction) fd.type;
+            OutBuffer buf;
+            buf.writestring(fd.toPrettyChars());
+            buf.writestring(parametersTypeToChars(tf.parameterList));
+            if (tf.mod)
+            {
+                buf.writeByte(' ');
+                buf.MODtoBuffer(tf.mod);
+            }
             .errorSupplemental(fd.loc,
-                    printed ? "                `%s%s`" :
-                    single_candidate ? "Candidate is: `%s%s`" : "Candidates are: `%s%s`",
-                    fd.toPrettyChars(),
-                parametersTypeToChars(tf.parameterList));
+                printed ? "                `%s`" :
+                single_candidate ? "Candidate is: `%s`" : "Candidates are: `%s`", buf.peekChars());
         }
         else if (auto td = s.isTemplateDeclaration())
         {
@@ -4621,7 +4631,14 @@  bool setUnsafePreview(Scope* sc, FeatureState fs, bool gag, Loc loc, const(char)
       case default_:
         if (!sc.func)
             return false;
-        if (!sc.func.isSafeBypassingInference() && !sc.func.safetyViolation)
+        if (sc.func.isSafeBypassingInference())
+        {
+            if (!gag)
+            {
+                warning(loc, msg, arg0 ? arg0.toChars() : "", arg1 ? arg1.toChars() : "", arg2 ? arg2.toChars() : "");
+            }
+        }
+        else if (!sc.func.safetyViolation)
         {
             import dmd.func : AttributeViolation;
             sc.func.safetyViolation = new AttributeViolation(loc, msg, arg0, arg1, arg2);
diff --git a/gcc/d/dmd/hdrgen.d b/gcc/d/dmd/hdrgen.d
index 8325081dbd2..ac2dda3e89f 100644
--- a/gcc/d/dmd/hdrgen.d
+++ b/gcc/d/dmd/hdrgen.d
@@ -1943,7 +1943,7 @@  private void visitTemplateParameters(TemplateParameters* parameters, ref OutBuff
     {
         if (i)
             buf.writestring(", ");
-        p.templateParameterToBuffer(buf, &hgs);
+        toCBuffer(p, buf, hgs);
     }
 }
 
@@ -2885,10 +2885,10 @@  void floatToBuffer(Type type, const real_t value, ref OutBuffer buf, const bool
     }
 }
 
-private void templateParameterToBuffer(TemplateParameter tp, ref OutBuffer buf, HdrGenState* hgs)
+void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs)
 {
-    scope v = new TemplateParameterPrettyPrintVisitor(&buf, hgs);
-    tp.accept(v);
+    scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs);
+    (cast() tp).accept(v);
 }
 
 private extern (C++) final class TemplateParameterPrettyPrintVisitor : Visitor
@@ -3262,12 +3262,6 @@  void argExpTypesToCBuffer(ref OutBuffer buf, Expressions* arguments)
     }
 }
 
-void toCBuffer(const TemplateParameter tp, ref OutBuffer buf, ref HdrGenState hgs)
-{
-    scope v = new TemplateParameterPrettyPrintVisitor(&buf, &hgs);
-    (cast() tp).accept(v);
-}
-
 void arrayObjectsToBuffer(ref OutBuffer buf, Objects* objects)
 {
     if (!objects || !objects.length)
@@ -3837,7 +3831,7 @@  private void visitFuncIdentWithPrefix(TypeFunction t, const Identifier ident, Te
         {
             if (i)
                 buf.writestring(", ");
-            p.templateParameterToBuffer(buf, hgs);
+            toCBuffer(p, buf, *hgs);
         }
         buf.writeByte(')');
     }
@@ -3862,6 +3856,11 @@  private void initializerToBuffer(Initializer inx, ref OutBuffer buf, HdrGenState
         buf.writestring("void");
     }
 
+    void visitDefault(DefaultInitializer iz)
+    {
+        buf.writestring("{ }");
+    }
+
     void visitStruct(StructInitializer si)
     {
         //printf("StructInitializer::toCBuffer()\n");
diff --git a/gcc/d/dmd/id.d b/gcc/d/dmd/id.d
index 5fcda91b435..32221d94744 100644
--- a/gcc/d/dmd/id.d
+++ b/gcc/d/dmd/id.d
@@ -323,6 +323,8 @@  immutable Msgtable[] msgtable =
     { "_d_newitemTTrace" },
     { "_d_newarrayT" },
     { "_d_newarrayTTrace" },
+    { "_d_newarraymTX" },
+    { "_d_newarraymTXTrace" },
     { "_d_assert_fail" },
     { "dup" },
     { "_aaApply" },
@@ -366,7 +368,6 @@  immutable Msgtable[] msgtable =
     { "_d_arraysetlengthTTrace"},
     { "_d_arrayappendT" },
     { "_d_arrayappendTTrace" },
-    { "_d_arrayappendcTXImpl" },
     { "_d_arrayappendcTX" },
     { "_d_arrayappendcTXTrace" },
     { "_d_arraycatnTX" },
diff --git a/gcc/d/dmd/import.h b/gcc/d/dmd/import.h
index 31ee61a65fb..aeb3621f1eb 100644
--- a/gcc/d/dmd/import.h
+++ b/gcc/d/dmd/import.h
@@ -43,9 +43,7 @@  public:
     Import *syntaxCopy(Dsymbol *s) override; // copy only syntax trees
     void importAll(Scope *sc) override;
     Dsymbol *toAlias() override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope* sc) override;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     bool overloadInsert(Dsymbol *s) override;
 
     Import *isImport() override { return this; }
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index 98ac9038a0a..2c7699b45ec 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -20,6 +20,7 @@  import dmd.dcast;
 import dmd.declaration;
 import dmd.dscope;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.errors;
 import dmd.expression;
 import dmd.expressionsem;
diff --git a/gcc/d/dmd/init.d b/gcc/d/dmd/init.d
index ebcd011f8a1..e48410082bd 100644
--- a/gcc/d/dmd/init.d
+++ b/gcc/d/dmd/init.d
@@ -68,6 +68,11 @@  extern (C++) class Initializer : ASTNode
         return kind == InitKind.void_ ? cast(inout VoidInitializer)cast(void*)this : null;
     }
 
+    final inout(DefaultInitializer) isDefaultInitializer() inout @nogc nothrow pure
+    {
+        return kind == InitKind.default_ ? cast(inout DefaultInitializer)cast(void*)this : null;
+    }
+
     final inout(StructInitializer) isStructInitializer() inout @nogc nothrow pure
     {
         return kind == InitKind.struct_ ? cast(inout StructInitializer)cast(void*)this : null;
@@ -111,6 +116,24 @@  extern (C++) final class VoidInitializer : Initializer
     }
 }
 
+/***********************************************************
+ * The C23 default initializer `{ }`
+ */
+extern (C++) final class DefaultInitializer : Initializer
+{
+    Type type;      // type that this will initialize to
+
+    extern (D) this(const ref Loc loc) @safe
+    {
+        super(loc, InitKind.default_);
+    }
+
+    override void accept(Visitor v)
+    {
+        v.visit(this);
+    }
+}
+
 /***********************************************************
  */
 extern (C++) final class ErrorInitializer : Initializer
@@ -266,6 +289,11 @@  Initializer syntaxCopy(Initializer inx)
         return new VoidInitializer(vi.loc);
     }
 
+    static Initializer visitDefault(DefaultInitializer vi)
+    {
+        return new DefaultInitializer(vi.loc);
+    }
+
     static Initializer visitError(ErrorInitializer vi)
     {
         return vi;
@@ -352,6 +380,7 @@  mixin template VisitInitializer(Result)
         final switch (init.kind)
         {
             case InitKind.void_:    mixin(visitCase("Void"));    break;
+            case InitKind.default_: mixin(visitCase("Default")); break;
             case InitKind.error:    mixin(visitCase("Error"));   break;
             case InitKind.struct_:  mixin(visitCase("Struct"));  break;
             case InitKind.array:    mixin(visitCase("Array"));   break;
diff --git a/gcc/d/dmd/init.h b/gcc/d/dmd/init.h
index 67d0527a3b2..21bd07f4f39 100644
--- a/gcc/d/dmd/init.h
+++ b/gcc/d/dmd/init.h
@@ -20,6 +20,7 @@  class Expression;
 class Type;
 class ErrorInitializer;
 class VoidInitializer;
+class DefaultInitializer;
 class StructInitializer;
 class ArrayInitializer;
 class ExpInitializer;
@@ -37,6 +38,7 @@  public:
 
     ErrorInitializer   *isErrorInitializer();
     VoidInitializer    *isVoidInitializer();
+    DefaultInitializer *isDefaultInitializer();
     StructInitializer  *isStructInitializer();
     ArrayInitializer   *isArrayInitializer();
     ExpInitializer     *isExpInitializer();
@@ -53,6 +55,14 @@  public:
     void accept(Visitor *v) override { v->visit(this); }
 };
 
+class DefaultInitializer final : public Initializer
+{
+public:
+    Type *type;         // type that this will initialize to
+
+    void accept(Visitor *v) override { v->visit(this); }
+};
+
 class ErrorInitializer final : public Initializer
 {
 public:
diff --git a/gcc/d/dmd/initsem.d b/gcc/d/dmd/initsem.d
index 139db0f59e9..76c2d8916b0 100644
--- a/gcc/d/dmd/initsem.d
+++ b/gcc/d/dmd/initsem.d
@@ -24,6 +24,7 @@  import dmd.dinterpret;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
@@ -106,6 +107,7 @@  Expression toAssocArrayLiteral(ArrayInitializer ai)
  */
 extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Type tx, NeedInterpret needInterpret)
 {
+    //printf("initializerSemantic() tx: %p %s\n", tx, tx.toChars());
     Type t = tx;
 
     static Initializer err()
@@ -119,6 +121,12 @@  extern(C++) Initializer initializerSemantic(Initializer init, Scope* sc, ref Typ
         return i;
     }
 
+    Initializer visitDefault(DefaultInitializer i)
+    {
+        i.type = t;
+        return i;
+    }
+
     Initializer visitError(ErrorInitializer i)
     {
         return i;
@@ -1017,6 +1025,12 @@  Initializer inferType(Initializer init, Scope* sc)
         return new ErrorInitializer();
     }
 
+    Initializer visitDefault(DefaultInitializer i)
+    {
+        error(i.loc, "cannot infer type from default initializer");
+        return new ErrorInitializer();
+    }
+
     Initializer visitError(ErrorInitializer i)
     {
         return i;
@@ -1175,6 +1189,11 @@  extern (C++) Expression initializerToExpression(Initializer init, Type itype = n
         return null;
     }
 
+    Expression visitDefault(DefaultInitializer di)
+    {
+        return di.type ? di.type.defaultInit(Loc.initial, isCfile) : null;
+    }
+
     Expression visitError(ErrorInitializer)
     {
         return ErrorExp.get();
diff --git a/gcc/d/dmd/lambdacomp.d b/gcc/d/dmd/lambdacomp.d
index ec070d8ec0b..d19d435f240 100644
--- a/gcc/d/dmd/lambdacomp.d
+++ b/gcc/d/dmd/lambdacomp.d
@@ -22,6 +22,7 @@  import dmd.astenums;
 import dmd.declaration;
 import dmd.denum;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.expression;
 import dmd.func;
diff --git a/gcc/d/dmd/module.h b/gcc/d/dmd/module.h
index 6e8153d485a..92efc1656da 100644
--- a/gcc/d/dmd/module.h
+++ b/gcc/d/dmd/module.h
@@ -43,7 +43,6 @@  public:
 
     bool isAncestorPackageOf(const Package * const pkg) const;
 
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     void accept(Visitor *v) override { v->visit(this); }
 
     Module *isPackageMod();
@@ -124,7 +123,6 @@  public:
     Module *parse();    // syntactic parse
     void importAll(Scope *sc) override;
     int needModuleInfo();
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     bool isPackageAccessible(Package *p, Visibility visibility, int flags = 0) override;
     Dsymbol *symtabInsert(Dsymbol *s) override;
     static void runDeferredSemantic();
diff --git a/gcc/d/dmd/nogc.d b/gcc/d/dmd/nogc.d
index 59bf1d5d1d5..e59b01019f4 100644
--- a/gcc/d/dmd/nogc.d
+++ b/gcc/d/dmd/nogc.d
@@ -108,12 +108,6 @@  public:
                 return;
             f.printGCUsage(e.loc, "setting `length` may cause a GC allocation");
         }
-        else if (fd.ident == Id._d_arrayappendT || fd.ident == Id._d_arrayappendcTX)
-        {
-            if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
-                return;
-            f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
-        }
     }
 
     override void visit(ArrayLiteralExp e)
@@ -187,20 +181,14 @@  public:
 
     override void visit(CatAssignExp e)
     {
-        /* CatAssignExp will exist in `__traits(compiles, ...)` and in the `.e1` branch of a `__ctfe ? :` CondExp.
-         * The other branch will be `_d_arrayappendcTX(e1, 1), e1[$-1]=e2` which will generate the warning about
-         * GC usage. See visit(CallExp).
-         */
         if (checkOnly)
         {
             err = true;
             return;
         }
-        if (f.setGC(e.loc, null))
-        {
-            err = true;
+        if (setGC(e, "cannot use operator `~=` in `@nogc` %s `%s`"))
             return;
-        }
+        f.printGCUsage(e.loc, "operator `~=` may cause a GC allocation");
     }
 
     override void visit(CatExp e)
diff --git a/gcc/d/dmd/nspace.d b/gcc/d/dmd/nspace.d
index 2d3367af804..a49e0bf0cc2 100644
--- a/gcc/d/dmd/nspace.d
+++ b/gcc/d/dmd/nspace.d
@@ -85,33 +85,6 @@  extern (C++) final class Nspace : ScopeDsymbol
         return ns;
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        ScopeDsymbol.addMember(sc, sds);
-
-        if (members)
-        {
-            if (!symtab)
-                symtab = new DsymbolTable();
-            // The namespace becomes 'imported' into the enclosing scope
-            for (Scope* sce = sc; 1; sce = sce.enclosing)
-            {
-                ScopeDsymbol sds2 = sce.scopesym;
-                if (sds2)
-                {
-                    sds2.importScope(this, Visibility(Visibility.Kind.public_));
-                    break;
-                }
-            }
-            assert(sc);
-            sc = sc.push(this);
-            sc.linkage = LINK.cpp; // namespaces default to C++ linkage
-            sc.parent = this;
-            members.foreachDsymbol(s => s.addMember(sc, this));
-            sc.pop();
-        }
-    }
-
     override void setScope(Scope* sc)
     {
         ScopeDsymbol.setScope(sc);
@@ -126,22 +99,6 @@  extern (C++) final class Nspace : ScopeDsymbol
         }
     }
 
-    override Dsymbol search(const ref Loc loc, Identifier ident, int flags = SearchLocalsOnly)
-    {
-        //printf("%s.Nspace.search('%s')\n", toChars(), ident.toChars());
-        if (_scope && !symtab)
-            dsymbolSemantic(this, _scope);
-
-        if (!members || !symtab) // opaque or semantic() is not yet called
-        {
-            if (!(flags & IgnoreErrors))
-                .error(loc, "%s `%s` is forward referenced when looking for `%s`", kind, toPrettyChars, ident.toChars());
-            return null;
-        }
-
-        return ScopeDsymbol.search(loc, ident, flags);
-    }
-
     override bool hasPointers()
     {
         //printf("Nspace::hasPointers() %s\n", toChars());
diff --git a/gcc/d/dmd/nspace.h b/gcc/d/dmd/nspace.h
index e9fb7bdc777..7d30402c595 100644
--- a/gcc/d/dmd/nspace.h
+++ b/gcc/d/dmd/nspace.h
@@ -21,9 +21,7 @@  class Nspace final : public ScopeDsymbol
   public:
     Expression *identExp;
     Nspace *syntaxCopy(Dsymbol *s) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     void setScope(Scope *sc) override;
-    Dsymbol *search(const Loc &loc, Identifier *ident, int flags = SearchLocalsOnly) override;
     bool hasPointers() override;
     void setFieldOffset(AggregateDeclaration *ad, FieldState& fieldState, bool isunion) override;
     const char *kind() const override;
diff --git a/gcc/d/dmd/opover.d b/gcc/d/dmd/opover.d
index b445b7b707b..b7bc9257b3e 100644
--- a/gcc/d/dmd/opover.d
+++ b/gcc/d/dmd/opover.d
@@ -23,6 +23,7 @@  import dmd.declaration;
 import dmd.dscope;
 import dmd.dstruct;
 import dmd.dsymbol;
+import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
 import dmd.expression;
diff --git a/gcc/d/dmd/optimize.d b/gcc/d/dmd/optimize.d
index 69028fac21d..a9791684df4 100644
--- a/gcc/d/dmd/optimize.d
+++ b/gcc/d/dmd/optimize.d
@@ -928,6 +928,14 @@  Expression optimize(Expression e, int result, bool keepLvalue = false)
         }
     }
 
+    void visitCatAssign(CatAssignExp e)
+    {
+        if (auto lowering = e.lowering)
+            optimize(lowering, result, keepLvalue);
+        else
+            visitBinAssign(e);
+    }
+
     void visitBin(BinExp e)
     {
         //printf("BinExp::optimize(result = %d) %s\n", result, e.toChars());
@@ -1392,9 +1400,9 @@  Expression optimize(Expression e, int result, bool keepLvalue = false)
             case EXP.leftShiftAssign:
             case EXP.rightShiftAssign:
             case EXP.unsignedRightShiftAssign:
+            case EXP.concatenateDcharAssign: visitBinAssign(ex.isBinAssignExp()); break;
             case EXP.concatenateElemAssign:
-            case EXP.concatenateDcharAssign:
-            case EXP.concatenateAssign: visitBinAssign(ex.isBinAssignExp()); break;
+            case EXP.concatenateAssign:      visitCatAssign(cast(CatAssignExp) ex); break;
 
             case EXP.minusMinus:
             case EXP.plusPlus:
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index 51e522d71e4..f9d174ab14f 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -4878,30 +4878,11 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 AST.Declaration v;
                 AST.Dsymbol s;
 
-                // try to parse function type:
-                // TypeCtors? BasicType ( Parameters ) MemberFunctionAttributes
                 bool attributesAppended;
                 const StorageClass funcStc = parseTypeCtor();
-                Token* tlu = &token;
                 Token* tk;
-                if (token.value != TOK.function_ &&
-                    token.value != TOK.delegate_ &&
-                    isBasicType(&tlu) && tlu &&
-                    tlu.value == TOK.leftParenthesis)
-                {
-                    AST.Type tret = parseBasicType();
-                    auto parameterList = parseParameterList(null);
-
-                    parseAttributes();
-                    if (udas)
-                        error("user-defined attributes not allowed for `alias` declarations");
-
-                    attributesAppended = true;
-                    storage_class = appendStorageClass(storage_class, funcStc);
-                    AST.Type tf = new AST.TypeFunction(parameterList, tret, link, storage_class);
-                    v = new AST.AliasDeclaration(loc, ident, tf);
-                }
-                else if (token.value == TOK.function_ ||
+                // function literal?
+                if (token.value == TOK.function_ ||
                     token.value == TOK.delegate_ ||
                     token.value == TOK.leftParenthesis &&
                         skipAttributes(peekPastParen(&token), &tk) &&
@@ -4911,10 +4892,10 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                     token.value == TOK.ref_ && peekNext() == TOK.leftParenthesis &&
                         skipAttributes(peekPastParen(peek(&token)), &tk) &&
                         (tk.value == TOK.goesTo || tk.value == TOK.leftCurly) ||
-                    token.value == TOK.auto_ && peekNext() == TOK.ref_ &&
-                        peekNext2() == TOK.leftParenthesis &&
-                        skipAttributes(peekPastParen(peek(peek(&token))), &tk) &&
-                        (tk.value == TOK.goesTo || tk.value == TOK.leftCurly)
+                    token.value == TOK.auto_ &&
+                        (peekNext() == TOK.leftParenthesis || // for better error
+                            peekNext() == TOK.ref_ &&
+                            peekNext2() == TOK.leftParenthesis)
                    )
                 {
                     // function (parameters) { statements... }
@@ -4955,21 +4936,46 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
                 }
                 else
                 {
-                    parseAttributes();
                     // type
+                    parseAttributes();
                     if (udas)
                         error("user-defined attributes not allowed for `alias` declarations");
 
-                    auto t = parseType();
+                    auto t = parseBasicType();
+                    t = parseTypeSuffixes(t);
+                    if (token.value == TOK.identifier)
+                    {
+                        error("unexpected identifier `%s` after `%s`",
+                            token.ident.toChars(), t.toChars());
+                        nextToken();
+                    }
+                    else if (token.value == TOK.leftParenthesis)
+                    {
+                        // function type:
+                        // StorageClasses Type ( Parameters ) MemberFunctionAttributes
+                        auto parameterList = parseParameterList(null);
+                        udas = null;
+                        parseStorageClasses(storage_class, link, setAlignment, ealign, udas, linkloc);
+                        if (udas)
+                            error("user-defined attributes not allowed for `alias` declarations");
+
+                        attributesAppended = true;
+                        // Note: method types can have a TypeCtor attribute
+                        storage_class = appendStorageClass(storage_class, funcStc);
+                        t = new AST.TypeFunction(parameterList, t, link, storage_class);
+                    }
 
                     // Disallow meaningless storage classes on type aliases
                     if (storage_class)
                     {
                         // Don't raise errors for STC that are part of a function/delegate type, e.g.
                         // `alias F = ref pure nothrow @nogc @safe int function();`
-                        auto tp = t.isTypePointer;
-                        const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
-                        const remStc = isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
+                        const remStc = t.isTypeFunction ?
+                            storage_class & ~(STC.FUNCATTR | STC.TYPECTOR) : {
+                            auto tp = t.isTypePointer;
+                            const isFuncType = (tp && tp.next.isTypeFunction) || t.isTypeDelegate;
+                            return isFuncType ? (storage_class & ~STC.FUNCATTR) : storage_class;
+                        }();
 
                         if (remStc)
                         {
@@ -7217,6 +7223,7 @@  class Parser(AST, Lexer = dmd.lexer.Lexer) : Lexer
         return false;
     }
 
+    // pt = test token. If found, pt is set to the token after BasicType
     private bool isBasicType(Token** pt)
     {
         // This code parallels parseBasicType()
diff --git a/gcc/d/dmd/parsetimevisitor.d b/gcc/d/dmd/parsetimevisitor.d
index a4a9434334e..3d0a5854625 100644
--- a/gcc/d/dmd/parsetimevisitor.d
+++ b/gcc/d/dmd/parsetimevisitor.d
@@ -298,5 +298,6 @@  public:
     void visit(AST.StructInitializer i) { visit(cast(AST.Initializer)i); }
     void visit(AST.ArrayInitializer i) { visit(cast(AST.Initializer)i); }
     void visit(AST.VoidInitializer i) { visit(cast(AST.Initializer)i); }
+    void visit(AST.DefaultInitializer i) { visit(cast(AST.Initializer)i); }
     void visit(AST.CInitializer i) { visit(cast(AST.CInitializer)i); }
 }
diff --git a/gcc/d/dmd/scope.h b/gcc/d/dmd/scope.h
index 178542e37b0..2cac5f2941b 100644
--- a/gcc/d/dmd/scope.h
+++ b/gcc/d/dmd/scope.h
@@ -61,6 +61,9 @@  enum class SCOPE
     Cfile         = 0x0800,  // C semantics apply
     free          = 0x8000,  // is on free list
     fullinst      = 0x10000, // fully instantiate templates
+    ctfeBlock     = 0x20000, // inside a `if (__ctfe)` block
+    dip1000       = 0x40000, // dip1000 errors enabled for this scope
+    dip25         = 0x80000, // dip25 errors enabled for this scope
 };
 
 struct Scope
@@ -126,4 +129,6 @@  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);
 };
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index bf220f31d9b..c255701d767 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -918,7 +918,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
                         if (f.isref)
                         {
                             // Function returns a reference
-                            exp = exp.toLvalue(sc2);
+                            exp = exp.toLvalue(sc2, "`ref` return");
                             checkReturnEscapeRef(sc2, exp, false);
                             exp = exp.optimize(WANTvalue, /*keepLvalue*/ true);
                         }
diff --git a/gcc/d/dmd/statementsem.d b/gcc/d/dmd/statementsem.d
index f8b2c26df7f..3873adc82ee 100644
--- a/gcc/d/dmd/statementsem.d
+++ b/gcc/d/dmd/statementsem.d
@@ -3801,7 +3801,7 @@  private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
 {
     version (none)
     {
-        if (global.params.useDIP1000 == FeatureState.enabled)
+        if (sc2.useDIP1000 == FeatureState.enabled)
         {
             message(loc, "To enforce `@safe`, the compiler allocates a closure unless `opApply()` uses `scope`");
         }
@@ -3809,7 +3809,7 @@  private extern(D) Expression applyOpApply(ForeachStatement fs, Expression flde,
     }
     else
     {
-        if (global.params.useDIP1000 == FeatureState.enabled)
+        if (sc2.useDIP1000 == FeatureState.enabled)
             ++(cast(FuncExp)flde).fd.tookAddressOf;  // allocate a closure unless the opApply() uses 'scope'
     }
     assert(tab.ty == Tstruct || tab.ty == Tclass);
diff --git a/gcc/d/dmd/staticassert.d b/gcc/d/dmd/staticassert.d
index 15c46b304ba..7f22c4c993a 100644
--- a/gcc/d/dmd/staticassert.d
+++ b/gcc/d/dmd/staticassert.d
@@ -52,11 +52,6 @@  extern (C++) final class StaticAssert : Dsymbol
         return new StaticAssert(loc, exp.syntaxCopy(), msgs ? Expression.arraySyntaxCopy(msgs) : null);
     }
 
-    override void addMember(Scope* sc, ScopeDsymbol sds)
-    {
-        // we didn't add anything
-    }
-
     override bool oneMember(Dsymbol* ps, Identifier ident)
     {
         //printf("StaticAssert::oneMember())\n");
diff --git a/gcc/d/dmd/staticassert.h b/gcc/d/dmd/staticassert.h
index 2b7d300f6af..c0d5363a414 100644
--- a/gcc/d/dmd/staticassert.h
+++ b/gcc/d/dmd/staticassert.h
@@ -21,7 +21,6 @@  public:
     Expressions *msg;
 
     StaticAssert *syntaxCopy(Dsymbol *s) override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     bool oneMember(Dsymbol **ps, Identifier *ident) override;
     const char *kind() const override;
     StaticAssert *isStaticAssert() override { return this; }
diff --git a/gcc/d/dmd/traits.d b/gcc/d/dmd/traits.d
index 79df7fde02b..0acadbb4604 100644
--- a/gcc/d/dmd/traits.d
+++ b/gcc/d/dmd/traits.d
@@ -32,6 +32,7 @@  import dmd.dsymbol;
 import dmd.dsymbolsem;
 import dmd.dtemplate;
 import dmd.errors;
+import dmd.errorsink;
 import dmd.expression;
 import dmd.expressionsem;
 import dmd.func;
@@ -92,43 +93,50 @@  private Dsymbol getDsymbolWithoutExpCtx(RootObject oarg)
 }
 
 /**
- * get an array of size_t values that indicate possible pointer words in memory
- *  if interpreted as the type given as argument
- * Returns: the size of the type in bytes, ulong.max on error
+ * Fill an array of target size_t values that indicate possible pointer words in memory
+ *  if interpreted as the type given as argument.
+ *  One bit in the array per pointer-sized piece of memory
+ * Params:
+ *      loc = location for error messages
+ *      t = type to generate pointer bitmap from
+ *      data = array forming the bitmap
+ *      eSink = error message sink
+ * Returns:
+ *      size of the type `t` in bytes, ulong.max on error
  */
-ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
+ulong getTypePointerBitmap(Loc loc, Type t, ref Array!(ulong) data, ErrorSink eSink)
 {
-    ulong sz;
-    if (t.ty == Tclass && !(cast(TypeClass)t).sym.isInterfaceDeclaration())
-        sz = (cast(TypeClass)t).sym.AggregateDeclaration.size(loc);
-    else
-        sz = t.size(loc);
+    auto tc = t.isTypeClass();
+    const ulong sz = (tc && !tc.sym.isInterfaceDeclaration())
+        ? tc.sym.AggregateDeclaration.size(loc)
+        : t.size(loc);
     if (sz == SIZE_INVALID)
         return ulong.max;
 
-    const sz_size_t = Type.tsize_t.size(loc);
+    const sz_size_t = Type.tsize_t.size(loc); // size of target's size_t
+    assert(sz_size_t <= ulong.sizeof);
     if (sz > sz.max - sz_size_t)
     {
-        error(loc, "size overflow for type `%s`", t.toChars());
+        eSink.error(loc, "size overflow for type `%s`", t.toChars());
         return ulong.max;
     }
 
-    ulong bitsPerWord = sz_size_t * 8;
-    ulong cntptr = (sz + sz_size_t - 1) / sz_size_t;
-    ulong cntdata = (cntptr + bitsPerWord - 1) / bitsPerWord;
+    const ulong bitsPerElement = sz_size_t * 8;  // bits used in each array element
+    const ulong cntptr = (sz + sz_size_t - 1) / sz_size_t; // pointers have same size as sz_size_t
+    const ulong length = (cntptr + bitsPerElement - 1) / bitsPerElement; // a bit per pointer
 
-    data.setDim(cast(size_t)cntdata);
+    data.setDim(cast(size_t)length);
     data.zero();
 
     ulong offset;
-    bool error;
+    bool error;    // sticky error indicator
 
     void visit(Type t)
     {
         void setpointer(ulong off)
         {
             ulong ptroff = off / sz_size_t;
-            (*data)[cast(size_t)(ptroff / (8 * sz_size_t))] |= 1L << (ptroff % (8 * sz_size_t));
+            data[cast(size_t)(ptroff / bitsPerElement)] |= 1L << (ptroff % bitsPerElement);
         }
 
         void visitType(Type t)
@@ -247,7 +255,7 @@  ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
         visit.VisitType(t);
     }
 
-    if (auto tc = t.isTypeClass())
+    if (auto tcx = t.isTypeClass())
     {
         // a "toplevel" class is treated as an instance, while TypeClass fields are treated as references
         void visitTopLevelClass(TypeClass t)
@@ -264,7 +272,7 @@  ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
             offset = classoff;
         }
 
-        visitTopLevelClass(tc);
+        visitTopLevelClass(tcx);
     }
     else
         visit(t);
@@ -281,28 +289,28 @@  ulong getTypePointerBitmap(Loc loc, Type t, Array!(ulong)* data)
  *
  *  Returns: [T.sizeof, pointerbit0-31/63, pointerbit32/64-63/128, ...]
  */
-private Expression pointerBitmap(TraitsExp e)
+private Expression pointerBitmap(TraitsExp e, ErrorSink eSink)
 {
     if (!e.args || e.args.length != 1)
     {
-        error(e.loc, "a single type expected for trait pointerBitmap");
+        eSink.error(e.loc, "a single type expected for trait pointerBitmap");
         return ErrorExp.get();
     }
 
     Type t = getType((*e.args)[0]);
     if (!t)
     {
-        error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
+        eSink.error(e.loc, "`%s` is not a type", (*e.args)[0].toChars());
         return ErrorExp.get();
     }
 
     Array!(ulong) data;
-    ulong sz = getTypePointerBitmap(e.loc, t, &data);
+    const ulong sz = getTypePointerBitmap(e.loc, t, data, eSink);
     if (sz == ulong.max)
         return ErrorExp.get();
 
     auto exps = new Expressions(data.length + 1);
-    (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t);
+    (*exps)[0] = new IntegerExp(e.loc, sz, Type.tsize_t);       // [0] is size in bytes of t
     foreach (size_t i; 1 .. exps.length)
         (*exps)[i] = new IntegerExp(e.loc, data[cast(size_t) (i - 1)], Type.tsize_t);
 
@@ -472,13 +480,13 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
     }
     if (e.ident == Id.isAbstractClass)
     {
-        return isTypeX(t => t.toBasetype().ty == Tclass &&
-                            (cast(TypeClass)t.toBasetype()).sym.isAbstract());
+        return isTypeX(t => t.toBasetype().isTypeClass() &&
+                            t.toBasetype().isTypeClass().sym.isAbstract());
     }
     if (e.ident == Id.isFinalClass)
     {
-        return isTypeX(t => t.toBasetype().ty == Tclass &&
-                            ((cast(TypeClass)t.toBasetype()).sym.storage_class & STC.final_) != 0);
+        return isTypeX(t => t.toBasetype().isTypeClass() &&
+                            (t.toBasetype().isTypeClass().sym.storage_class & STC.final_) != 0);
     }
     if (e.ident == Id.isTemplate)
     {
@@ -508,7 +516,8 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
         }
 
         Type tb = t.baseElemOf();
-        if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+        auto ts = tb.isTypeStruct();
+        if (auto sd = ts ? ts.sym : null)
         {
             return sd.isPOD() ? True() : False();
         }
@@ -529,7 +538,8 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
         }
 
         Type tb = t.baseElemOf();
-        if (auto sd = tb.ty == Tstruct ? (cast(TypeStruct)tb).sym : null)
+        auto ts = tb.isTypeStruct();
+        if (auto sd = ts ? ts.sym : null)
         {
             return (e.ident == Id.hasPostblit) ? (sd.postblit ? True() : False())
                  : (sd.hasCopyCtor ? True() : False());
@@ -793,10 +803,10 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
                 {
                     if (auto p = s.toParent())         // `C`'s parent is `C!2`, believe it or not
                     {
-                        if (p.isTemplateInstance())    // `C!2` is a template instance
+                        if (auto ti = p.isTemplateInstance())    // `C!2` is a template instance
                         {
                             s = p;                     // `C!2`'s parent is `T1`
-                            auto td = (cast(TemplateInstance)p).tempdecl;
+                            auto td = ti.tempdecl;
                             if (td)
                                 s = td;                // get the declaration context just in case there's two contexts
                         }
@@ -1297,7 +1307,7 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
         if (fd && fd.parent && fd.parent.isTemplateInstance)
         {
             fd.functionSemantic3();
-            tf = cast(TypeFunction)fd.type;
+            tf = fd.type.isTypeFunction();
         }
 
         auto mods = new Expressions();
@@ -1738,9 +1748,9 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
                 ex = ex.expressionSemantic(sc2);
                 ex = resolvePropertiesOnly(sc2, ex);
                 ex = ex.optimize(WANTvalue);
-                if (sc2.func && sc2.func.type.ty == Tfunction)
+                if (sc2.func && sc2.func.type.isTypeFunction())
                 {
-                    const tf = cast(TypeFunction)sc2.func.type;
+                    const tf = sc2.func.type.isTypeFunction();
                     err |= tf.isnothrow && canThrow(ex, sc2.func, null);
                 }
                 ex = checkGC(sc2, ex);
@@ -1868,7 +1878,7 @@  Expression semanticTraits(TraitsExp e, Scope* sc)
     }
     if (e.ident == Id.getPointerBitmap)
     {
-        return pointerBitmap(e);
+        return pointerBitmap(e, global.errorSink);
     }
     if (e.ident == Id.initSymbol)
     {
diff --git a/gcc/d/dmd/typesem.d b/gcc/d/dmd/typesem.d
index 4a4c5d4f7f0..8795002cd15 100644
--- a/gcc/d/dmd/typesem.d
+++ b/gcc/d/dmd/typesem.d
@@ -1099,7 +1099,7 @@  extern(C++) Type typeSemantic(Type type, const ref Loc loc, Scope* sc)
             if (isRefOrOut && !isAuto &&
                 !(global.params.previewIn && (fparam.storageClass & STC.in_)) &&
                 global.params.rvalueRefParam != FeatureState.enabled)
-                e = e.toLvalue(sc);
+                e = e.toLvalue(sc, "create default argument for `ref` / `out` parameter from");
 
             fparam.defaultArg = e;
             return (e.op != EXP.error);
diff --git a/gcc/d/dmd/version.h b/gcc/d/dmd/version.h
index 697d46ee211..c268bc9b8cf 100644
--- a/gcc/d/dmd/version.h
+++ b/gcc/d/dmd/version.h
@@ -20,7 +20,6 @@  public:
     DebugSymbol *syntaxCopy(Dsymbol *) override;
 
     const char *toChars() const override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     const char *kind() const override;
     DebugSymbol *isDebugSymbol() override;
     void accept(Visitor *v) override { v->visit(this); }
@@ -34,7 +33,6 @@  public:
     VersionSymbol *syntaxCopy(Dsymbol *) override;
 
     const char *toChars() const override;
-    void addMember(Scope *sc, ScopeDsymbol *sds) override;
     const char *kind() const override;
     VersionSymbol *isVersionSymbol() override;
     void accept(Visitor *v) override { v->visit(this); }
diff --git a/gcc/d/dmd/visitor.h b/gcc/d/dmd/visitor.h
index 3d8c3e60220..360784a1076 100644
--- a/gcc/d/dmd/visitor.h
+++ b/gcc/d/dmd/visitor.h
@@ -176,6 +176,7 @@  class NewDeclaration;
 
 class Initializer;
 class VoidInitializer;
+class DefaultInitializer;
 class ErrorInitializer;
 class StructInitializer;
 class ArrayInitializer;
@@ -591,6 +592,7 @@  public:
     virtual void visit(StructInitializer *i) { visit((Initializer *)i); }
     virtual void visit(ArrayInitializer *i) { visit((Initializer *)i); }
     virtual void visit(VoidInitializer *i) { visit((Initializer *)i); }
+    virtual void visit(DefaultInitializer *i) { visit((Initializer *)i); }
     virtual void visit(CInitializer *i) { visit((Initializer *)i); }
 };
 
diff --git a/gcc/d/expr.cc b/gcc/d/expr.cc
index 17801a3bd1e..a907979ba04 100644
--- a/gcc/d/expr.cc
+++ b/gcc/d/expr.cc
@@ -789,42 +789,58 @@  public:
 
   void visit (CatAssignExp *e) final override
   {
+    if (!global.params.useGC)
+      {
+	error_at (make_location_t (e->loc),
+		  "appending to array in %qs requires the GC and cannot be "
+		  "used with %<-fno-druntime%>", e->toChars ());
+	this->result_ = error_mark_node;
+	return;
+      }
+
     Type *tb1 = e->e1->type->toBasetype ();
     Type *tb2 = e->e2->type->toBasetype ();
-    Type *etype = tb1->nextOf ()->toBasetype ();
-
-    /* Save the address of `e1', so it can be evaluated first.
-       As all D run-time library functions for concat assignments update `e1'
-       in-place and then return its value, the saved address can also be used as
-       the result of this expression as well.  */
-    tree lhs = build_expr (e->e1);
-    tree lexpr = stabilize_expr (&lhs);
-    tree ptr = d_save_expr (build_address (lhs));
-    tree result = NULL_TREE;
 
-    if (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar
-	&& (etype->ty == TY::Tchar || etype->ty == TY::Twchar))
+    if (e->op == EXP::concatenateDcharAssign)
       {
 	/* Append a dchar to a char[] or wchar[]:
 	   The assignment is handled by the D run-time library, so only
 	   need to call `_d_arrayappend[cw]d(&e1, e2)'  */
+	Type *etype = tb1->nextOf ()->toBasetype ();
+
+	/* Save the address of `e1', so it can be evaluated first.
+	   As all D run-time library functions for concat assignments update
+	   `e1' in-place and then return its value, the saved address can also
+	   be used as the result of this expression as well.  */
+	tree lhs = build_expr (e->e1);
+	tree lexpr = stabilize_expr (&lhs);
+	tree ptr = d_save_expr (build_address (lhs));
+	tree result = NULL_TREE;
+
+	gcc_assert (tb1->ty == TY::Tarray && tb2->ty == TY::Tdchar
+		    && (etype->ty == TY::Tchar || etype->ty == TY::Twchar));
+
 	libcall_fn libcall = (etype->ty == TY::Tchar)
 	  ? LIBCALL_ARRAYAPPENDCD : LIBCALL_ARRAYAPPENDWD;
 
 	result = build_libcall (libcall, e->type, 2,
 				ptr, build_expr (e->e2));
+
+	/* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr;  */
+	result = compound_expr (compound_expr (lexpr, ptr), result);
+	this->result_ = compound_expr (result, build_deref (ptr));
       }
     else
       {
+	gcc_assert (e->op == EXP::concatenateAssign
+		    || e->op == EXP::concatenateElemAssign);
+	gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray);
 	/* Appending an element or array to another array has already been
 	   handled by the front-end.  */
-	gcc_assert (tb1->ty == TY::Tarray || tb2->ty == TY::Tsarray);
-	gcc_unreachable ();
-      }
+	gcc_assert (e->lowering);
 
-    /* Construct in order: ptr = &e1, _d_arrayappend(ptr, e2), *ptr;  */
-    result = compound_expr (compound_expr (lexpr, ptr), result);
-    this->result_ = compound_expr (result, build_deref (ptr));
+	this->result_ = build_expr (e->lowering);
+      }
   }
 
   /* Build an assignment expression.  The right operand is implicitly
@@ -2359,50 +2375,9 @@  public:
 	/* Allocating memory for a new D array.  */
 	gcc_assert (e->arguments && e->arguments->length >= 1);
 
-	if (e->arguments->length == 1)
-	  {
-	    /* Single dimension array allocations has already been handled by
-	       the front-end.  */
-	    gcc_assert (e->lowering);
-	    result = build_expr (e->lowering);
-	  }
-	else
-	  {
-	    /* Multidimensional array allocations.  */
-	    tree tarray = make_array_type (Type::tsize_t, e->arguments->length);
-	    tree var = build_local_temp (tarray);
-	    vec <constructor_elt, va_gc> *elms = NULL;
-
-	    /* Get the base element type for the array, generating the
-	       initializer for the dims parameter along the way.  */
-	    Type *telem = e->newtype->toBasetype ();
-	    for (size_t i = 0; i < e->arguments->length; i++)
-	      {
-		Expression *arg = (*e->arguments)[i];
-		CONSTRUCTOR_APPEND_ELT (elms, size_int (i), build_expr (arg));
-
-		gcc_assert (telem->ty == TY::Tarray);
-		telem = telem->toBasetype ()->nextOf ();
-		gcc_assert (telem);
-	      }
-
-	    /* Initialize the temporary.  */
-	    tree init = modify_expr (var, build_constructor (tarray, elms));
-	    var = compound_expr (init, var);
-
-	    /* Generate: _d_newarraymTX(ti, dims)
-		     or: _d_newarraymiTX(ti, dims)  */
-	    libcall_fn libcall = telem->isZeroInit ()
-	      ? LIBCALL_NEWARRAYMTX : LIBCALL_NEWARRAYMITX;
-
-	    tree tinfo = build_typeinfo (e, e->type);
-	    tree dims = d_array_value (build_ctype (Type::tsize_t->arrayOf ()),
-				       size_int (e->arguments->length),
-				       build_address (var));
-
-	    result = build_libcall (libcall, e->newtype->toBasetype (), 2,
-				    tinfo, dims);
-	  }
+	/* Array allocations have already been handled by the front-end.  */
+	gcc_assert (e->lowering != NULL);
+	result = build_expr (e->lowering);
 
 	if (e->argprefix)
 	  result = compound_expr (build_expr (e->argprefix), result);
diff --git a/gcc/d/runtime.def b/gcc/d/runtime.def
index f7887e1548f..3307b3b8244 100644
--- a/gcc/d/runtime.def
+++ b/gcc/d/runtime.def
@@ -70,13 +70,6 @@  DEF_D_RUNTIME (DYNAMIC_CAST, "_d_dynamic_cast", RT(OBJECT),
 DEF_D_RUNTIME (INTERFACE_CAST, "_d_interface_cast", RT(OBJECT),
 	       P2(OBJECT, CLASSINFO), 0)
 
-/* Used when calling `new' on a multi-dimensional array.
-   The `i' variant is for when the initializer is nonzero.  */
-DEF_D_RUNTIME (NEWARRAYMTX, "_d_newarraymTX", RT(ARRAY_VOID),
-	       P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
-DEF_D_RUNTIME (NEWARRAYMITX, "_d_newarraymiTX", RT(ARRAY_VOID),
-	       P2(CONST_TYPEINFO, ARRAY_SIZE_T), 0)
-
 /* Used for allocating an array literal on the GC heap.  */
 DEF_D_RUNTIME (ARRAYLITERALTX, "_d_arrayliteralTX", RT(VOIDPTR),
 	       P2(CONST_TYPEINFO, SIZE_T), 0)
diff --git a/gcc/testsuite/gdc.dg/asm1.d b/gcc/testsuite/gdc.dg/asm1.d
index 1b249ee7b35..1593eb6acd3 100644
--- a/gcc/testsuite/gdc.dg/asm1.d
+++ b/gcc/testsuite/gdc.dg/asm1.d
@@ -58,7 +58,7 @@  void semantic1()
 void semantic2a(X...)(X expr)
 {
     alias X[0] var1;
-    asm { "%0" : "=m" (var1); } // { dg-error "double' is a 'double' definition and cannot be modified" }
+    asm { "%0" : "=m" (var1); } // { dg-error "cannot modify type 'double'" }
 }
 
 void semantic2()
diff --git a/gcc/testsuite/gdc.test/compilable/issue16020.d b/gcc/testsuite/gdc.test/compilable/issue16020.d
index cfd078cdcd1..38a5d624320 100644
--- a/gcc/testsuite/gdc.test/compilable/issue16020.d
+++ b/gcc/testsuite/gdc.test/compilable/issue16020.d
@@ -1,3 +1,4 @@ 
+// function type aliases
 module issue16020;
 
 alias F1 = const(int)(); const(int) f1(){return 42;}
@@ -36,4 +37,8 @@  alias Specialized = FunTemplate!int;
 alias Compared = void(int);
 static assert(is(Specialized == Compared));
 
-void main() {}
+// type suffixes
+alias FT = const(int)*();
+static assert(is(FT* == const(int)* function()));
+alias FT2 = int*[2]() pure;
+static assert(is(FT2* == int*[2] function() pure));
diff --git a/gcc/testsuite/gdc.test/compilable/nogc.d b/gcc/testsuite/gdc.test/compilable/nogc.d
index 88cf1229d4d..959adc499cc 100644
--- a/gcc/testsuite/gdc.test/compilable/nogc.d
+++ b/gcc/testsuite/gdc.test/compilable/nogc.d
@@ -119,3 +119,12 @@  void f(bool cond, string s) @nogc {
     alias Unused2 = typeof(&inner); // (Does not) INFERS GC (anymore)
     enum Unused3 = __traits(compiles , &inner);
 }
+
+// https://issues.dlang.org/show_bug.cgi?id=24072
+
+version (D_SIMD) void f24072() @nogc
+{
+    alias int4 = __vector(int[4]);
+    int4 b = cast(int4)[1, 2, 3, 4];
+    int4 c = cast(int4)[1, 2];
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/b20011.d b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
index 7baad47f378..3ddcdaaf76b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/b20011.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/b20011.d
@@ -1,10 +1,10 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/b20011.d(25): Error: `S1(cast(ubyte)0u).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(28): Error: `S2(null).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(29): Error: `S2(null).member` is not an lvalue and cannot be modified
-fail_compilation/b20011.d(32): Error: `U1(cast(ubyte)0u, ).m2` is not an lvalue and cannot be modified
+fail_compilation/b20011.d(25): Error: cannot modify expression `S1(cast(ubyte)0u).member` because it is not an lvalue
+fail_compilation/b20011.d(28): Error: cannot modify expression `S2(null).member` because it is not an lvalue
+fail_compilation/b20011.d(29): Error: cannot modify expression `S2(null).member` because it is not an lvalue
+fail_compilation/b20011.d(32): Error: cannot modify expression `U1(cast(ubyte)0u, ).m2` because it is not an lvalue
 fail_compilation/b20011.d(37): Error: function `b20011.main.assignableByRef(ref ubyte p)` is not callable using argument types `(ubyte)`
 fail_compilation/b20011.d(37):        cannot pass rvalue argument `S1(cast(ubyte)0u).member` of type `ubyte` to parameter `ref ubyte p`
 fail_compilation/b20011.d(38): Error: function `b20011.main.assignableByOut(out ubyte p)` is not callable using argument types `(ubyte)`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d b/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d
new file mode 100644
index 00000000000..ae37023f0a1
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/const_ctor.d
@@ -0,0 +1,26 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/const_ctor.d(23): Error: `const` copy constructor `const_ctor.S1.this` cannot construct a mutable object
+fail_compilation/const_ctor.d(25): Error: `const` constructor `const_ctor.S2.this` cannot construct a mutable object
+---
+*/
+
+struct S1
+{
+    this(ref const S1 s) const {}
+    int* i;
+}
+struct S2
+{
+    this(int) const {}
+    int* i;
+}
+
+void main()
+{
+    const(S1) s1;
+    S1 m1 = s1;
+
+    S2 s2 = S2(5);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d b/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d
new file mode 100644
index 00000000000..337ded09fd2
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/ctor_attr.d
@@ -0,0 +1,29 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/ctor_attr.d(26): Error: none of the overloads of `this` can construct a mutable object with argument types `(int)`
+fail_compilation/ctor_attr.d(16):        Candidates are: `ctor_attr.S.this(int x) const`
+fail_compilation/ctor_attr.d(18):                        `ctor_attr.S.this(string x)`
+fail_compilation/ctor_attr.d(17):                        `this()(int x) shared`
+fail_compilation/ctor_attr.d(28): Error: none of the overloads of `foo` are callable using a mutable object with argument types `(int)`
+fail_compilation/ctor_attr.d(20):        Candidates are: `ctor_attr.S.foo(int x) immutable`
+fail_compilation/ctor_attr.d(21):                        `ctor_attr.S.foo(string x)`
+---
+*/
+
+struct S
+{
+    this(int x) const {}
+    this()(int x) shared {}
+    this(string x) {}
+
+    void foo(int x) immutable  {}
+    void foo(string x) {}
+}
+
+void f()
+{
+   auto s = S(1);
+   S t;
+   t.foo(1);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
index 207f6a4aa15..74444327ecb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10415.d
@@ -2,7 +2,7 @@ 
 TEST_OUTPUT:
 ---
 fail_compilation/diag10415.d(36): Error: none of the overloads of `x` are callable using argument types `(int) const`
-fail_compilation/diag10415.d(13):        Candidates are: `diag10415.C.x()`
+fail_compilation/diag10415.d(13):        Candidates are: `diag10415.C.x() const`
 fail_compilation/diag10415.d(18):                        `diag10415.C.x(int __param_0)`
 fail_compilation/diag10415.d(39): Error: d.x is not an lvalue
 ---
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
index 3e154979e8c..2c9384159ff 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10862.d
@@ -26,10 +26,10 @@  fail_compilation/diag10862.d-mixin-78(78): Error: assignment cannot be used as a
 fail_compilation/diag10862.d-mixin-79(79): Error: assignment cannot be used as a condition, perhaps `==` was meant?
 fail_compilation/diag10862.d-mixin-80(80): Error: using the result of a comma expression is not allowed
 fail_compilation/diag10862.d-mixin-80(80): Error: assignment cannot be used as a condition, perhaps `==` was meant?
-fail_compilation/diag10862.d-mixin-83(83): Error: `a + b` is not an lvalue and cannot be modified
+fail_compilation/diag10862.d-mixin-83(83): Error: cannot modify expression `a + b` because it is not an lvalue
 fail_compilation/diag10862.d-mixin-84(84): Error: undefined identifier `c`
 fail_compilation/diag10862.d(86): Error: undefined identifier `semanticError`
-fail_compilation/diag10862.d(93): Error: lazy variable `bar` cannot be modified
+fail_compilation/diag10862.d(93): Error: cannot modify lazy variable `bar`
 fail_compilation/diag10862.d(95): Error: template instance `diag10862.test3.foo!int` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
index f98a5b27dea..9bad6336d18 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag10926.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag10926.d(11): Error: `cast(const(int)[])c` is not an lvalue and cannot be modified
+fail_compilation/diag10926.d(11): Error: cannot modify expression `cast(const(int)[])c` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
index e93d40b224e..b88dd7803cf 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag14102.d
@@ -1,10 +1,10 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag14102.d(14): Error: `-x` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(15): Error: `-(x -= 1)` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(16): Error: `-(x -= 1 -= 1)` is not an lvalue and cannot be modified
-fail_compilation/diag14102.d(17): Error: `-(x -= 1 -= 1 -= 1)` is not an lvalue and cannot be modified
+fail_compilation/diag14102.d(14): Error: cannot modify expression `-x` because it is not an lvalue
+fail_compilation/diag14102.d(15): Error: cannot modify expression `-(x -= 1)` because it is not an lvalue
+fail_compilation/diag14102.d(16): Error: cannot modify expression `-(x -= 1 -= 1)` because it is not an lvalue
+fail_compilation/diag14102.d(17): Error: cannot modify expression `-(x -= 1 -= 1 -= 1)` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
index f6b49d6bd13..d43342bdc58 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag4596.d
@@ -1,9 +1,9 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/diag4596.d(15): Error: `this` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(15): Error: cannot modify expression `this` because it is not an lvalue
 fail_compilation/diag4596.d(16): Error: conditional expression `1 ? this : this` is not a modifiable lvalue
-fail_compilation/diag4596.d(18): Error: `super` is not an lvalue and cannot be modified
+fail_compilation/diag4596.d(18): Error: cannot modify expression `super` because it is not an lvalue
 fail_compilation/diag4596.d(19): Error: conditional expression `1 ? super : super` is not a modifiable lvalue
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
index a55ef731ad2..626fb827878 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/diag8101b.d
@@ -6,7 +6,7 @@  fail_compilation/diag8101b.d(19):        Candidates are: `diag8101b.S.foo(int __
 fail_compilation/diag8101b.d(20):                        `diag8101b.S.foo(int __param_0, int __param_1)`
 fail_compilation/diag8101b.d(30): Error: function `diag8101b.S.bar(int __param_0)` is not callable using argument types `(double)`
 fail_compilation/diag8101b.d(30):        cannot pass argument `1.0` of type `double` to parameter `int __param_0`
-fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object
+fail_compilation/diag8101b.d(33): Error: none of the overloads of `foo` are callable using a `const` object with argument types `(int)`
 fail_compilation/diag8101b.d(19):        Candidates are: `diag8101b.S.foo(int __param_0)`
 fail_compilation/diag8101b.d(20):                        `diag8101b.S.foo(int __param_0, int __param_1)`
 fail_compilation/diag8101b.d(35): Error: mutable method `diag8101b.S.bar` is not callable using a `const` object
diff --git a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d b/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
deleted file mode 100644
index 77ab52046fc..00000000000
--- a/gcc/testsuite/gdc.test/fail_compilation/dip1000_deprecation.d
+++ /dev/null
@@ -1,56 +0,0 @@ 
-/*
-REQUIRED_ARGS: -de
-TEST_OUTPUT:
----
-fail_compilation/dip1000_deprecation.d(17): Deprecation: `@safe` function `main` calling `inferred`
-fail_compilation/dip1000_deprecation.d(25):        which wouldn't be `@safe` because of:
-fail_compilation/dip1000_deprecation.d(25):        scope variable `x0` may not be returned
-fail_compilation/dip1000_deprecation.d(19): Deprecation: `@safe` function `main` calling `inferredC`
-fail_compilation/dip1000_deprecation.d(36):        which calls `dip1000_deprecation.inferred`
-fail_compilation/dip1000_deprecation.d(25):        which wouldn't be `@safe` because of:
-fail_compilation/dip1000_deprecation.d(25):        scope variable `x0` may not be returned
----
-*/
-
-void main() @safe
-{
-    cast(void)inferred();
-    cast(void)inferredB(); // no deprecation, trusted
-    cast(void)inferredC(); // nested deprecation
-}
-
-auto inferred()
-{
-    scope int* x0;
-    return x0;
-}
-
-auto inferredB() @trusted
-{
-    scope int* x1;
-    return x1;
-}
-
-auto inferredC()
-{
-    return inferred(); // no deprecation, inferredC is not explicit `@safe`
-}
-
-@safe:
-
-struct S
-{
-    int* ptr;
-    int* incorrectReturnRef() scope return @trusted {return ptr;}
-}
-
-S createS() { return S.init; }
-
-int* escape(int i)
-{
-    if (i) return S().incorrectReturnRef();
-    if (i) return createS().incorrectReturnRef();
-
-    S s;
-    return s.incorrectReturnRef();
-}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
index f0eaeba821a..d9cfb047724 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail10299.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail10299.d(11): Error: `foo!string` is not an lvalue and cannot be modified
+fail_compilation/fail10299.d(11): Error: cannot take address of expression `foo!string` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
index ac520d79997..156da435c7b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13116.d
@@ -1,8 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13116.d(14): Error: `this` is not an lvalue and cannot be modified
-fail_compilation/fail13116.d(23): Error: `super` is not an lvalue and cannot be modified
+fail_compilation/fail13116.d(14): Error: cannot `ref` return expression `this` because it is not an lvalue
+fail_compilation/fail13116.d(23): Error: cannot `ref` return expression `super` because it is not an lvalue
 ---
 */
 struct S
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
index e3f990c2fdf..6307e902551 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336a.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13336a.d(28): Error: `choose(true)` is not an lvalue and cannot be modified
+fail_compilation/fail13336a.d(28): Error: cannot modify expression `choose(true)` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
index b8fb12d1427..f8959a2183c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail13336b.d
@@ -6,8 +6,8 @@  double sy;
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail13336b.d(16): Error: `cast(double)sx` is not an lvalue and cannot be modified
-fail_compilation/fail13336b.d(24): Error: `cast(double)sx` is not an lvalue and cannot be modified
+fail_compilation/fail13336b.d(16): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue
+fail_compilation/fail13336b.d(24): Error: cannot `ref` return expression `cast(double)sx` because it is not an lvalue
 ---
 */
 ref f1(bool f)
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
index 0fb9708b430..718948c2832 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail17491.d
@@ -1,13 +1,13 @@ 
 /* TEST_OUTPUT:
 ---
-fail_compilation/fail17491.d(22): Error: `(S17491).init` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(23): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(25): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(26): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(31): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(32): Error: `S17491(0)` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(34): Error: `S17491(0).field` is not an lvalue and cannot be modified
-fail_compilation/fail17491.d(35): Error: `S17491(0).field` is not an lvalue and cannot be modified
+fail_compilation/fail17491.d(22): Error: cannot modify expression `(S17491).init` because it is not an lvalue
+fail_compilation/fail17491.d(23): Error: cannot take address of expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(25): Error: cannot modify expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(26): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(31): Error: cannot modify expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(32): Error: cannot take address of expression `S17491(0)` because it is not an lvalue
+fail_compilation/fail17491.d(34): Error: cannot modify expression `S17491(0).field` because it is not an lvalue
+fail_compilation/fail17491.d(35): Error: cannot take address of expression `S17491(0).field` because it is not an lvalue
 ---
 */
 // https://issues.dlang.org/show_bug.cgi?id=17491
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d
index 2e170d096c5..0b4117d5bc6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail21243.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail21243.d
@@ -1,16 +1,12 @@ 
 /+ TEST_OUTPUT:
 ---
-fail_compilation/fail21243.d(16): Error: found `(` when expecting `ref` and function literal following `auto`
-fail_compilation/fail21243.d(16): Error: semicolon expected following auto declaration, not `int`
-fail_compilation/fail21243.d(16): Error: semicolon needed to end declaration of `x` instead of `)`
-fail_compilation/fail21243.d(16): Error: declaration expected, not `)`
-fail_compilation/fail21243.d(17): Error: `auto` can only be used as part of `auto ref` for function literal return values
-fail_compilation/fail21243.d(18): Error: basic type expected, not `(`
-fail_compilation/fail21243.d(18): Error: function declaration without return type. (Note that constructors are always named `this`)
-fail_compilation/fail21243.d(18): Deprecation: storage class `auto` has no effect in type aliases
-fail_compilation/fail21243.d(18): Error: semicolon expected to close `alias` declaration, not `=>`
-fail_compilation/fail21243.d(18): Error: declaration expected, not `=>`
-fail_compilation/fail21243.d(19): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(12): Error: found `(` when expecting `ref` and function literal following `auto`
+fail_compilation/fail21243.d(12): Error: semicolon expected following auto declaration, not `int`
+fail_compilation/fail21243.d(12): Error: semicolon needed to end declaration of `x` instead of `)`
+fail_compilation/fail21243.d(12): Error: declaration expected, not `)`
+fail_compilation/fail21243.d(13): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(14): Error: `auto` can only be used as part of `auto ref` for function literal return values
+fail_compilation/fail21243.d(15): Error: `auto` can only be used as part of `auto ref` for function literal return values
 ---
 +/
 auto a = auto (int x) => x;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail217.d b/gcc/testsuite/gdc.test/fail_compilation/fail217.d
index 11ad76fabdc..ecae1a38e6d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail217.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail217.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail217.d(22): Error: mutable method `fail217.Message.this` is not callable using a `immutable` object
+fail_compilation/fail217.d(22): Error: mutable constructor `fail217.Message.this` cannot construct a `immutable` object
 fail_compilation/fail217.d(13):        Consider adding `const` or `inout` here
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail24224.d b/gcc/testsuite/gdc.test/fail_compilation/fail24224.d
new file mode 100644
index 00000000000..db87f5305d7
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail24224.d
@@ -0,0 +1,22 @@ 
+/+
+TEST_OUTPUT:
+---
+fail_compilation/fail24224.d(19): Error: struct / class type expected as argument to __traits(initSymbol) instead of `ES`
+fail_compilation/fail24224.d(20): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EU`
+fail_compilation/fail24224.d(21): Error: struct / class type expected as argument to __traits(initSymbol) instead of `EC`
+---
++/
+struct S {}
+union U {}
+class C {}
+
+enum ES : S { a = S.init }
+enum EU : U { a = U.init }
+enum EC : C { a = C.init }
+
+void test()
+{
+    auto init1 = __traits(initSymbol, ES);
+    auto init2 = __traits(initSymbol, EU);
+    auto init3 = __traits(initSymbol, EC);
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
index 584a4679ccd..26d44296498 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail6795.d
@@ -2,12 +2,12 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail6795.d(19): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(20): Error: `[0:0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(22): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(23): Error: `[0:0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(25): Error: `[0][0]` is not an lvalue and cannot be modified
-fail_compilation/fail6795.d(26): Error: `[0:0][0]` is not an lvalue and cannot be modified
+fail_compilation/fail6795.d(19): Error: cannot modify expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(20): Error: cannot modify expression `[0:0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(22): Error: cannot modify expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(23): Error: cannot modify expression `[0:0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(25): Error: cannot take address of expression `[0][0]` because it is not an lvalue
+fail_compilation/fail6795.d(26): Error: cannot take address of expression `[0:0][0]` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
index 38f47ba0913..920956bf2f9 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424d.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424d.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424d.d(10): Error: template `this.g()() immutable` has no value
 ---
 */
 struct S7424d
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
index e92b4693d51..ddf9d1a89b3 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424e.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424e.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424e.d(10): Error: template `this.g()() immutable` has no value
 ---
 */
 struct S7424e
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
index 1af14f83d7e..2f7f8f36153 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424f.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424f.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424f.d(10): Error: template `this.g()() shared` has no value
 ---
 */
 struct S7424f
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
index 6352166add5..4e922d6f5be 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7424i.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7424i.d(10): Error: template `this.g()()` has no value
+fail_compilation/fail7424i.d(10): Error: template `this.g()() immutable` has no value
 ---
 */
 struct S7424g
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d
index 76a92c2b193..a106a566a5c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603a.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7603a.d(7): Error: cannot modify constant `true`
+fail_compilation/fail7603a.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true`
 ---
 */
 void test(ref bool val = true) { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d
index 9b84d3f6a4d..a6524221afd 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603b.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7603b.d(7): Error: cannot modify constant `true`
+fail_compilation/fail7603b.d(7): Error: cannot create default argument for `ref` / `out` parameter from constant `true`
 ---
 */
 void test(out bool val = true) { }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d
index 25a7399dd7a..3d030fc9668 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail7603c.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail7603c.d(8): Error: cannot modify constant `3`
+fail_compilation/fail7603c.d(8): Error: cannot create default argument for `ref` / `out` parameter from constant `3`
 ---
 */
 enum x = 3;
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
index e08badf34a9..4d593e39ddb 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9537.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail9537.d(26): Error: `foo(tuple(1, 2))` is not an lvalue and cannot be modified
+fail_compilation/fail9537.d(26): Error: cannot take address of expression `foo(tuple(1, 2))` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
index b49ffe13dfc..26447a73914 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9773.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail9773.d(7): Error: `""` is not an lvalue and cannot be modified
+fail_compilation/fail9773.d(7): Error: cannot create default argument for `ref` / `out` parameter from expression `""` because it is not an lvalue
 ---
 */
 void f(ref string a = "")
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
index 791e734349f..0c2384fccfa 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail9891.d
@@ -3,7 +3,7 @@  TEST_OUTPUT:
 ---
 fail_compilation/fail9891.d(13): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `ref int` of parameter `n`
 fail_compilation/fail9891.d(18): Error: expression `i` of type `immutable(int)` is not implicitly convertible to type `out int` of parameter `n`
-fail_compilation/fail9891.d(23): Error: `prop()` is not an lvalue and cannot be modified
+fail_compilation/fail9891.d(23): Error: cannot create default argument for `ref` / `out` parameter from expression `prop()` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
index c3c735ed552..0db6a45c9a2 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_arrayop2.d
@@ -207,21 +207,21 @@  fail_compilation/fail_arrayop2.d(265): Error: array operation `[1] * 6` without
 fail_compilation/fail_arrayop2.d(268): Error: array operation `[1] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(269): Error: array operation `"abc"[] + '\x01'` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(272): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(275): Error: `([1] * 6)[0..2]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(275): Error: cannot take address of expression `([1] * 6)[0..2]` because it is not an lvalue
 fail_compilation/fail_arrayop2.d(278): Error: can only `*` a pointer, not a `int[]`
 fail_compilation/fail_arrayop2.d(281): Error: the `delete` keyword is obsolete
 fail_compilation/fail_arrayop2.d(281):        use `object.destroy()` (and `core.memory.GC.free()` if applicable) instead
 fail_compilation/fail_arrayop2.d(284): Error: array operation `da[] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(287): Error: array operation `da[] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(290): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(290): Error: cannot modify expression `[1] * 6` because it is not an lvalue
 fail_compilation/fail_arrayop2.d(291): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(294): Error: `[1] * 6` is not an lvalue and cannot be modified
-fail_compilation/fail_arrayop2.d(295): Error: `([1] * 6)[]` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(294): Error: cannot modify expression `[1] * 6` because it is not an lvalue
+fail_compilation/fail_arrayop2.d(295): Error: cannot modify expression `([1] * 6)[]` because it is not an lvalue
 fail_compilation/fail_arrayop2.d(298): Error: array operation `[1] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(299): Error: array operation `[1] * 6` without destination memory not allowed
 fail_compilation/fail_arrayop2.d(300): Error: array operation `[1] * 6` without destination memory not allowed
-fail_compilation/fail_arrayop2.d(303): Error: `[1] * 6` is not an lvalue and cannot be modified
-fail_compilation/fail_arrayop2.d(304): Error: `[1] * 6` is not an lvalue and cannot be modified
+fail_compilation/fail_arrayop2.d(303): Error: cannot modify expression `[1] * 6` because it is not an lvalue
+fail_compilation/fail_arrayop2.d(304): Error: cannot modify expression `[1] * 6` because it is not an lvalue
 fail_compilation/fail_arrayop2.d(307): Error: `[1] * 6` is not of integral type, it is a `int[]`
 fail_compilation/fail_arrayop2.d(308): Error: `[1] * 6` is not of integral type, it is a `int[]`
 fail_compilation/fail_arrayop2.d(309): Error: `[1] * 6` is not of integral type, it is a `int[]`
diff --git a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
index a9e5429366a..9851ffc1c74 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/fail_scope.d
@@ -1,10 +1,6 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/fail_scope.d(28): Deprecation: scope parameter `da` may not be returned
-fail_compilation/fail_scope.d(30): Deprecation: scope parameter `o` may not be returned
-fail_compilation/fail_scope.d(31): Deprecation: scope parameter `dg` may not be returned
-fail_compilation/fail_scope.d(38): Deprecation: scope parameter `p` may not be returned
 fail_compilation/fail_scope.d(43): Error: returning `cast(char[])string` escapes a reference to local variable `string`
 fail_compilation/fail_scope.d(61): Error: returning `s.bar()` escapes a reference to local variable `s`
 fail_compilation/fail_scope.d(72): Error: `fail_scope.foo8` called with argument types `(int)` matches both:
@@ -23,6 +19,10 @@  fail_compilation/fail_scope.d(135): Error: returning `foo16226(i)` escapes a ref
 //fail_compilation/fail_scope.d(40): Error: scope variable `p` may not be returned
 */
 
+
+
+
+
 alias int delegate() dg_t;
 
 int[]  checkEscapeScope1(scope int[]  da) { return da; }
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
index 827f0451824..fed8c608569 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice10419.d
@@ -1,7 +1,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice10419.d(12): Error: `arr().length` is not an lvalue and cannot be modified
+fail_compilation/ice10419.d(12): Error: cannot modify expression `arr().length` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
index c5894d2c7ee..343624dbc39 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice12841.d
@@ -1,8 +1,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/ice12841.d(23): Error: `taskPool().amap(Args...)(Args args)` is not an lvalue and cannot be modified
-fail_compilation/ice12841.d(24): Error: `amap(Args...)(Args args)` is not an lvalue and cannot be modified
+fail_compilation/ice12841.d(23): Error: cannot take address of expression `taskPool().amap(Args...)(Args args)` because it is not an lvalue
+fail_compilation/ice12841.d(24): Error: cannot take address of template `amap(Args...)(Args args)`, perhaps instantiate it first
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
index d34fc60db6a..6998e685a75 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice13459.d
@@ -3,7 +3,7 @@  TEST_OUTPUT:
 ---
 fail_compilation/ice13459.d(12): Error: undefined identifier `B`
 fail_compilation/ice13459.d(18): Error: none of the overloads of `opSlice` are callable using argument types `(int, int)`
-fail_compilation/ice13459.d(11):        Candidate is: `ice13459.A.opSlice()`
+fail_compilation/ice13459.d(11):        Candidate is: `ice13459.A.opSlice() const`
 ---
 */
 struct A
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
index 0d697e22c9f..df6667d9e4b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice20264.d
@@ -2,7 +2,7 @@ 
 DISABLED: freebsd32 linux32 osx32 win32
 TEST_OUTPUT:
 ---
-fail_compilation/ice20264.d(12): Error: `cast(__vector(float[4]))a` is not an lvalue and cannot be modified
+fail_compilation/ice20264.d(12): Error: cannot modify expression `cast(__vector(float[4]))a` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
index 47fd44c6b01..c9ab014b6e6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/ice9284.d
@@ -2,7 +2,7 @@ 
 TEST_OUTPUT:
 ---
 fail_compilation/ice9284.d(14): Error: template `ice9284.C.__ctor` is not callable using argument types `!()(int)`
-fail_compilation/ice9284.d(12):        Candidate is: `__ctor()(string)`
+fail_compilation/ice9284.d(12):        Candidate is: `this()(string)`
 fail_compilation/ice9284.d(20): Error: template instance `ice9284.C.__ctor!()` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d b/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d
new file mode 100644
index 00000000000..408e4027fd6
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/immutable_ctor.d
@@ -0,0 +1,19 @@ 
+/*
+TEST_OUTPUT:
+---
+fail_compilation/immutable_ctor.d(18): Error: `immutable` copy constructor `immutable_ctor.S1.this` cannot construct a mutable object
+---
+*/
+
+struct S1
+{
+    this(ref const S1 s) immutable {
+    }
+    int i;
+}
+
+void main()
+{
+    const(S1) s1;
+    S1 ms1 = s1;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue16020.d b/gcc/testsuite/gdc.test/fail_compilation/issue16020.d
index fe4ad78f1ac..79eda2ea08c 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/issue16020.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue16020.d
@@ -1,9 +1,10 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/issue16020.d(12): Error: user-defined attributes not allowed for `alias` declarations
-fail_compilation/issue16020.d(13): Error: semicolon expected to close `alias` declaration, not `(`
-fail_compilation/issue16020.d(13): Error: declaration expected, not `(`
+fail_compilation/issue16020.d(13): Error: user-defined attributes not allowed for `alias` declarations
+fail_compilation/issue16020.d(14): Error: semicolon expected to close `alias` declaration, not `(`
+fail_compilation/issue16020.d(14): Error: declaration expected, not `(`
+fail_compilation/issue16020.d(15): Deprecation: storage class `final` has no effect in type aliases
 ---
 */
 module issue16020;
@@ -11,3 +12,4 @@  module issue16020;
 struct UDA{}
 alias Fun = @UDA void();
 alias FunTemplate = void(T)(T t);
+alias F2 = final int();
diff --git a/gcc/testsuite/gdc.test/fail_compilation/issue20704.d b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d
index 1e1f2e6f34b..ba91b063572 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/issue20704.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/issue20704.d
@@ -1,12 +1,12 @@ 
 /* TEST_OUTPUT:
 ---
-fail_compilation/issue20704.d(17): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from constant `0`
 fail_compilation/issue20704.d(28): Error: template instance `issue20704.f2!int` error instantiating
-fail_compilation/issue20704.d(19): Error: cannot modify constant `0`
+fail_compilation/issue20704.d(19): Error: cannot create default argument for `ref` / `out` parameter from constant `0`
 fail_compilation/issue20704.d(30): Error: template instance `issue20704.f4!int` error instantiating
-fail_compilation/issue20704.d(17): Error: `S(0)` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `S(0)` because it is not an lvalue
 fail_compilation/issue20704.d(36): Error: template instance `issue20704.f2!(S)` error instantiating
-fail_compilation/issue20704.d(17): Error: `null` is not an lvalue and cannot be modified
+fail_compilation/issue20704.d(17): Error: cannot create default argument for `ref` / `out` parameter from expression `null` because it is not an lvalue
 fail_compilation/issue20704.d(38): Error: template instance `issue20704.f2!(C)` error instantiating
 ---
 */
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test16381.d b/gcc/testsuite/gdc.test/fail_compilation/test16381.d
index fd92798366c..5847e0459b6 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test16381.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test16381.d
@@ -2,7 +2,7 @@ 
 REQUIRED_ARGS: -m64
 TEST_OUTPUT:
 ---
-fail_compilation/test16381.d(15): Error: `foo()` is not an lvalue and cannot be modified
+fail_compilation/test16381.d(15): Error: cannot take address of expression `foo()` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test22048.d b/gcc/testsuite/gdc.test/fail_compilation/test22048.d
index e0560689f8d..72b91546a2b 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test22048.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test22048.d
@@ -3,7 +3,7 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test22048.d(10): Error: unexpected identifier `p` in declarator
+fail_compilation/test22048.d(10): Error: unexpected identifier `p` after `int`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24157.d b/gcc/testsuite/gdc.test/fail_compilation/test24157.d
index 5022014a9a1..d78c9b628ef 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/test24157.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24157.d
@@ -3,8 +3,8 @@ 
 /*
 TEST_OUTPUT:
 ---
-fail_compilation/test24157.d(23): Error: `p.self()` is not an lvalue and cannot be modified
-fail_compilation/test24157.d(27): Error: `p.unshared()` is not an lvalue and cannot be modified
+fail_compilation/test24157.d(23): Error: cannot take address of expression `p.self()` because it is not an lvalue
+fail_compilation/test24157.d(27): Error: cannot take address of expression `p.unshared()` because it is not an lvalue
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/test24159.d b/gcc/testsuite/gdc.test/fail_compilation/test24159.d
new file mode 100644
index 00000000000..35c7f364168
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/test24159.d
@@ -0,0 +1,14 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=24159
+// REQUIRED_ARGS: -betterC
+/*
+TEST_OUTPUT:
+---
+fail_compilation/test24159.d(13): Error: appending to array in `x ~= 3` requires the GC which is not available with -betterC
+---
+*/
+
+extern(C) void main()
+{
+    int[] x = null;
+    x ~= 3;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
index 50cebabfda4..1173d14480d 100644
--- a/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
+++ b/gcc/testsuite/gdc.test/fail_compilation/testrvaluecpctor.d
@@ -5,9 +5,9 @@  TEST_OUTPUT:
 ---
 fail_compilation/testrvaluecpctor.d(16): Error: cannot define both an rvalue constructor and a copy constructor for `struct Foo`
 fail_compilation/testrvaluecpctor.d(24):        Template instance `testrvaluecpctor.Foo!int.Foo.__ctor!(immutable(Foo!int), immutable(Foo!int))` creates an rvalue constructor for `struct Foo`
-fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `__ctor` are callable using a `immutable` object
+fail_compilation/testrvaluecpctor.d(24): Error: none of the overloads of `this` can construct a `immutable` object with argument types `(immutable(Foo!int))`
 fail_compilation/testrvaluecpctor.d(18):        Candidates are: `testrvaluecpctor.Foo!int.Foo.this(ref scope Foo!int rhs)`
-fail_compilation/testrvaluecpctor.d(16):                        `__ctor(Rhs, this This)(scope Rhs rhs)`
+fail_compilation/testrvaluecpctor.d(16):                        `this(Rhs, this This)(scope Rhs rhs)`
 ---
 */
 
diff --git a/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d b/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d
new file mode 100644
index 00000000000..e911dff7729
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/tolvalue.d
@@ -0,0 +1,48 @@ 
+/**
+TEST_OUTPUT:
+---
+fail_compilation/tolvalue.d(28): Error: cannot take address of template `templateFunc(T)()`, perhaps instantiate it first
+fail_compilation/tolvalue.d(29): Error: cannot take address of type `int`
+fail_compilation/tolvalue.d(30): Error: cannot take address of constant `3`
+fail_compilation/tolvalue.d(31): Error: cannot take address of operator `$`
+fail_compilation/tolvalue.d(32): Error: cannot take address of compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(33): Error: cannot take address of manifest constant `f`
+fail_compilation/tolvalue.d(38): Error: cannot create default argument for `ref` / `out` parameter from constant `3`
+fail_compilation/tolvalue.d(39): Error: cannot create default argument for `ref` / `out` parameter from compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(40): Error: cannot create default argument for `ref` / `out` parameter from manifest constant `f`
+fail_compilation/tolvalue.d(45): Error: cannot modify constant `3`
+fail_compilation/tolvalue.d(46): Error: cannot modify compiler-generated variable `__ctfe`
+fail_compilation/tolvalue.d(47): Error: cannot modify manifest constant `f`
+---
+*/
+
+// https://issues.dlang.org/show_bug.cgi?id=24238
+
+void templateFunc(T)() {}
+alias intAlias = int;
+enum E { f }
+
+void addr()
+{
+    int[] a;
+    auto x0 = &templateFunc;
+    auto x1 = &intAlias;
+    auto x2 = &3;
+    auto x3 = a[&$];
+    auto x4 = &__ctfe;
+    auto x6 = &E.f;
+}
+
+void refArg()
+{
+    void f0(ref int = 3) {}
+    void f1(ref bool = __ctfe) {}
+    void f3(ref E = E.f) {}
+}
+
+void inc(int lz)
+{
+    3++;
+    __ctfe++;
+    E.f++;
+}
diff --git a/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d b/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d
new file mode 100644
index 00000000000..e8a8d48c790
--- /dev/null
+++ b/gcc/testsuite/gdc.test/fail_compilation/vector_cast.d
@@ -0,0 +1,13 @@ 
+/**
+REQUIRED_ARGS: -m64
+TEST_OUTPUT:
+---
+fail_compilation/vector_cast.d(11): Error: cannot cast expression `a` of type `int[3]` to `__vector(int[4])`
+fail_compilation/vector_cast.d(13): Error: cannot cast expression `a` of type `int[5]` to `__vector(int[4])`
+---
+*/
+
+alias int4 = __vector(int[4]);
+int4 convtest3(int[3] a) { return cast(int4) a; }
+int4 convtest4(int[4] a) { return cast(int4) a; }
+int4 convtest5(int[5] a) { return cast(int4) a; }
diff --git a/gcc/testsuite/gdc.test/runnable/staticaa.d b/gcc/testsuite/gdc.test/runnable/staticaa.d
index 17a2ecb5ec7..606b70e908a 100644
--- a/gcc/testsuite/gdc.test/runnable/staticaa.d
+++ b/gcc/testsuite/gdc.test/runnable/staticaa.d
@@ -56,7 +56,7 @@  struct Key
 {
     int v;
     bool opEquals(ref const Key o) const { return v == o.v; }
-    size_t toHash() const { return v; }
+    size_t toHash() const nothrow { return v; }
 }
 
 Destructing[Key] dAa = [Key(1): Destructing(10), Key(2): Destructing(20)];
@@ -142,6 +142,18 @@  void testImmutable()
 
 /////////////////////////////////////////////
 
+// https://issues.dlang.org/show_bug.cgi?id=24209
+void testLocalStatic() @trusted
+{
+    static int[int] aa0 = [1: 2];
+    __gshared string[string] aa1 = null;
+
+    assert(aa0[1] == 2);
+    assert(aa1.length == 0);
+}
+
+/////////////////////////////////////////////
+
 void main()
 {
     testSimple();
@@ -150,4 +162,5 @@  void main()
     testStructInit();
     testClassInit();
     testImmutable();
+    testLocalStatic();
 }
diff --git a/gcc/testsuite/gdc.test/runnable/test24184.d b/gcc/testsuite/gdc.test/runnable/test24184.d
new file mode 100644
index 00000000000..736824fce86
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test24184.d
@@ -0,0 +1,30 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=24184
+
+void stage3(alias abc)(ubyte[])
+{
+    bool skipSpaces()
+    {
+        abc();
+        return false;
+    }
+    skipSpaces;
+}
+ubyte[] singleThreadJsonImpl(alias xxx)(ubyte[] table)
+{
+    align(64) ubyte[] vector;
+
+    ubyte[] abc() { return vector; }
+
+    stage3!(abc)(table);
+
+    return table;
+}
+ubyte[] singleThreadJsonText()
+{
+    bool xxx() { return true; }
+
+    return singleThreadJsonImpl!(xxx)([]);
+}
+void deserializeJson() { singleThreadJsonText(); }
+
+void main() { deserializeJson(); }
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 235db4b2ef1..aa0062c10eb 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-643b1261bba0757d97efa3ff1f63e461271eb000
+ff57fec51558013b25cadb7e83da9f4675915d56
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/dmd repository.
diff --git a/libphobos/libdruntime/core/cpuid.d b/libphobos/libdruntime/core/cpuid.d
index b79bd1df9c4..9c5735728b5 100644
--- a/libphobos/libdruntime/core/cpuid.d
+++ b/libphobos/libdruntime/core/cpuid.d
@@ -666,10 +666,12 @@  void getAMDcacheinfo()
 // to determine number of processors.
 void getCpuInfo0B()
 {
-    int level=0;
     int threadsPerCore;
     uint a, b, c, d;
-    do {
+    // I'm not sure about this. The docs state that there
+    // are 2 hyperthreads per core if HT is factory enabled.
+    for (int level = 0; level < 2; level++)
+    {
         version (GNU_OR_LDC) asm pure nothrow @nogc {
             "cpuid" : "=a" (a), "=b" (b), "=c" (c), "=d" (d) : "a" (0x0B), "c" (level);
         } else asm pure nothrow @nogc {
@@ -681,19 +683,20 @@  void getCpuInfo0B()
             mov c, ECX;
             mov d, EDX;
         }
-        if (b!=0) {
-           // I'm not sure about this. The docs state that there
-           // are 2 hyperthreads per core if HT is factory enabled.
-            if (level==0)
+        if (b != 0)
+        {
+            if (level == 0)
                 threadsPerCore = b & 0xFFFF;
-            else if (level==1) {
+            else if (level == 1)
+            {
                 cpuFeatures.maxThreads = b & 0xFFFF;
                 cpuFeatures.maxCores = cpuFeatures.maxThreads / threadsPerCore;
             }
-
         }
-        ++level;
-    } while (a!=0 || b!=0);
+        // Got "invalid domain" returned from cpuid
+        if (a == 0 && b == 0)
+            break;
+    }
 }
 
 void cpuidX86()
diff --git a/libphobos/libdruntime/core/internal/array/appending.d b/libphobos/libdruntime/core/internal/array/appending.d
index bb24813ae9e..ba34727a305 100644
--- a/libphobos/libdruntime/core/internal/array/appending.d
+++ b/libphobos/libdruntime/core/internal/array/appending.d
@@ -14,56 +14,55 @@  private extern (C) byte[] _d_arrayappendcTX(const TypeInfo ti, ref return scope
 
 private enum isCopyingNothrow(T) = __traits(compiles, (ref T rhs) nothrow { T lhs = rhs; });
 
-/// Implementation of `_d_arrayappendcTX` and `_d_arrayappendcTXTrace`
-template _d_arrayappendcTXImpl(Tarr : T[], T)
+/**
+ * Extend an array `px` by `n` elements.
+ * Caller must initialize those elements.
+ * Params:
+ *  px = the array that will be extended, taken as a reference
+ *  n = how many new elements to extend it with
+ * Returns:
+ *  The new value of `px`
+ * Bugs:
+ *  This function template was ported from a much older runtime hook that bypassed safety,
+ *  purity, and throwabilty checks. To prevent breaking existing code, this function template
+ *  is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+ */
+ref Tarr _d_arrayappendcTX(Tarr : T[], T)(return ref scope Tarr px, size_t n) @trusted
 {
-    private enum errorMessage = "Cannot append to array if compiling without support for runtime type information!";
+    // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
+    version (DigitalMars) pragma(inline, false);
+    version (D_TypeInfo)
+    {
+        auto ti = typeid(Tarr);
+
+        // _d_arrayappendcTX takes the `px` as a ref byte[], but its length
+        // should still be the original length
+        auto pxx = (cast(byte*)px.ptr)[0 .. px.length];
+        ._d_arrayappendcTX(ti, pxx, n);
+        px = (cast(T*)pxx.ptr)[0 .. pxx.length];
+
+        return px;
+    }
+    else
+        assert(0, "Cannot append to array if compiling without support for runtime type information!");
+}
 
+version (D_ProfileGC)
+{
     /**
-     * Extend an array `px` by `n` elements.
-     * Caller must initialize those elements.
-     * Params:
-     *  px = the array that will be extended, taken as a reference
-     *  n = how many new elements to extend it with
-     * Returns:
-     *  The new value of `px`
-     * Bugs:
-     *  This function template was ported from a much older runtime hook that bypassed safety,
-     *  purity, and throwabilty checks. To prevent breaking existing code, this function template
-     *  is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
+     * TraceGC wrapper around $(REF _d_arrayappendT, core,internal,array,appending).
      */
-    ref Tarr _d_arrayappendcTX(return ref scope Tarr px, size_t n) @trusted pure nothrow
+    ref Tarr _d_arrayappendcTXTrace(Tarr : T[], T)(string file, int line, string funcname, return ref scope Tarr px, size_t n) @trusted
     {
-        // needed for CTFE: https://github.com/dlang/druntime/pull/3870#issuecomment-1178800718
-        version (DigitalMars) pragma(inline, false);
         version (D_TypeInfo)
         {
-            auto ti = typeid(Tarr);
-
-            // _d_arrayappendcTX takes the `px` as a ref byte[], but its length
-            // should still be the original length
-            auto pxx = (cast(byte*)px.ptr)[0 .. px.length];
-            ._d_arrayappendcTX(ti, pxx, n);
-            px = (cast(T*)pxx.ptr)[0 .. pxx.length];
+            import core.internal.array.utils: TraceHook, gcStatsPure, accumulatePure;
+            mixin(TraceHook!(Tarr.stringof, "_d_arrayappendcTX"));
 
-            return px;
+            return _d_arrayappendcTX(px, n);
         }
         else
-            assert(0, errorMessage);
-    }
-
-    version (D_ProfileGC)
-    {
-        import core.internal.array.utils : _d_HookTraceImpl;
-
-        /**
-         * TraceGC wrapper around $(REF _d_arrayappendcTX, rt,array,appending,_d_arrayappendcTXImpl).
-         * Bugs:
-         *  This function template was ported from a much older runtime hook that bypassed safety,
-         *  purity, and throwabilty checks. To prevent breaking existing code, this function template
-         *  is temporarily declared `@trusted pure` until the implementation can be brought up to modern D expectations.
-         */
-        alias _d_arrayappendcTXTrace = _d_HookTraceImpl!(Tarr, _d_arrayappendcTX, errorMessage);
+            static assert(0, "Cannot append to array if compiling without support for runtime type information!");
     }
 }
 
@@ -78,7 +77,7 @@  ref Tarr _d_arrayappendT(Tarr : T[], T)(return ref scope Tarr x, scope Tarr y) @
     enum hasPostblit = __traits(hasPostblit, T);
     auto length = x.length;
 
-    _d_arrayappendcTXImpl!Tarr._d_arrayappendcTX(x, y.length);
+    _d_arrayappendcTX(x, y.length);
 
     // Only call `copyEmplace` if `T` has a copy ctor and no postblit.
     static if (hasElaborateCopyConstructor!T && !hasPostblit)
@@ -126,7 +125,7 @@  version (D_ProfileGC)
             return _d_arrayappendT(x, y);
         }
         else
-            assert(0, "Cannot append to array if compiling without support for runtime type information!");
+            static assert(0, "Cannot append to array if compiling without support for runtime type information!");
     }
 }
 
diff --git a/libphobos/libdruntime/core/internal/array/construction.d b/libphobos/libdruntime/core/internal/array/construction.d
index 54f8767139c..655acc8db57 100644
--- a/libphobos/libdruntime/core/internal/array/construction.d
+++ b/libphobos/libdruntime/core/internal/array/construction.d
@@ -486,3 +486,111 @@  version (D_ProfileGC)
             assert(0, "Cannot create new array if compiling without support for runtime type information!");
     }
 }
+
+/**
+ * Create a new multi-dimensional array. Also initalize elements if their type has an initializer.
+ * Otherwise, not zero-initialize the array.
+ *
+ * ---
+ * void main()
+ * {
+ *     S[][] s = new S[][](2, 3)
+ *
+ *     // lowering:
+ *     S[] s = _d_newarraymTX!(S[][], S)([2, 3]);
+ * }
+ * ---
+ *
+ * Params:
+ *    dims = array length values for each dimension
+ *    isShared = whether the array should be shared
+ *
+ * Returns:
+ *    newly allocated array
+ */
+Tarr _d_newarraymTX(Tarr : U[], T, U)(size_t[] dims, bool isShared=false) @trusted
+{
+    debug(PRINTF) printf("_d_newarraymTX(dims.length = %d)\n", dims.length);
+
+    if (dims.length == 0)
+        return null;
+
+    alias UnqT = Unqual!(T);
+
+    void[] __allocateInnerArray(size_t[] dims)
+    {
+        import core.internal.array.utils : __arrayStart, __setArrayAllocLength, __arrayAlloc;
+
+        auto dim = dims[0];
+
+        debug(PRINTF) printf("__allocateInnerArray(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
+        if (dims.length == 1)
+        {
+            auto r = _d_newarrayT!UnqT(dim, isShared);
+            return *cast(void[]*)(&r);
+        }
+
+        auto allocSize = (void[]).sizeof * dim;
+        auto info = __arrayAlloc!UnqT(allocSize);
+        __setArrayAllocLength!UnqT(info, allocSize, isShared);
+        auto p = __arrayStart(info)[0 .. dim];
+
+        foreach (i; 0..dim)
+        {
+            (cast(void[]*)p.ptr)[i] = __allocateInnerArray(dims[1..$]);
+        }
+        return p;
+    }
+
+    auto result = __allocateInnerArray(dims);
+    debug(PRINTF) printf("result = %llx\n", result.ptr);
+
+    return (cast(U*) result.ptr)[0 .. dims[0]];
+}
+
+unittest
+{
+    int[][] a = _d_newarraymTX!(int[][], int)([2, 3]);
+
+    assert(a.length == 2);
+    for (size_t i = 0; i < a.length; i++)
+    {
+        assert(a[i].length == 3);
+        for (size_t j = 0; j < a[i].length; j++)
+            assert(a[i][j] == 0);
+    }
+}
+
+unittest
+{
+    struct S { int x = 1; }
+
+    S[][] a = _d_newarraymTX!(S[][], S)([2, 3]);
+
+    assert(a.length == 2);
+    for (size_t i = 0; i < a.length; i++)
+    {
+        assert(a[i].length == 3);
+        for (size_t j = 0; j < a[i].length; j++)
+            assert(a[i][j].x == 1);
+    }
+}
+
+version (D_ProfileGC)
+{
+    /**
+    * TraceGC wrapper around $(REF _d_newarraymT, core,internal,array,construction).
+    */
+    Tarr _d_newarraymTXTrace(Tarr : U[], T, U)(string file, int line, string funcname, size_t[] dims, bool isShared=false) @trusted
+    {
+        version (D_TypeInfo)
+        {
+            import core.internal.array.utils : TraceHook, gcStatsPure, accumulatePure;
+            mixin(TraceHook!(T.stringof, "_d_newarraymTX"));
+
+            return _d_newarraymTX!(Tarr, T)(dims, isShared);
+        }
+        else
+            assert(0, "Cannot create new multi-dimensional array if compiling without support for runtime type information!");
+    }
+}
diff --git a/libphobos/libdruntime/core/internal/atomic.d b/libphobos/libdruntime/core/internal/atomic.d
index 5daab89a387..eebf94ee29d 100644
--- a/libphobos/libdruntime/core/internal/atomic.d
+++ b/libphobos/libdruntime/core/internal/atomic.d
@@ -656,7 +656,7 @@  version (DigitalMars)
             asm pure nothrow @nogc @trusted
             {
                 naked;
-                rep; nop;
+                pause;
                 ret;
             }
         }
@@ -665,8 +665,7 @@  version (DigitalMars)
             asm pure nothrow @nogc @trusted
             {
                 naked;
-    //            pause; // TODO: DMD should add this opcode to its inline asm
-                rep; nop;
+                pause;
                 ret;
             }
         }
diff --git a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
index 39cd30aee16..6f194126e7e 100644
--- a/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
+++ b/libphobos/libdruntime/core/internal/gc/impl/conservative/gc.d
@@ -3336,7 +3336,7 @@  Lmark:
 
         busyThreads.atomicOp!"+="(1); // main thread is busy
 
-        evStart.set();
+        evStart.setIfInitialized();
 
         debug(PARALLEL_PRINTF) printf("mark %lld roots\n", cast(ulong)(ptop - pbot));
 
@@ -3438,7 +3438,7 @@  Lmark:
         stopGC = true;
         while (atomicLoad(stoppedThreads) < startedThreads && !allThreadsDead)
         {
-            evStart.set();
+            evStart.setIfInitialized();
             evDone.wait(dur!"msecs"(1));
         }
 
@@ -3467,7 +3467,7 @@  Lmark:
         {
             evStart.wait();
             pullFromScanStack();
-            evDone.set();
+            evDone.setIfInitialized();
         }
         stoppedThreads.atomicOp!"+="(1);
     }
diff --git a/libphobos/libdruntime/core/internal/newaa.d b/libphobos/libdruntime/core/internal/newaa.d
index 314f2554103..2fd93651a22 100644
--- a/libphobos/libdruntime/core/internal/newaa.d
+++ b/libphobos/libdruntime/core/internal/newaa.d
@@ -50,6 +50,7 @@  struct Impl
     immutable uint valsz;
     immutable uint valoff;
     Flags flags;
+    size_t delegate(scope const void*) nothrow hashFn;
 
     enum Flags : ubyte
     {
@@ -76,15 +77,19 @@  private size_t mix(size_t h) @safe pure nothrow @nogc
 
 struct Entry(K, V)
 {
-    /*const*/ K key; // this really should be const, but legacy issues.
+    // can make this const, because we aren't really going to use it aside from
+    // construction.
+    const K key;
     V value;
 }
 
 
 // create a binary-compatible AA structure that can be used directly as an
 // associative array.
-AAShell makeAA(K, V)(V[K] src)
+// NOTE: this must only be called during CTFE
+AAShell makeAA(K, V)(V[K] src) @trusted
 {
+    assert(__ctfe, "makeAA Must only be called at compile time");
     immutable srclen = src.length;
     assert(srclen <= uint.max);
     alias E = Entry!(K, V);
@@ -96,6 +101,12 @@  AAShell makeAA(K, V)(V[K] src)
     while (srclen * GROW_DEN > dim * GROW_NUM)
         dim = dim * GROW_FAC;
 
+    // used during runtime.
+    size_t delegate(scope const void *) nothrow hashFn = (scope const void* val) {
+        auto x = cast(K*)val;
+        return hashOf(*x);
+    };
+
     Bucket[] buckets;
     // Allocate and fill the buckets
     if (__ctfe)
@@ -140,5 +151,19 @@  AAShell makeAA(K, V)(V[K] src)
     } ();
     // return the new implementation
     return AAShell(new Impl(buckets, cast(uint)srclen, 0, typeid(E), firstUsed,
-            K.sizeof, V.sizeof, E.value.offsetof, flags));
+            K.sizeof, V.sizeof, E.value.offsetof, flags, hashFn));
+}
+
+unittest
+{
+    static struct Foo
+    {
+        ubyte x;
+        double d;
+    }
+    static int[Foo] utaa = [Foo(1, 2.0) : 5];
+    auto k = Foo(1, 2.0);
+    // verify that getHash doesn't match hashOf for Foo
+    assert(typeid(Foo).getHash(&k) != hashOf(k));
+    assert(utaa[Foo(1, 2.0)] == 5);
 }
diff --git a/libphobos/libdruntime/core/stdc/fenv.d b/libphobos/libdruntime/core/stdc/fenv.d
index 288f9c25dc6..0051ecdb7c9 100644
--- a/libphobos/libdruntime/core/stdc/fenv.d
+++ b/libphobos/libdruntime/core/stdc/fenv.d
@@ -797,7 +797,7 @@  else
     }
     else version (LoongArch64)
     {
-        // Define bits representing exceptions in the FPSR status word.
+        // Define bits representing exceptions in the Flags field in FCSR{0,2}.
         enum
         {
             FE_INEXACT      = 0x010000, ///
@@ -808,13 +808,13 @@  else
             FE_ALL_EXCEPT   = 0x1f0000, ///
         }
 
-        // Define bits representing rounding modes in the FPCR Rmode field.
+        // Define bits representing rounding modes in the RM field in FCSR{0,3}.
         enum
         {
             FE_TONEAREST    = 0x000, ///
             FE_TOWARDZERO   = 0x100, ///
-            FE_DOWNWARD     = 0x200, ///
-            FE_UPWARD       = 0x300, ///
+            FE_UPWARD       = 0x200, ///
+            FE_DOWNWARD     = 0x300, ///
         }
     }
     else
diff --git a/libphobos/libdruntime/core/stdc/stdarg.d b/libphobos/libdruntime/core/stdc/stdarg.d
index 5b79813ae1b..0ba1ebe34e3 100644
--- a/libphobos/libdruntime/core/stdc/stdarg.d
+++ b/libphobos/libdruntime/core/stdc/stdarg.d
@@ -257,6 +257,12 @@  T va_arg(T)(ref va_list ap)
         ap += T.sizeof.alignUp;
         return *p;
     }
+    else version (LoongArch64)
+    {
+        auto p = cast(T*) ap;
+        ap += T.sizeof.alignUp;
+        return *p;
+    }
     else version (MIPS_Any)
     {
         auto p = cast(T*) ap;
diff --git a/libphobos/libdruntime/core/sync/event.d b/libphobos/libdruntime/core/sync/event.d
index 37951061d93..048607f6ed2 100644
--- a/libphobos/libdruntime/core/sync/event.d
+++ b/libphobos/libdruntime/core/sync/event.d
@@ -61,7 +61,7 @@  struct ProcessFile
             group.create(&doProcess);
 
         buffer = std.file.read(filename);
-        event.set();
+        event.setIfInitialized();
         group.joinAll();
         event.terminate();
     }
@@ -162,9 +162,13 @@  nothrow @nogc:
         }
     }
 
+    deprecated ("Use setIfInitialized() instead") void set()
+    {
+        setIfInitialized();
+    }
 
     /// Set the event to "signaled", so that waiting clients are resumed
-    void set()
+    void setIfInitialized()
     {
         version (Windows)
         {
@@ -302,7 +306,7 @@  private:
     // auto-reset, initial state false
     Event ev1 = Event(false, false);
     assert(!ev1.wait(1.dur!"msecs"));
-    ev1.set();
+    ev1.setIfInitialized();
     assert(ev1.wait());
     assert(!ev1.wait(1.dur!"msecs"));
 
@@ -336,7 +340,7 @@  unittest
     auto start = MonoTime.currTime;
     assert(numRunning == 0);
 
-    event.set();
+    event.setIfInitialized();
     group.joinAll();
 
     assert(numRunning == numThreads);
diff --git a/libphobos/libdruntime/core/sys/elf/package.d b/libphobos/libdruntime/core/sys/elf/package.d
index b120ee58f69..60e05d97036 100644
--- a/libphobos/libdruntime/core/sys/elf/package.d
+++ b/libphobos/libdruntime/core/sys/elf/package.d
@@ -339,6 +339,8 @@  enum EM_CSKY =        252;
 
 enum EM_NUM =         253;
 
+enum EM_LOONGARCH =   258;
+
 enum EM_ALPHA =        0x9026;
 
 enum EV_NONE =         0;
diff --git a/libphobos/libdruntime/core/sys/linux/sys/auxv.d b/libphobos/libdruntime/core/sys/linux/sys/auxv.d
index 5f098e98e02..1099fae497f 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/auxv.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/auxv.d
@@ -13,6 +13,7 @@  extern (C):
 
 version (MIPS32)  version = MIPS_Any;
 version (MIPS64)  version = MIPS_Any;
+version (LoongArch64) version = LoongArch_Any;
 version (PPC)     version = PPC_Any;
 version (PPC64)   version = PPC_Any;
 version (S390)    version = IBMZ_Any;
@@ -156,3 +157,19 @@  else version (IBMZ_Any)
   enum HWCAP_S390_TE                      = 1024;
   enum HWCAP_S390_VX                      = 2048;
 }
+else version (LoongArch_Any)
+{
+  enum HWCAP_LOONGARCH_CPUCFG             = 0x00000001;
+  enum HWCAP_LOONGARCH_LAM                = 0x00000002;
+  enum HWCAP_LOONGARCH_UAL                = 0x00000004;
+  enum HWCAP_LOONGARCH_FPU                = 0x00000008;
+  enum HWCAP_LOONGARCH_LSX                = 0x00000010;
+  enum HWCAP_LOONGARCH_LASX               = 0x00000020;
+  enum HWCAP_LOONGARCH_CRC32              = 0x00000040;
+  enum HWCAP_LOONGARCH_COMPLEX            = 0x00000080;
+  enum HWCAP_LOONGARCH_CRYPTO             = 0x00000100;
+  enum HWCAP_LOONGARCH_LVZ                = 0x00000200;
+  enum HWCAP_LOONGARCH_LBT_X86            = 0x00000400;
+  enum HWCAP_LOONGARCH_LBT_ARM            = 0x00000800;
+  enum HWCAP_LOONGARCH_LBT_MIPS           = 0x00001000;
+}
diff --git a/libphobos/libdruntime/core/sys/linux/sys/mman.d b/libphobos/libdruntime/core/sys/linux/sys/mman.d
index 7ed78ef6436..e4765af1490 100644
--- a/libphobos/libdruntime/core/sys/linux/sys/mman.d
+++ b/libphobos/libdruntime/core/sys/linux/sys/mman.d
@@ -432,6 +432,7 @@  else version (MIPS_Any)
         MAP_HUGETLB = 0x80000,
     }
 }
+// http://sourceware.org/git/?p=glibc.git;a=blob;f=sysdeps/unix/sysv/linux/bits/mman-map-flags-generic.h
 else version (LoongArch64)
 {
     static if (_DEFAULT_SOURCE) enum
diff --git a/libphobos/libdruntime/core/thread/fiber.d b/libphobos/libdruntime/core/thread/fiber.d
index 65878bc1c66..8bbd6e15c4e 100644
--- a/libphobos/libdruntime/core/thread/fiber.d
+++ b/libphobos/libdruntime/core/thread/fiber.d
@@ -178,8 +178,12 @@  private
     }
     else version (LoongArch64)
     {
-        version = AsmLoongArch64_Posix;
-        version = AsmExternal;
+        version (Posix)
+        {
+            version = AsmLoongArch64_Posix;
+            version = AsmExternal;
+            version = AlignFiberStackTo16Byte;
+        }
     }
 
     version (Posix)
@@ -1444,24 +1448,28 @@  private:
         }
         else version (AsmLoongArch64_Posix)
         {
+            // Like others, FP registers and return address ($r1) are kept
+            // below the saved stack top (tstack) to hide from GC scanning.
+            // fiber_switchContext expects newp sp to look like this:
+            //   10: $r21 (reserved)
+            //    9: $r22 (frame pointer)
+            //    8: $r23
+            //   ...
+            //    0: $r31 <-- newp tstack
+            //   -1: $r1  (return address)  [&fiber_entryPoint]
+            //   -2: $f24
+            //   ...
+            //   -9: $f31
+
             version (StackGrowsDown) {}
-            else static assert(0);
+            else
+                static assert(false, "Only full descending stacks supported on LoongArch64");
 
-            // Like others, FP registers and return address (ra) are kept
-            // below the saved stack top (tstack) to hide from GC scanning.
-            // The newp stack should look like this on LoongArch64:
-            // 18: fp     <- pstack
-            // ...
-            //  9: s0     <- newp tstack
-            //  8: ra     [&fiber_entryPoint]
-            //  7: fs7
-            // ...
-            //  1: fs1
-            //  0: fs0
-            pstack -= 10 * size_t.sizeof; // skip s0-s8 and fp
-            // set $ra
-            push( cast(size_t) &fiber_entryPoint );
-            pstack += size_t.sizeof;
+            // Only need to set return address ($r1).  Everything else is fine
+            // zero initialized.
+            pstack -= size_t.sizeof * 11;    // skip past space reserved for $r21-$r31
+            push (cast(size_t) &fiber_entryPoint);
+            pstack += size_t.sizeof;         // adjust sp (newp) above lr
         }
         else version (AsmAArch64_Posix)
         {
diff --git a/libphobos/libdruntime/core/vararg.d b/libphobos/libdruntime/core/vararg.d
index 2c3e9659fb6..e6dd47d06d3 100644
--- a/libphobos/libdruntime/core/vararg.d
+++ b/libphobos/libdruntime/core/vararg.d
@@ -129,6 +129,13 @@  void va_arg()(ref va_list ap, TypeInfo ti, void* parmn)
         ap += tsize.alignUp;
         parmn[0..tsize] = p[0..tsize];
     }
+    else version (LoongArch64)
+    {
+        const tsize = ti.tsize;
+        auto p = cast(void*) ap;
+        ap += tsize.alignUp;
+        parmn[0..tsize] = p[0..tsize];
+    }
     else version (MIPS_Any)
     {
         const tsize = ti.tsize;
diff --git a/libphobos/libdruntime/object.d b/libphobos/libdruntime/object.d
index 0111be0b617..5589c0a884f 100644
--- a/libphobos/libdruntime/object.d
+++ b/libphobos/libdruntime/object.d
@@ -642,7 +642,8 @@  class TypeInfo
      */
     size_t getHash(scope const void* p) @trusted nothrow const
     {
-        return hashOf(p);
+        // by default, do not assume anything about the type
+        return 0;
     }
 
     /// Compares two instances for equality.
@@ -2918,19 +2919,19 @@  alias AssociativeArray(Key, Value) = Value[Key];
  * Params:
  *      aa =     The associative array.
  */
-void clear(Value, Key)(Value[Key] aa)
+void clear(Value, Key)(Value[Key] aa) @trusted
 {
     _aaClear(*cast(AA *) &aa);
 }
 
 /** ditto */
-void clear(Value, Key)(Value[Key]* aa)
+void clear(Value, Key)(Value[Key]* aa) @trusted
 {
     _aaClear(*cast(AA *) aa);
 }
 
 ///
-@system unittest
+@safe unittest
 {
     auto aa = ["k1": 2];
     aa.clear;
@@ -4666,11 +4667,13 @@  public import core.internal.array.appending : _d_arrayappendT;
 version (D_ProfileGC)
 {
     public import core.internal.array.appending : _d_arrayappendTTrace;
+    public import core.internal.array.appending : _d_arrayappendcTXTrace;
     public import core.internal.array.concatenation : _d_arraycatnTXTrace;
     public import core.lifetime : _d_newitemTTrace;
     public import core.internal.array.construction : _d_newarrayTTrace;
+    public import core.internal.array.construction : _d_newarraymTXTrace;
 }
-public import core.internal.array.appending : _d_arrayappendcTXImpl;
+public import core.internal.array.appending : _d_arrayappendcTX;
 public import core.internal.array.comparison : __cmp;
 public import core.internal.array.equality : __equals;
 public import core.internal.array.casting: __ArrayCast;
@@ -4678,6 +4681,7 @@  public import core.internal.array.concatenation : _d_arraycatnTX;
 public import core.internal.array.construction : _d_arrayctor;
 public import core.internal.array.construction : _d_arraysetctor;
 public import core.internal.array.construction : _d_newarrayT;
+public import core.internal.array.construction : _d_newarraymTX;
 public import core.internal.array.arrayassign : _d_arrayassign_l;
 public import core.internal.array.arrayassign : _d_arrayassign_r;
 public import core.internal.array.arrayassign : _d_arraysetassign;
diff --git a/libphobos/libdruntime/rt/aaA.d b/libphobos/libdruntime/rt/aaA.d
index 4014862b4e4..36f25554db3 100644
--- a/libphobos/libdruntime/rt/aaA.d
+++ b/libphobos/libdruntime/rt/aaA.d
@@ -41,7 +41,7 @@  struct AA
     Impl* impl;
     alias impl this;
 
-    private @property bool empty() const pure nothrow @nogc
+    private @property bool empty() const pure nothrow @nogc @safe
     {
         return impl is null || !impl.length;
     }
@@ -57,6 +57,7 @@  private:
         buckets = allocBuckets(sz);
         firstUsed = cast(uint) buckets.length;
         valoff = cast(uint) talign(keysz, ti.value.talign);
+        hashFn = &ti.key.getHash;
 
         import rt.lifetime : hasPostblit, unqualify;
 
@@ -78,6 +79,10 @@  private:
     immutable uint valoff;
     Flags flags;
 
+    // function that calculates hash of a key. Set on creation
+    // the parameter is a pointer to the key.
+    size_t delegate(scope const void*) nothrow hashFn;
+
     enum Flags : ubyte
     {
         none = 0x0,
@@ -85,7 +90,7 @@  private:
         hasPointers = 0x2,
     }
 
-    @property size_t length() const pure nothrow @nogc
+    @property size_t length() const pure nothrow @nogc @safe
     {
         assert(used >= deleted);
         return used - deleted;
@@ -156,7 +161,7 @@  private:
         GC.free(obuckets.ptr); // safe to free b/c impossible to reference
     }
 
-    void clear() pure nothrow
+    void clear() pure nothrow @trusted
     {
         import core.stdc.string : memset;
         // clear all data, but don't change bucket array length
@@ -457,9 +462,9 @@  private size_t mix(size_t h) @safe pure nothrow @nogc
     return h;
 }
 
-private size_t calcHash(scope const void* pkey, scope const TypeInfo keyti) nothrow
+private size_t calcHash(scope const void *pkey, scope const Impl* impl) nothrow
 {
-    immutable hash = keyti.getHash(pkey);
+    immutable hash = impl.hashFn(pkey);
     // highest bit is set to distinguish empty/deleted from filled buckets
     return mix(hash) | HASH_FILLED_MARK;
 }
@@ -550,7 +555,7 @@  extern (C) void* _aaGetX(scope AA* paa, const TypeInfo_AssociativeArray ti,
     }
 
     // get hash and bucket for key
-    immutable hash = calcHash(pkey, ti.key);
+    immutable hash = calcHash(pkey, aa);
 
     // found a value => return it
     if (auto p = aa.findSlotLookup(hash, pkey, ti.key))
@@ -617,7 +622,7 @@  extern (C) inout(void)* _aaInX(inout AA aa, scope const TypeInfo keyti, scope co
     if (aa.empty)
         return null;
 
-    immutable hash = calcHash(pkey, keyti);
+    immutable hash = calcHash(pkey, aa);
     if (auto p = aa.findSlotLookup(hash, pkey, keyti))
         return p.entry + aa.valoff;
     return null;
@@ -629,7 +634,7 @@  extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke
     if (aa.empty)
         return false;
 
-    immutable hash = calcHash(pkey, keyti);
+    immutable hash = calcHash(pkey, aa);
     if (auto p = aa.findSlotLookup(hash, pkey, keyti))
     {
         // clear entry
@@ -648,7 +653,7 @@  extern (C) bool _aaDelX(AA aa, scope const TypeInfo keyti, scope const void* pke
 }
 
 /// Remove all elements from AA.
-extern (C) void _aaClear(AA aa) pure nothrow
+extern (C) void _aaClear(AA aa) pure nothrow @safe
 {
     if (!aa.empty)
     {
@@ -778,7 +783,7 @@  extern (C) Impl* _d_assocarrayliteralTX(const TypeInfo_AssociativeArray ti, void
     uint actualLength = 0;
     foreach (_; 0 .. length)
     {
-        immutable hash = calcHash(pkey, ti.key);
+        immutable hash = calcHash(pkey, aa);
 
         auto p = aa.findSlotLookup(hash, pkey, ti.key);
         if (p is null)
diff --git a/libphobos/libdruntime/rt/lifetime.d b/libphobos/libdruntime/rt/lifetime.d
index af3c6bb1296..8ce2d564bd6 100644
--- a/libphobos/libdruntime/rt/lifetime.d
+++ b/libphobos/libdruntime/rt/lifetime.d
@@ -1041,98 +1041,6 @@  extern (C) void[] _d_newarrayiT(const TypeInfo ti, size_t length) pure nothrow @
     }
 }
 
-
-/*
- * Helper for creating multi-dimensional arrays
- */
-private void[] _d_newarrayOpT(alias op)(const TypeInfo ti, size_t[] dims)
-{
-    debug(PRINTF) printf("_d_newarrayOpT(ndims = %d)\n", dims.length);
-    if (dims.length == 0)
-        return null;
-
-    void[] foo(const TypeInfo ti, size_t[] dims)
-    {
-        auto tinext = unqualify(ti.next);
-        auto dim = dims[0];
-
-        debug(PRINTF) printf("foo(ti = %p, ti.next = %p, dim = %d, ndims = %d\n", ti, ti.next, dim, dims.length);
-        if (dims.length == 1)
-        {
-            auto r = op(ti, dim);
-            return *cast(void[]*)(&r);
-        }
-
-        auto allocsize = (void[]).sizeof * dim;
-        auto info = __arrayAlloc(allocsize, ti, tinext);
-        auto isshared = typeid(ti) is typeid(TypeInfo_Shared);
-        __setArrayAllocLength(info, allocsize, isshared, tinext);
-        auto p = __arrayStart(info)[0 .. dim];
-
-        foreach (i; 0..dim)
-        {
-            (cast(void[]*)p.ptr)[i] = foo(tinext, dims[1..$]);
-        }
-        return p;
-    }
-
-    auto result = foo(ti, dims);
-    debug(PRINTF) printf("result = %llx\n", result.ptr);
-
-    return result;
-}
-
-
-/**
-Create a new multi-dimensional array
-
-Has two variants:
-- `_d_newarraymTX` which initializes to 0
-- `_d_newarraymiTX` which initializes elements based on `TypeInfo`
-
----
-void main()
-{
-    new int[][](10, 20);
-    // _d_newarraymTX(typeid(float), [10, 20]);
-
-    new float[][][](10, 20, 30);
-    // _d_newarraymiTX(typeid(float), [10, 20, 30]);
-}
----
-
-Params:
-    ti = `TypeInfo` of the array type
-    dims = array length values for each dimension
-
-Returns:
-    newly allocated array
-*/
-extern (C) void[] _d_newarraymTX(const TypeInfo ti, size_t[] dims) @weak
-{
-    debug(PRINTF) printf("_d_newarraymT(dims.length = %d)\n", dims.length);
-
-    if (dims.length == 0)
-        return null;
-    else
-    {
-        return _d_newarrayOpT!(_d_newarrayT)(ti, dims);
-    }
-}
-
-/// ditto
-extern (C) void[] _d_newarraymiTX(const TypeInfo ti, size_t[] dims) @weak
-{
-    debug(PRINTF) printf("_d_newarraymiT(dims.length = %d)\n", dims.length);
-
-    if (dims.length == 0)
-        return null;
-    else
-    {
-        return _d_newarrayOpT!(_d_newarrayiT)(ti, dims);
-    }
-}
-
 /**
 Non-template version of $(REF _d_newitemT, core,lifetime) that does not perform
 initialization. Needed for $(REF allocEntry, rt,aaA).
diff --git a/libphobos/src/MERGE b/libphobos/src/MERGE
index 95b2778d141..1b20d58c1e2 100644
--- a/libphobos/src/MERGE
+++ b/libphobos/src/MERGE
@@ -1,4 +1,4 @@ 
-fc06c514a8c4492f60fc89b8c4f857e6932fbcbd
+17bafda797296e04f40f16a9660e5a9685392db4
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/phobos repository.
diff --git a/libphobos/src/std/algorithm/iteration.d b/libphobos/src/std/algorithm/iteration.d
index 0adb88b2210..ef1170600b3 100644
--- a/libphobos/src/std/algorithm/iteration.d
+++ b/libphobos/src/std/algorithm/iteration.d
@@ -4809,26 +4809,41 @@  private template ReduceSeedType(E)
 /++
 Implements the homonym function (also known as `accumulate`, $(D
 compress), `inject`, or `foldl`) present in various programming
-languages of functional flavor. The call `fold!(fun)(range, seed)`
-first assigns `seed` to an internal variable `result`,
-also called the accumulator. Then, for each element `x` in $(D
-range), `result = fun(result, x)` gets evaluated. Finally, $(D
-result) is returned. The one-argument version `fold!(fun)(range)`
+languages of functional flavor, iteratively calling one or more predicates.
+
+$(P Each predicate in `fun` must take two arguments:)
+* An accumulator value
+* An element of the range `r`
+$(P Each predicate must return a value which implicitly converts to the
+type of the accumulator.)
+
+$(P For a single predicate,
+the call `fold!(fun)(range, seed)` will:)
+
+* Use `seed` to initialize an internal variable `result` (also called
+  the accumulator).
+* For each element `e` in $(D range), evaluate `result = fun(result, e)`.
+* Return $(D result).
+
+$(P The one-argument version `fold!(fun)(range)`
 works similarly, but it uses the first element of the range as the
-seed (the range must be non-empty).
+seed (the range must be non-empty) and iterates over the remaining
+elements.)
+
+Multiple results are produced when using multiple predicates.
 
 Params:
     fun = the predicate function(s) to apply to the elements
 
 See_Also:
-    $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
+    * $(HTTP en.wikipedia.org/wiki/Fold_(higher-order_function), Fold (higher-order function))
 
-    $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers
-    precise summing of floating point numbers.
+    * $(LREF sum) is similar to `fold!((a, b) => a + b)` that offers
+      precise summing of floating point numbers.
 
-    This is functionally equivalent to $(LREF reduce) with the argument order
-    reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons)
-    for multiple seeds.
+    * `fold` is functionally equivalent to $(LREF reduce) with the argument order
+      reversed, and without the need to use $(REF_ALTTEXT `tuple`,tuple,std,typecons)
+      for multiple seeds.
 +/
 template fold(fun...)
 if (fun.length >= 1)
@@ -4836,20 +4851,21 @@  if (fun.length >= 1)
     /**
     Params:
         r = the $(REF_ALTTEXT input range, isInputRange, std,range,primitives) to fold
-        seed = the initial value of the accumulator
+        seeds = the initial values of each accumulator (optional), one for each predicate
     Returns:
-        the accumulated `result`
+        Either the accumulated result for a single predicate, or a
+        $(REF_ALTTEXT `Tuple`,Tuple,std,typecons) of results.
      */
-    auto fold(R, S...)(R r, S seed)
+    auto fold(R, S...)(R r, S seeds)
     {
         static if (S.length < 2)
         {
-            return reduce!fun(seed, r);
+            return reduce!fun(seeds, r);
         }
         else
         {
             import std.typecons : tuple;
-            return reduce!fun(tuple(seed), r);
+            return reduce!fun(tuple(seeds), r);
         }
     }
 }
@@ -4860,10 +4876,10 @@  if (fun.length >= 1)
     immutable arr = [1, 2, 3, 4, 5];
 
     // Sum all elements
-    assert(arr.fold!((a, b) => a + b) == 15);
+    assert(arr.fold!((a, e) => a + e) == 15);
 
     // Sum all elements with explicit seed
-    assert(arr.fold!((a, b) => a + b)(6) == 21);
+    assert(arr.fold!((a, e) => a + e)(6) == 21);
 
     import std.algorithm.comparison : min, max;
     import std.typecons : tuple;
@@ -4875,10 +4891,10 @@  if (fun.length >= 1)
     assert(arr.fold!(min, max)(0, 7) == tuple(0, 7));
 
     // Can be used in a UFCS chain
-    assert(arr.map!(a => a + 1).fold!((a, b) => a + b) == 20);
+    assert(arr.map!(a => a + 1).fold!((a, e) => a + e) == 20);
 
     // Return the last element of any range
-    assert(arr.fold!((a, b) => b) == 5);
+    assert(arr.fold!((a, e) => e) == 5);
 }
 
 @safe @nogc pure nothrow unittest
diff --git a/libphobos/src/std/algorithm/searching.d b/libphobos/src/std/algorithm/searching.d
index 37a08de7a8f..68979057f54 100644
--- a/libphobos/src/std/algorithm/searching.d
+++ b/libphobos/src/std/algorithm/searching.d
@@ -1546,28 +1546,96 @@  if (isInputRange!Range && !isInfinite!Range &&
 }
 
 // find
+/**
+Finds an element `e` of an $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+where `pred(e)` is `true`.
+$(P
+$(PANEL
+$(UL
+$(LI `find` behaves similarly to `dropWhile` in other languages.)
+$(LI To _find the *last* matching element in a
+$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`,
+call `find!pred(retro(haystack))`. See $(REF retro, std,range).)
+)))
+
+Complexity:
+    `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
+
+Params:
+
+    pred = The predicate to match an element.
+    haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
+               searched in.
+
+Returns:
+    `haystack` advanced such that the front element satisfies `pred`.
+    If no such element exists, returns an empty `haystack`.
+*/
+InputRange find(alias pred, InputRange)(InputRange haystack)
+if (isInputRange!InputRange)
+{
+    alias R = InputRange;
+    alias predFun = unaryFun!pred;
+    static if (isNarrowString!R)
+    {
+        import std.utf : decode;
+
+        immutable len = haystack.length;
+        size_t i = 0, next = 0;
+        while (next < len)
+        {
+            if (predFun(decode(haystack, next)))
+                return haystack[i .. $];
+            i = next;
+        }
+        return haystack[$ .. $];
+    }
+    else
+    {
+        //standard range
+        for ( ; !haystack.empty; haystack.popFront() )
+        {
+            if (predFun(haystack.front))
+                break;
+        }
+        return haystack;
+    }
+}
+
+///
+@safe unittest
+{
+    auto arr = [ 1, 2, 3, 4, 1 ];
+    assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
+
+    // with predicate alias
+    bool pred(int e) => e + 1 > 1.5;
+    assert(find!(pred)(arr) == arr);
+}
+
+@safe pure unittest
+{
+    int[] r = [ 1, 2, 3 ];
+    assert(find!(a=>a > 2)(r) == [3]);
+    bool pred(int x) { return x + 1 > 1.5; }
+    assert(find!(pred)(r) == r);
+
+    assert(find!(a=>a > 'v')("hello world") == "world");
+    assert(find!(a=>a%4 == 0)("日本語") == "本語");
+}
+
 /**
 Finds an individual element in an $(REF_ALTTEXT input range, isInputRange, std,range,primitives).
 Elements of `haystack` are compared with `needle` by using predicate
 `pred` with `pred(haystack.front, needle)`.
-`find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
-
 The predicate is passed to $(REF binaryFun, std, functional), and can either accept a
 string, or any callable that can be executed via `pred(element, element)`.
 
-To _find the last occurrence of `needle` in a
-$(REF_ALTTEXT bidirectional, isBidirectionalRange, std,range,primitives) `haystack`,
-call `find(retro(haystack), needle)`. See $(REF retro, std,range).
-
-If no `needle` is provided, `pred(haystack.front)` will be evaluated on each
-element of the input range.
-
-If `input` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives),
+If `haystack` is a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives),
 `needle` can be a $(REF_ALTTEXT forward range, isForwardRange, std,range,primitives) too.
 In this case `startsWith!pred(haystack, needle)` is evaluated on each evaluation.
 
-Note:
-    `find` behaves similar to `dropWhile` in other languages.
+$(NOTE To find the first element $(I not) matching the needle, use predicate `"a != b"`.)
 
 Complexity:
     `find` performs $(BIGOH walkLength(haystack)) evaluations of `pred`.
@@ -1579,21 +1647,16 @@  Complexity:
 Params:
 
     pred = The predicate for comparing each element with the needle, defaulting to equality `"a == b"`.
-           The negated predicate `"a != b"` can be used to search instead for the first
-           element $(I not) matching the needle.
-
     haystack = The $(REF_ALTTEXT input range, isInputRange, std,range,primitives)
                searched in.
-
     needle = The element searched for.
 
 Returns:
-
     `haystack` advanced such that the front element is the one searched for;
     that is, until `binaryFun!pred(haystack.front, needle)` is `true`. If no
     such position exists, returns an empty `haystack`.
 
-See_ALso: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith)
+See_Also: $(LREF findAdjacent), $(LREF findAmong), $(LREF findSkip), $(LREF findSplit), $(LREF startsWith)
 */
 InputRange find(alias pred = "a == b", InputRange, Element)(InputRange haystack, scope Element needle)
 if (isInputRange!InputRange &&
@@ -1754,8 +1817,8 @@  if (isInputRange!InputRange &&
     assert(arr.find(4) == [4, 4, 4, 4, 5, 6, 9]);
     assert(arr.find(1) == arr);
     assert(arr.find(9) == [9]);
-    assert(arr.find!((a, b) => a > b)(4) == [5, 6, 9]);
-    assert(arr.find!((a, b) => a < b)(4) == arr);
+    assert(arr.find!((e, n) => e > n)(4) == [5, 6, 9]);
+    assert(arr.find!((e, n) => e < n)(4) == arr);
     assert(arr.find(0).empty);
     assert(arr.find(10).empty);
     assert(arr.find(8).empty);
@@ -1770,7 +1833,7 @@  if (isInputRange!InputRange &&
     import std.uni : toLower;
 
     string[] s = ["Hello", "world", "!"];
-    assert(s.find!((a, b) => toLower(a) == b)("hello") == s);
+    assert(s.find!((e, n) => toLower(e) == n)("hello") == s);
 }
 
 @safe unittest
@@ -1862,60 +1925,6 @@  if (isInputRange!InputRange &&
     assert([x].find(x).empty == false);
 }
 
-/// ditto
-InputRange find(alias pred, InputRange)(InputRange haystack)
-if (isInputRange!InputRange)
-{
-    alias R = InputRange;
-    alias predFun = unaryFun!pred;
-    static if (isNarrowString!R)
-    {
-        import std.utf : decode;
-
-        immutable len = haystack.length;
-        size_t i = 0, next = 0;
-        while (next < len)
-        {
-            if (predFun(decode(haystack, next)))
-                return haystack[i .. $];
-            i = next;
-        }
-        return haystack[$ .. $];
-    }
-    else
-    {
-        //standard range
-        for ( ; !haystack.empty; haystack.popFront() )
-        {
-            if (predFun(haystack.front))
-                break;
-        }
-        return haystack;
-    }
-}
-
-///
-@safe unittest
-{
-    auto arr = [ 1, 2, 3, 4, 1 ];
-    assert(find!("a > 2")(arr) == [ 3, 4, 1 ]);
-
-    // with predicate alias
-    bool pred(int x) { return x + 1 > 1.5; }
-    assert(find!(pred)(arr) == arr);
-}
-
-@safe pure unittest
-{
-    int[] r = [ 1, 2, 3 ];
-    assert(find!(a=>a > 2)(r) == [3]);
-    bool pred(int x) { return x + 1 > 1.5; }
-    assert(find!(pred)(r) == r);
-
-    assert(find!(a=>a > 'v')("hello world") == "world");
-    assert(find!(a=>a%4 == 0)("日本語") == "本語");
-}
-
 /// ditto
 R1 find(alias pred = "a == b", R1, R2)(R1 haystack, scope R2 needle)
 if (isForwardRange!R1 && isForwardRange!R2
@@ -2376,9 +2385,9 @@  is considered to be 1.) The strategy used in searching several
 subranges at once maximizes cache usage by moving in `haystack` as
 few times as possible.
  */
-Tuple!(Range, size_t) find(alias pred = "a == b", Range, Ranges...)
-(Range haystack, Ranges needles)
-if (Ranges.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
+Tuple!(Range, size_t) find(alias pred = "a == b", Range, Needles...)
+(Range haystack, Needles needles)
+if (Needles.length > 1 && is(typeof(startsWith!pred(haystack, needles))))
 {
     for (;; haystack.popFront())
     {
@@ -2536,13 +2545,13 @@  was successful.
 For more information about `pred` see $(LREF find).
 
 See_Also:
-$(REF among, std,algorithm,comparison) for checking a value against multiple possibilities.
+$(REF among, std,algorithm,comparison) for checking a value against multiple arguments.
  +/
 template canFind(alias pred="a == b")
 {
     /++
-    Returns `true` if and only if any value `v` found in the
-    input range `range` satisfies the predicate `pred`.
+    Returns `true` if and only if `pred(e)` is true for any value `e` in the
+    input range `range`.
     Performs (at most) $(BIGOH haystack.length) evaluations of `pred`.
      +/
     bool canFind(Range)(Range haystack)
@@ -2565,16 +2574,15 @@  template canFind(alias pred="a == b")
     Returns the 1-based index of the first needle found in `haystack`. If no
     needle is found, then `0` is returned.
 
-    So, if used directly in the condition of an if statement or loop, the result
+    So, if used directly in the condition of an `if` statement or loop, the result
     will be `true` if one of the needles is found and `false` if none are
     found, whereas if the result is used elsewhere, it can either be cast to
     `bool` for the same effect or used to get which needle was found first
-    without having to deal with the tuple that `LREF find` returns for the
+    without having to deal with the tuple that $(LREF find) returns for the
     same operation.
      +/
-    size_t canFind(Range, Ranges...)(Range haystack, scope Ranges needles)
-    if (Ranges.length > 1 &&
-        allSatisfy!(isForwardRange, Ranges) &&
+    size_t canFind(Range, Needles...)(Range haystack, scope Needles needles)
+    if (Needles.length > 1 &&
         is(typeof(find!pred(haystack, needles))))
     {
         return find!pred(haystack, needles)[1];
@@ -2584,15 +2592,21 @@  template canFind(alias pred="a == b")
 ///
 @safe unittest
 {
-    assert(canFind([0, 1, 2, 3], 2) == true);
-    assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]));
-    assert(canFind([0, 1, 2, 3], [1, 2], [2, 3]) == 1);
-    assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]));
-    assert(canFind([0, 1, 2, 3], [1, 7], [2, 3]) == 2);
+    const arr = [0, 1, 2, 3];
+    assert(canFind(arr, 2));
+    assert(!canFind(arr, 4));
+
+    // find one of several needles
+    assert(arr.canFind(3, 2));
+    assert(arr.canFind(3, 2) == 2); // second needle found
+    assert(arr.canFind([1, 3], 2) == 2);
 
-    assert(canFind([0, 1, 2, 3], 4) == false);
-    assert(!canFind([0, 1, 2, 3], [1, 3], [2, 4]));
-    assert(canFind([0, 1, 2, 3], [1, 3], [2, 4]) == 0);
+    assert(canFind(arr, [1, 2], [2, 3]));
+    assert(canFind(arr, [1, 2], [2, 3]) == 1);
+    assert(canFind(arr, [1, 7], [2, 3]));
+    assert(canFind(arr, [1, 7], [2, 3]) == 2);
+    assert(!canFind(arr, [1, 3], [2, 4]));
+    assert(canFind(arr, [1, 3], [2, 4]) == 0);
 }
 
 /**
@@ -2607,10 +2621,10 @@  template canFind(alias pred="a == b")
         "cardboard"
     ];
     assert(!canFind(words, "bees"));
-    assert( canFind!((string a, string b) => a.startsWith(b))(words, "bees"));
+    assert( canFind!((string elem, string needle) => elem.startsWith(needle))(words, "bees"));
 }
 
-/// Search for mutliple items in an array of items (search for needles in an array of hay stacks)
+/// Search for multiple items in an array of items (search for needles in an array of haystacks)
 @safe unittest
 {
     string s1 = "aaa111aaa";
@@ -2618,7 +2632,7 @@  template canFind(alias pred="a == b")
     string s3 = "aaa333aaa";
     string s4 = "aaa444aaa";
     const hay = [s1, s2, s3, s4];
-    assert(hay.canFind!(e => (e.canFind("111", "222"))));
+    assert(hay.canFind!(e => e.canFind("111", "222")));
 }
 
 @safe unittest
@@ -2736,7 +2750,7 @@  Returns:
 `seq` advanced to the first matching element, or until empty if there are no
 matching elements.
 
-See_Also: $(LREF find), $(REF std,algorithm,comparison,among)
+See_Also: $(LREF find), $(REF among, std,algorithm,comparison)
 */
 InputRange findAmong(alias pred = "a == b", InputRange, ForwardRange)(
     InputRange seq, ForwardRange choices)
diff --git a/libphobos/src/std/array.d b/libphobos/src/std/array.d
index a613a8d9e4a..494fa297b4b 100644
--- a/libphobos/src/std/array.d
+++ b/libphobos/src/std/array.d
@@ -1201,7 +1201,7 @@  private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
     auto a2 = minimallyInitializedArray!(S2[][])(2, 2);
     assert(a2);
     enum b2 = minimallyInitializedArray!(S2[][])(2, 2);
-    assert(b2);
+    assert(b2 !is null);
     static struct S3
     {
         //this() @disable;
@@ -1210,7 +1210,7 @@  private auto arrayAllocImpl(bool minimallyInitialized, T, I...)(I sizes) nothrow
     auto a3 = minimallyInitializedArray!(S3[][])(2, 2);
     assert(a3);
     enum b3 = minimallyInitializedArray!(S3[][])(2, 2);
-    assert(b3);
+    assert(b3 !is null);
 }
 
 /++
diff --git a/libphobos/src/std/logger/package.d b/libphobos/src/std/logger/package.d
index 330ef88aa06..14a439486db 100644
--- a/libphobos/src/std/logger/package.d
+++ b/libphobos/src/std/logger/package.d
@@ -54,7 +54,7 @@  $(UL
     $(LI `trace`)
     $(LI `info`)
     $(LI `warning`)
-    #(LI `error`)
+    $(LI `error`)
     $(LI `critical`)
     $(LI `fatal`)
 )
diff --git a/libphobos/src/std/math/hardware.d b/libphobos/src/std/math/hardware.d
index 81c7302b4c1..cb6cb87845c 100644
--- a/libphobos/src/std/math/hardware.d
+++ b/libphobos/src/std/math/hardware.d
@@ -33,6 +33,7 @@  version (SPARC64)   version = SPARC_Any;
 version (SystemZ)   version = IBMZ_Any;
 version (RISCV32)   version = RISCV_Any;
 version (RISCV64)   version = RISCV_Any;
+version (LoongArch64)   version = LoongArch_Any;
 
 version (D_InlineAsm_X86)    version = InlineAsm_X86_Any;
 version (D_InlineAsm_X86_64) version = InlineAsm_X86_Any;
@@ -60,6 +61,7 @@  else version (X86_Any)   version = IeeeFlagsSupport;
 else version (PPC_Any)   version = IeeeFlagsSupport;
 else version (RISCV_Any) version = IeeeFlagsSupport;
 else version (MIPS_Any)  version = IeeeFlagsSupport;
+else version (LoongArch_Any) version = IeeeFlagsSupport;
 else version (ARM_Any)   version = IeeeFlagsSupport;
 
 // Struct FloatingPointControl is only available if hardware FP units are available.
@@ -90,6 +92,7 @@  private:
     // The ARM and PowerPC FPSCR is a 32-bit register.
     // The SPARC FSR is a 32bit register (64 bits for SPARC 7 & 8, but high bits are uninteresting).
     // The RISC-V (32 & 64 bit) fcsr is 32-bit register.
+    // THe LoongArch fcsr (fcsr0) is a 32-bit register.
     uint flags;
 
     version (CRuntime_Microsoft)
@@ -216,6 +219,15 @@  private:
             return result;
             `);
         }
+        else version (LoongArch_Any)
+        {
+            uint result = void;
+            asm pure nothrow @nogc
+            {
+                "movfcsr2gr %0,$r2" : "=r" (result);
+            }
+            return result & EXCEPTIONS_MASK;
+        }
         else
             assert(0, "Not yet supported");
     }
@@ -303,6 +315,13 @@  private:
             }
             `);
         }
+        else version (LoongArch_Any)
+        {
+            asm nothrow @nogc
+            {
+                "movgr2fcsr $r2,$r0";
+            }
+        }
         else
         {
             /* SPARC:
@@ -725,6 +744,21 @@  nothrow @nogc:
                                  | inexactException,
         }
     }
+    else version (LoongArch_Any)
+    {
+        enum : ExceptionMask
+        {
+            inexactException      = 0x00,
+            divByZeroException    = 0x01,
+            overflowException     = 0x02,
+            underflowException    = 0x04,
+            invalidException      = 0x08,
+            severeExceptions   = overflowException | divByZeroException
+                                 | invalidException,
+            allExceptions      = severeExceptions | underflowException
+                                 | inexactException,
+        }
+    }
     else version (MIPS_Any)
     {
         enum : ExceptionMask
@@ -812,6 +846,8 @@  nothrow @nogc:
             return true;
         else version (MIPS_Any)
             return true;
+        else version (LoongArch_Any)
+            return true;
         else version (ARM_Any)
         {
             // The hasExceptionTraps_impl function is basically pure,
@@ -885,6 +921,10 @@  private:
     {
         alias ControlState = uint;
     }
+    else version (LoongArch_Any)
+    {
+        alias ControlState = uint;
+    }
     else version (MIPS_Any)
     {
         alias ControlState = uint;
@@ -1008,6 +1048,16 @@  private:
             return cont;
             `);
         }
+        else version (LoongArch_Any)
+        {
+            ControlState cont;
+            asm pure nothrow @nogc
+            {
+                "movfcsr2gr %0,$r0" : "=r" (cont);
+            }
+            cont &= (roundingMask | allExceptions);
+            return cont;
+        }
         else
             assert(0, "Not yet supported");
     }
@@ -1120,6 +1170,14 @@  private:
             }
             `);
         }
+        else version (LoongArch_Any)
+        {
+            asm nothrow @nogc
+            {
+                "movgr2fcsr $r0,%0" :
+                : "r" (newState & (roundingMask | allExceptions));
+            }
+        }
         else
             assert(0, "Not yet supported");
     }