diff mbox series

[committed] d: Merge upstream dmd 529110f66, druntime 148608b7.

Message ID 20220624185611.3905081-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] d: Merge upstream dmd 529110f66, druntime 148608b7. | expand

Commit Message

Iain Buclaw June 24, 2022, 6:56 p.m. UTC
Hi,

This patch merges the D front-end with upstream dmd 529110f66.

The git revision hash of libdruntime has also been bumped, though the
only changes made have been outside what is merged downstream.

D front-end changes:

    - Import latest bug fixes to mainline.

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

Regards,
Iain.

---
gcc/d/ChangeLog:

	* dmd/MERGE: Merge upstream dmd 529110f66.
	* decl.cc (DeclVisitor::visit (TupleDeclaration *)): Update for new
	front-end interface.
	* types.cc (layout_aggregate_members): Likewise.

libphobos/ChangeLog:

	* libdruntime/MERGE: Merge upstream druntime 148608b7.
---
 gcc/d/decl.cc                                 |   6 +-
 gcc/d/dmd/MERGE                               |   2 +-
 gcc/d/dmd/canthrow.d                          |  13 +-
 gcc/d/dmd/cparse.d                            |  34 ++++-
 gcc/d/dmd/declaration.d                       |  63 +++++----
 gcc/d/dmd/dinterpret.d                        |  17 +--
 gcc/d/dmd/dmangle.d                           |  18 ++-
 gcc/d/dmd/dsymbolsem.d                        |  33 +++--
 gcc/d/dmd/dtoh.d                              | 128 +++++++++---------
 gcc/d/dmd/expression.d                        |   8 +-
 gcc/d/dmd/expressionsem.d                     | 104 ++++++++++----
 gcc/d/dmd/foreachvar.d                        |  14 +-
 gcc/d/dmd/importc.d                           |   4 +
 gcc/d/dmd/ob.d                                |  22 +--
 gcc/d/dmd/parse.d                             |  11 +-
 gcc/d/dmd/root/filename.d                     |  27 ++--
 gcc/d/dmd/semantic2.d                         |   5 +
 gcc/d/dmd/semantic3.d                         |   2 +-
 gcc/d/types.cc                                |   6 +-
 .../compilable/dtoh_AnonDeclaration.d         |  14 +-
 .../compilable/dtoh_StructDeclaration.d       |  18 ++-
 .../compilable/dtoh_TemplateDeclaration.d     |   6 +-
 .../gdc.test/compilable/dtoh_mangling.d       |   8 +-
 .../gdc.test/compilable/dtoh_protection.d     |  28 +++-
 gcc/testsuite/gdc.test/compilable/test23168.d |  30 ++++
 gcc/testsuite/gdc.test/compilable/test23169.d |  14 ++
 gcc/testsuite/gdc.test/compilable/testparse.d |  10 ++
 gcc/testsuite/gdc.test/runnable/test23010.d   |  43 ++++++
 libphobos/libdruntime/MERGE                   |   2 +-
 29 files changed, 464 insertions(+), 226 deletions(-)
 create mode 100644 gcc/testsuite/gdc.test/compilable/test23168.d
 create mode 100644 gcc/testsuite/gdc.test/compilable/test23169.d
 create mode 100644 gcc/testsuite/gdc.test/runnable/test23010.d
diff mbox series

Patch

diff --git a/gcc/d/decl.cc b/gcc/d/decl.cc
index 8676a1b588b..b82e2d55c13 100644
--- a/gcc/d/decl.cc
+++ b/gcc/d/decl.cc
@@ -225,9 +225,9 @@  public:
 	RootObject *o = (*d->objects)[i];
 	if (o->dyncast () == DYNCAST_EXPRESSION)
 	  {
-	    DsymbolExp *de = ((Expression *) o)->isDsymbolExp ();
-	    if (de != NULL && de->s->isDeclaration ())
-	      this->build_dsymbol (de->s);
+	    VarExp *ve = ((Expression *) o)->isVarExp ();
+	    if (ve)
+	      this->build_dsymbol (ve->var);
 	  }
       }
   }
diff --git a/gcc/d/dmd/MERGE b/gcc/d/dmd/MERGE
index d1e3dc16312..f5c42f0ff00 100644
--- a/gcc/d/dmd/MERGE
+++ b/gcc/d/dmd/MERGE
@@ -1,4 +1,4 @@ 
-6203135dcf0112d3211add0cbfb22fecc5df1af4
+529110f66d7d301d62d943a4e4482edaddeb46ea
 
 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/canthrow.d b/gcc/d/dmd/canthrow.d
index a38cbb1610b..fe6e1e344b9 100644
--- a/gcc/d/dmd/canthrow.d
+++ b/gcc/d/dmd/canthrow.d
@@ -270,18 +270,7 @@  private CT Dsymbol_canThrow(Dsymbol s, FuncDeclaration func, bool mustNotThrow)
     }
     else if (auto td = s.isTupleDeclaration())
     {
-        for (size_t i = 0; i < td.objects.dim; i++)
-        {
-            RootObject o = (*td.objects)[i];
-            if (o.dyncast() == DYNCAST.expression)
-            {
-                Expression eo = cast(Expression)o;
-                if (auto se = eo.isDsymbolExp())
-                {
-                    result |= Dsymbol_canThrow(se.s, func, mustNotThrow);
-                }
-            }
-        }
+        td.foreachVar(&symbolDg);
     }
     return result;
 }
diff --git a/gcc/d/dmd/cparse.d b/gcc/d/dmd/cparse.d
index 62ba889cc13..dff76345fa5 100644
--- a/gcc/d/dmd/cparse.d
+++ b/gcc/d/dmd/cparse.d
@@ -2413,11 +2413,19 @@  final class CParser(AST) : Parser!AST
                 if (scw & scwx)
                     error("duplicate storage class");
                 scw |= scwx;
+                // C11 6.7.1-2 At most one storage-class may be given, except that
+                // _Thread_local may appear with static or extern.
                 const scw2 = scw & (SCW.xstatic | SCW.xextern | SCW.xauto | SCW.xregister | SCW.xtypedef);
                 if (scw2 & (scw2 - 1) ||
-                    scw & (SCW.xauto | SCW.xregister) && scw & (SCW.xinline | SCW.x_Noreturn))
+                    scw & (SCW.x_Thread_local) && scw & (SCW.xauto | SCW.xregister | SCW.xtypedef))
                 {
-                    error("conflicting storage class");
+                    error("multiple storage classes in declaration specifiers");
+                    scw &= ~scwx;
+                }
+                if (level == LVL.local &&
+                    scw & (SCW.x_Thread_local) && scw & (SCW.xinline | SCW.x_Noreturn))
+                {
+                    error("`inline` and `_Noreturn` function specifiers not allowed for `_Thread_local`");
                     scw &= ~scwx;
                 }
                 if (level & (LVL.parameter | LVL.prototype) &&
@@ -2964,7 +2972,8 @@  final class CParser(AST) : Parser!AST
                 cparseGnuAttributes(specifier);
             if (specifier.mod & MOD.xconst)
                 t = toConst(t);
-            auto param = new AST.Parameter(STC.parameter, t, id, null, null);
+            auto param = new AST.Parameter(specifiersToSTC(LVL.parameter, specifier),
+                                           t, id, null, null);
             parameters.push(param);
             if (token.value == TOK.rightParenthesis)
                 break;
@@ -4630,6 +4639,15 @@  final class CParser(AST) : Parser!AST
                     stc = AST.STC.extern_ | AST.STC.gshared;
                 else if (specifier.scw & SCW.xstatic)
                     stc = AST.STC.gshared;
+                else if (specifier.scw & SCW.xregister)
+                    stc = AST.STC.register;
+            }
+            else if (level == LVL.parameter)
+            {
+                if (specifier.scw & SCW.xregister)
+                    stc = AST.STC.register | AST.STC.parameter;
+                else
+                    stc = AST.STC.parameter;
             }
             else if (level == LVL.member)
             {
@@ -5138,6 +5156,7 @@  final class CParser(AST) : Parser!AST
         if (!defines || defines.length < 10)  // minimum length of a #define line
             return;
         const length = defines.length;
+        defines.writeByte(0);
         auto slice = defines.peekChars()[0 .. length];
         resetDefineLines(slice);                // reset lexer
 
@@ -5234,12 +5253,15 @@  final class CParser(AST) : Parser!AST
                 }
                 skipToNextLine();
             }
-            else if (n.value != TOK.endOfLine)
+            else
             {
-                skipToNextLine();
+                scan(&n);
+                if (n.value != TOK.endOfLine)
+                {
+                    skipToNextLine();
+                }
             }
             nextDefineLine();
-            assert(p - slice.ptr <= length);
         }
     }
 
diff --git a/gcc/d/dmd/declaration.d b/gcc/d/dmd/declaration.d
index bb0feb642bd..ffb33d379db 100644
--- a/gcc/d/dmd/declaration.d
+++ b/gcc/d/dmd/declaration.d
@@ -656,23 +656,46 @@  extern (C++) final class TupleDeclaration : Declaration
     override bool needThis()
     {
         //printf("TupleDeclaration::needThis(%s)\n", toChars());
-        for (size_t i = 0; i < objects.dim; i++)
+        return isexp ? foreachVar((s) { return s.needThis(); }) != 0 : false;
+    }
+
+    /***********************************************************
+     * Calls dg(Dsymbol) for each Dsymbol, which should be a VarDeclaration
+     * inside VarExp (isexp == true).
+     * Params:
+     *    dg = delegate to call for each Dsymbol
+     */
+    extern (D) void foreachVar(scope void delegate(Dsymbol) dg)
+    {
+        assert(isexp);
+        foreach (o; *objects)
         {
-            RootObject o = (*objects)[i];
-            if (o.dyncast() == DYNCAST.expression)
-            {
-                Expression e = cast(Expression)o;
-                if (DsymbolExp ve = e.isDsymbolExp())
-                {
-                    Declaration d = ve.s.isDeclaration();
-                    if (d && d.needThis())
-                    {
-                        return true;
-                    }
-                }
-            }
+            if (auto e = o.isExpression())
+                if (auto ve = e.isVarExp())
+                    dg(ve.var);
         }
-        return false;
+    }
+
+    /***********************************************************
+     * Calls dg(Dsymbol) for each Dsymbol, which should be a VarDeclaration
+     * inside VarExp (isexp == true).
+     * If dg returns !=0, stops and returns that value else returns 0.
+     * Params:
+     *    dg = delegate to call for each Dsymbol
+     * Returns:
+     *    last value returned by dg()
+     */
+    extern (D) int foreachVar(scope int delegate(Dsymbol) dg)
+    {
+        assert(isexp);
+        foreach (o; *objects)
+        {
+            if (auto e = o.isExpression())
+                if (auto ve = e.isVarExp())
+                    if(auto ret = dg(ve.var))
+                        return ret;
+        }
+        return 0;
     }
 
     override inout(TupleDeclaration) isTupleDeclaration() inout
@@ -1142,15 +1165,7 @@  extern (C++) class VarDeclaration : Declaration
             // If this variable was really a tuple, set the offsets for the tuple fields
             TupleDeclaration v2 = aliassym.isTupleDeclaration();
             assert(v2);
-            for (size_t i = 0; i < v2.objects.dim; i++)
-            {
-                RootObject o = (*v2.objects)[i];
-                assert(o.dyncast() == DYNCAST.expression);
-                Expression e = cast(Expression)o;
-                assert(e.op == EXP.dSymbol);
-                DsymbolExp se = e.isDsymbolExp();
-                se.s.setFieldOffset(ad, fieldState, isunion);
-            }
+            v2.foreachVar((s) { s.setFieldOffset(ad, fieldState, isunion); });
             return;
         }
 
diff --git a/gcc/d/dmd/dinterpret.d b/gcc/d/dmd/dinterpret.d
index bb25210019f..5841a252454 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -2306,16 +2306,12 @@  public:
                 result = null;
 
                 // Reserve stack space for all tuple members
-                if (!td.objects)
-                    return;
-                foreach (o; *td.objects)
+                td.foreachVar((s)
                 {
-                    Expression ex = isExpression(o);
-                    DsymbolExp ds = ex ? ex.isDsymbolExp() : null;
-                    VarDeclaration v2 = ds ? ds.s.isVarDeclaration() : null;
+                    VarDeclaration v2 = s.isVarDeclaration();
                     assert(v2);
                     if (v2.isDataseg() && !v2.isCTFE())
-                        continue;
+                        return 0;
 
                     ctfeGlobals.stack.push(v2);
                     if (v2._init)
@@ -2325,7 +2321,7 @@  public:
                         {
                             einit = interpretRegion(ie.exp, istate, goal);
                             if (exceptionOrCant(einit))
-                                return;
+                                return 1;
                         }
                         else if (v2._init.isVoidInitializer())
                         {
@@ -2335,11 +2331,12 @@  public:
                         {
                             e.error("declaration `%s` is not yet implemented in CTFE", e.toChars());
                             result = CTFEExp.cantexp;
-                            return;
+                            return 1;
                         }
                         setValue(v2, einit);
                     }
-                }
+                    return 0;
+                });
                 return;
             }
             if (v.isStatic())
diff --git a/gcc/d/dmd/dmangle.d b/gcc/d/dmd/dmangle.d
index 76042969b9b..25794e2c21d 100644
--- a/gcc/d/dmd/dmangle.d
+++ b/gcc/d/dmd/dmangle.d
@@ -371,10 +371,20 @@  public:
         if (ta.isnogc)
             buf.writestring("Ni");
 
-        if (ta.isreturn && !ta.isreturninferred)
-            buf.writestring("Nj");
-        else if (ta.isScopeQual && !ta.isscopeinferred)
-            buf.writestring("Nl");
+        // `return scope` must be in that order
+        if (ta.isreturnscope && !ta.isreturninferred)
+        {
+            buf.writestring("NjNl");
+        }
+        else
+        {
+            // when return ref, the order is `scope return`
+            if (ta.isScopeQual && !ta.isscopeinferred)
+                buf.writestring("Nl");
+
+            if (ta.isreturn && !ta.isreturninferred)
+                buf.writestring("Nj");
+        }
 
         if (ta.islive)
             buf.writestring("Nm");
diff --git a/gcc/d/dmd/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index 7fd47818759..11a51f10e99 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -647,7 +647,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 else
                     ti = dsym._init ? dsym._init.syntaxCopy() : null;
 
-                StorageClass storage_class = STC.temp | STC.local | dsym.storage_class;
+                StorageClass storage_class = STC.temp | dsym.storage_class;
                 if ((dsym.storage_class & STC.parameter) && (arg.storageClass & STC.parameter))
                     storage_class |= arg.storageClass;
                 auto v = new VarDeclaration(dsym.loc, arg.type, id, ti, storage_class);
@@ -656,15 +656,7 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
 
                 v.dsymbolSemantic(sc);
 
-                if (sc.scopesym)
-                {
-                    //printf("adding %s to %s\n", v.toChars(), sc.scopesym.toChars());
-                    if (sc.scopesym.members)
-                        // Note this prevents using foreach() over members, because the limits can change
-                        sc.scopesym.members.push(v);
-                }
-
-                Expression e = new DsymbolExp(dsym.loc, v);
+                Expression e = new VarExp(dsym.loc, v);
                 (*exps)[i] = e;
             }
             auto v2 = new TupleDeclaration(dsym.loc, dsym.ident, exps);
@@ -728,6 +720,11 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
             else if (!dsym.type.hasPointers())
             {
                 dsym.storage_class &= ~STC.scope_;     // silently ignore; may occur in generic code
+                // https://issues.dlang.org/show_bug.cgi?id=23168
+                if (dsym.storage_class & STC.returnScope)
+                {
+                    dsym.storage_class &= ~(STC.return_ | STC.returnScope);
+                }
             }
         }
 
@@ -3208,10 +3205,19 @@  private extern(C++) final class DsymbolSemanticVisitor : Visitor
                 sc.stc |= STC.scope_;
 
             // If 'this' has no pointers, remove 'scope' as it has no meaning
+            // Note: this is already covered by semantic of `VarDeclaration` and `TypeFunction`,
+            // but existing code relies on `hasPointers()` being called here to resolve forward references:
+            // https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573
             if (sc.stc & STC.scope_ && ad && ad.isStructDeclaration() && !ad.type.hasPointers())
             {
                 sc.stc &= ~STC.scope_;
                 tf.isScopeQual = false;
+                if (tf.isreturnscope)
+                {
+                    sc.stc &= ~(STC.return_ | STC.returnScope);
+                    tf.isreturn = false;
+                    tf.isreturnscope = false;
+                }
             }
 
             sc.linkage = funcdecl._linkage;
@@ -6840,7 +6846,12 @@  bool determineFields(AggregateDeclaration ad)
             return 1;
 
         if (v.aliassym)
-            return 0;   // If this variable was really a tuple, skip it.
+        {
+            // If this variable was really a tuple, process each element.
+            if (auto tup = v.aliassym.isTupleDeclaration())
+                return tup.foreachVar(tv => tv.apply(&func, ad));
+            return 0;
+        }
 
         if (v.storage_class & (STC.static_ | STC.extern_ | STC.tls | STC.gshared | STC.manifest | STC.ctfe | STC.templateparameter))
             return 0;
diff --git a/gcc/d/dmd/dtoh.d b/gcc/d/dmd/dtoh.d
index 9afcc7fe687..c570068f7d6 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -873,7 +873,11 @@  public:
         // Tuple field are expanded into multiple VarDeclarations
         // (we'll visit them later)
         if (vd.type && vd.type.isTypeTuple())
+        {
+            assert(vd.aliassym);
+            vd.toAlias().accept(this);
             return;
+        }
 
         if (vd.originalType && vd.type == AST.Type.tsize_t)
             origType = vd.originalType;
@@ -1263,41 +1267,38 @@  public:
             size_t varCount;
             bool first = true;
             buf.level++;
-            foreach (m; *sd.members)
+            foreach (vd; sd.fields)
             {
-                if (auto vd = m.isVarDeclaration())
-                {
-                    if (!memberField(vd))
-                        continue;
-                    varCount++;
+                if (!memberField(vd) || vd.overlapped)
+                    continue;
+                varCount++;
 
-                    if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct &&
-                        !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray)
-                    {
-                        continue;
-                    }
-                    if (vd._init && vd._init.isVoidInitializer())
-                        continue;
+                if (!vd._init && !vd.type.isTypeBasic() && !vd.type.isTypePointer && !vd.type.isTypeStruct &&
+                    !vd.type.isTypeClass && !vd.type.isTypeDArray && !vd.type.isTypeSArray)
+                {
+                    continue;
+                }
+                if (vd._init && vd._init.isVoidInitializer())
+                    continue;
 
-                    if (first)
-                    {
-                        buf.writestringln(" :");
-                        first = false;
-                    }
-                    else
-                    {
-                        buf.writestringln(",");
-                    }
-                    writeIdentifier(vd, true);
-                    buf.writeByte('(');
+                if (first)
+                {
+                    buf.writestringln(" :");
+                    first = false;
+                }
+                else
+                {
+                    buf.writestringln(",");
+                }
+                writeIdentifier(vd, true);
+                buf.writeByte('(');
 
-                    if (vd._init)
-                    {
-                        auto e = AST.initializerToExpression(vd._init);
-                        printExpressionFor(vd.type, e, true);
-                    }
-                    buf.printf(")");
+                if (vd._init)
+                {
+                    auto e = AST.initializerToExpression(vd._init);
+                    printExpressionFor(vd.type, e, true);
                 }
+                buf.printf(")");
             }
             buf.level--;
             buf.writenl();
@@ -1308,49 +1309,43 @@  public:
             {
                 buf.printf("%s(", sd.ident.toChars());
                 first = true;
-                foreach (m; *sd.members)
+                foreach (vd; sd.fields)
                 {
-                    if (auto vd = m.isVarDeclaration())
+                    if (!memberField(vd) || vd.overlapped)
+                        continue;
+                    if (!first)
+                        buf.writestring(", ");
+                    assert(vd.type);
+                    assert(vd.ident);
+                    typeToBuffer(vd.type, vd, true);
+                    // Don't print default value for first parameter to not clash
+                    // with the default ctor defined above
+                    if (!first)
                     {
-                        if (!memberField(vd))
-                            continue;
-                        if (!first)
-                            buf.writestring(", ");
-                        assert(vd.type);
-                        assert(vd.ident);
-                        typeToBuffer(vd.type, vd, true);
-                        // Don't print default value for first parameter to not clash
-                        // with the default ctor defined above
-                        if (!first)
-                        {
-                            buf.writestring(" = ");
-                            printExpressionFor(vd.type, findDefaultInitializer(vd));
-                        }
-                        first = false;
+                        buf.writestring(" = ");
+                        printExpressionFor(vd.type, findDefaultInitializer(vd));
                     }
+                    first = false;
                 }
                 buf.writestring(") :");
                 buf.level++;
                 buf.writenl();
 
                 first = true;
-                foreach (m; *sd.members)
+                foreach (vd; sd.fields)
                 {
-                    if (auto vd = m.isVarDeclaration())
-                    {
-                        if (!memberField(vd))
-                            continue;
-
-                        if (first)
-                            first = false;
-                        else
-                            buf.writestringln(",");
-
-                        writeIdentifier(vd, true);
-                        buf.writeByte('(');
-                        writeIdentifier(vd, true);
-                        buf.writeByte(')');
-                    }
+                    if (!memberField(vd) || vd.overlapped)
+                        continue;
+
+                    if (first)
+                        first = false;
+                    else
+                        buf.writestringln(",");
+
+                    writeIdentifier(vd, true);
+                    buf.writeByte('(');
+                    writeIdentifier(vd, true);
+                    buf.writeByte(')');
                 }
                 buf.writenl();
                 buf.writestringln("{}");
@@ -1663,6 +1658,13 @@  public:
         assert(false, "This node type should be handled in the EnumDeclaration");
     }
 
+    override void visit(AST.TupleDeclaration tup)
+    {
+        debug (Debug_DtoH) mixin(traceVisit!tup);
+
+        tup.foreachVar((s) { s.accept(this); });
+    }
+
     /**
      * Prints a member/parameter/variable declaration into `buf`.
      *
diff --git a/gcc/d/dmd/expression.d b/gcc/d/dmd/expression.d
index ceecf4b5e74..397a41b33b7 100644
--- a/gcc/d/dmd/expression.d
+++ b/gcc/d/dmd/expression.d
@@ -348,14 +348,16 @@  int expandAliasThisTuples(Expressions* exps, size_t starti = 0)
         if (TupleDeclaration td = exp.isAliasThisTuple)
         {
             exps.remove(u);
-            foreach (i, o; *td.objects)
+            size_t i;
+            td.foreachVar((s)
             {
-                auto d = o.isExpression().isDsymbolExp().s.isDeclaration();
+                auto d = s.isDeclaration();
                 auto e = new DotVarExp(exp.loc, exp, d);
                 assert(d.type);
                 e.type = d.type;
                 exps.insert(u + i, e);
-            }
+                ++i;
+            });
             version (none)
             {
                 printf("expansion ->\n");
diff --git a/gcc/d/dmd/expressionsem.d b/gcc/d/dmd/expressionsem.d
index dcc5b5095ed..99e003b1856 100644
--- a/gcc/d/dmd/expressionsem.d
+++ b/gcc/d/dmd/expressionsem.d
@@ -6004,10 +6004,10 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
         se = se.toUTF8(sc);
 
-        auto namez = se.toStringz().ptr;
+        auto namez = se.toStringz();
         if (!global.filePath)
         {
-            e.error("need `-J` switch to import text file `%s`", namez);
+            e.error("need `-J` switch to import text file `%s`", namez.ptr);
             return setError();
         }
 
@@ -6036,8 +6036,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
         }
 
-        auto name = FileName.searchPath(global.filePath, namez, false);
-        if (!name)
+        auto resolvedNamez = FileName.searchPath(global.filePath, namez, false);
+        if (!resolvedNamez)
         {
             e.error("file `%s` cannot be found or not in a path specified with `-J`", se.toChars());
             e.errorSupplemental("Path(s) searched (as provided by `-J`):");
@@ -6051,11 +6051,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             return setError();
         }
 
-        sc._module.contentImportedFiles.push(name);
+        sc._module.contentImportedFiles.push(resolvedNamez.ptr);
         if (global.params.verbose)
         {
             const slice = se.peekString();
-            message("file      %.*s\t(%s)", cast(int)slice.length, slice.ptr, name);
+            message("file      %.*s\t(%s)", cast(int)slice.length, slice.ptr, resolvedNamez.ptr);
         }
         if (global.params.moduleDeps.buffer !is null)
         {
@@ -6072,27 +6072,27 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
                 ob.writestring("string : ");
             ob.write(se.peekString());
             ob.writestring(" (");
-            escapePath(ob, name);
+            escapePath(ob, resolvedNamez.ptr);
             ob.writestring(")");
             ob.writenl();
         }
         if (global.params.makeDeps.doOutput)
         {
-            global.params.makeDeps.files.push(name);
+            global.params.makeDeps.files.push(resolvedNamez.ptr);
         }
 
         {
-            auto fileName = FileName(name.toDString);
+            auto fileName = FileName(resolvedNamez);
             if (auto fmResult = global.fileManager.lookup(fileName))
             {
                 se = new StringExp(e.loc, fmResult);
             }
             else
             {
-                auto readResult = File.read(name.toDString);
+                auto readResult = File.read(resolvedNamez);
                 if (!readResult.success)
                 {
-                    e.error("cannot read file `%s`", name);
+                    e.error("cannot read file `%s`", resolvedNamez.ptr);
                     return setError();
                 }
                 else
@@ -6963,18 +6963,8 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             exp.error("cannot take address of `%s`", exp.e1.toChars());
             return setError();
         }
-        if (auto dve = exp.e1.isDotVarExp())
-        {
-            /* https://issues.dlang.org/show_bug.cgi?id=22749
-             * Error about taking address of any bit-field, regardless of
-             * whether SCOPE.Cfile is set.
-             */
-            if (auto bf = dve.var.isBitFieldDeclaration())
-            {
-                exp.error("cannot take address of bit-field `%s`", bf.toChars());
-                return setError();
-            }
-        }
+        if (!checkAddressable(exp, sc))
+            return setError();
 
         bool hasOverloads;
         if (auto f = isFuncAddress(exp, &hasOverloads))
@@ -8323,6 +8313,11 @@  private extern (C++) final class ExpressionSemanticVisitor : Visitor
             t1b = t1b.castMod(tv1.mod);
             exp.e1.type = t1b;
         }
+        if (t1b.ty == Tsarray || t1b.ty == Tarray)
+        {
+            if (!checkAddressable(exp, sc))
+                return setError();
+        }
 
         /* Run semantic on e2
          */
@@ -13152,6 +13147,69 @@  bool checkAddressVar(Scope* sc, Expression exp, VarDeclaration v)
     return true;
 }
 
+/**************************************
+ * This check ensures that the object in `exp` can have its address taken, or
+ * issue a diagnostic error.
+ * Params:
+ *      e = expression to check
+ *      sc = context
+ * Returns:
+ *      true if the expression is addressable
+ */
+bool checkAddressable(Expression e, Scope* sc)
+{
+    Expression ex = e;
+    while (true)
+    {
+        switch (ex.op)
+        {
+            case EXP.dotVariable:
+                // https://issues.dlang.org/show_bug.cgi?id=22749
+                // Error about taking address of any bit-field, regardless of
+                // whether SCOPE.Cfile is set.
+                if (auto bf = ex.isDotVarExp().var.isBitFieldDeclaration())
+                {
+                    e.error("cannot take address of bit-field `%s`", bf.toChars());
+                    return false;
+                }
+                goto case EXP.cast_;
+
+            case EXP.index:
+                ex = ex.isBinExp().e1;
+                continue;
+
+            case EXP.address:
+            case EXP.array:
+            case EXP.cast_:
+                ex = ex.isUnaExp().e1;
+                continue;
+
+            case EXP.variable:
+                if (sc.flags & SCOPE.Cfile)
+                {
+                    // C11 6.5.3.2: A variable that has its address taken cannot be
+                    // stored in a register.
+                    // C11 6.3.2.1: An array that has its address computed with `[]`
+                    // or cast to an lvalue pointer cannot be stored in a register.
+                    if (ex.isVarExp().var.storage_class & STC.register)
+                    {
+                        if (e.isIndexExp())
+                            e.error("cannot index through register variable `%s`", ex.toChars());
+                        else
+                            e.error("cannot take address of register variable `%s`", ex.toChars());
+                        return false;
+                    }
+                }
+                break;
+
+            default:
+                break;
+        }
+        break;
+    }
+    return true;
+}
+
 
 /*******************************
  * Checks the attributes of a function.
diff --git a/gcc/d/dmd/foreachvar.d b/gcc/d/dmd/foreachvar.d
index 53ed62efd70..63281b5760c 100644
--- a/gcc/d/dmd/foreachvar.d
+++ b/gcc/d/dmd/foreachvar.d
@@ -75,19 +75,7 @@  void foreachVar(Expression e, void delegate(VarDeclaration) dgVar)
             if (!v)
                 return;
             if (TupleDeclaration td = v.toAlias().isTupleDeclaration())
-            {
-                if (!td.objects)
-                    return;
-                foreach (o; *td.objects)
-                {
-                    Expression ex = isExpression(o);
-                    DsymbolExp s = ex ? ex.isDsymbolExp() : null;
-                    assert(s);
-                    VarDeclaration v2 = s.s.isVarDeclaration();
-                    assert(v2);
-                    dgVar(v2);
-                }
-            }
+                td.foreachVar((s) { dgVar(s.isVarDeclaration()); });
             else
                 dgVar(v);
             Dsymbol s = v.toAlias();
diff --git a/gcc/d/dmd/importc.d b/gcc/d/dmd/importc.d
index bcfbd9a122c..afec5ef1ead 100644
--- a/gcc/d/dmd/importc.d
+++ b/gcc/d/dmd/importc.d
@@ -81,10 +81,14 @@  Expression arrayFuncConv(Expression e, Scope* sc)
     auto t = e.type.toBasetype();
     if (auto ta = t.isTypeDArray())
     {
+        if (!checkAddressable(e, sc))
+            return ErrorExp.get();
         e = e.castTo(sc, ta.next.pointerTo());
     }
     else if (auto ts = t.isTypeSArray())
     {
+        if (!checkAddressable(e, sc))
+            return ErrorExp.get();
         e = e.castTo(sc, ts.next.pointerTo());
     }
     else if (t.isTypeFunction())
diff --git a/gcc/d/dmd/ob.d b/gcc/d/dmd/ob.d
index 121a266b428..5ff73c983f0 100644
--- a/gcc/d/dmd/ob.d
+++ b/gcc/d/dmd/ob.d
@@ -1407,16 +1407,7 @@  void genKill(ref ObState obstate, ObNode* ob)
                     }
                     else if (auto td = s.isTupleDeclaration())
                     {
-                        foreach (o; *td.objects)
-                        {
-                            if (auto eo = o.isExpression())
-                            {
-                                if (auto se = eo.isDsymbolExp())
-                                {
-                                    Dsymbol_visit(se.s);
-                                }
-                            }
-                        }
+                        td.foreachVar(&Dsymbol_visit);
                     }
                 }
 
@@ -2107,16 +2098,7 @@  void checkObErrors(ref ObState obstate)
                     }
                     else if (auto td = s.isTupleDeclaration())
                     {
-                        foreach (o; *td.objects)
-                        {
-                            if (auto eo = o.isExpression())
-                            {
-                                if (auto se = eo.isDsymbolExp())
-                                {
-                                    Dsymbol_visit(se.s);
-                                }
-                            }
-                        }
+                        td.foreachVar(&Dsymbol_visit);
                     }
                 }
 
diff --git a/gcc/d/dmd/parse.d b/gcc/d/dmd/parse.d
index eb5e6942948..4e3fd533c18 100644
--- a/gcc/d/dmd/parse.d
+++ b/gcc/d/dmd/parse.d
@@ -5877,7 +5877,8 @@  LagainStc:
             {
                 if (isDeclaration(&token, NeedDeclaratorId.mustIfDstyle, TOK.reserved, null))
                     goto Ldeclaration;
-                if (peekNext() == TOK.leftParenthesis)
+                const tv = peekNext();
+                if (tv == TOK.leftParenthesis)
                 {
                     // mixin(string)
                     AST.Expression e = parseAssignExp();
@@ -5893,6 +5894,14 @@  LagainStc:
                     }
                     break;
                 }
+                else if (tv == TOK.template_)
+                {
+                    // mixin template
+                    nextToken();
+                    AST.Dsymbol d = parseTemplateDeclaration(true);
+                    s = new AST.ExpStatement(loc, d);
+                    break;
+                }
                 AST.Dsymbol d = parseMixin();
                 s = new AST.ExpStatement(loc, d);
                 if (flags & ParseStatementFlags.scope_)
diff --git a/gcc/d/dmd/root/filename.d b/gcc/d/dmd/root/filename.d
index 3b7b75b0aff..226141d4608 100644
--- a/gcc/d/dmd/root/filename.d
+++ b/gcc/d/dmd/root/filename.d
@@ -734,16 +734,15 @@  nothrow:
      * Returns:
      *  index of the first reserved character in path if found, size_t.max otherwise
      */
-    extern (D) static size_t findReservedChar(const(char)* name) pure @nogc
+    extern (D) static size_t findReservedChar(const(char)[] name) pure @nogc @safe
     {
         version (Windows)
         {
-            size_t idx = 0;
             // According to https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file#naming-conventions
             // the following characters are not allowed in path: < > : " | ? *
-            for (const(char)* p = name; *p; p++, idx++)
+            foreach (idx; 0 .. name.length)
             {
-                char c = *p;
+                char c = name[idx];
                 if (c == '<' || c == '>' || c == ':' || c == '"' || c == '|' || c == '?' || c == '*')
                 {
                     return idx;
@@ -784,21 +783,21 @@  nothrow:
      * Returns:
      *  true if path contains '..' reference to parent directory
      */
-    extern (D) static bool refersToParentDir(const(char)* name) pure @nogc
+    extern (D) static bool refersToParentDir(const(char)[] name) pure @nogc @safe
     {
-        if (name[0] == '.' && name[1] == '.' && (!name[2] || isDirSeparator(name[2])))
+        size_t s = 0;
+        foreach (i; 0 .. name.length)
         {
-            return true;
-        }
-
-        for (const(char)* p = name; *p; p++)
-        {
-            char c = *p;
-            if (isDirSeparator(c) && p[1] == '.' && p[2] == '.' && (!p[3] || isDirSeparator(p[3])))
+            if (isDirSeparator(name[i]))
             {
-                return true;
+                if (name[s..i] == "..")
+                    return true;
+                s = i + 1;
             }
         }
+        if (name[s..$] == "..")
+            return true;
+
         return false;
     }
     unittest
diff --git a/gcc/d/dmd/semantic2.d b/gcc/d/dmd/semantic2.d
index 73dcaa6c960..bf18a2140fb 100644
--- a/gcc/d/dmd/semantic2.d
+++ b/gcc/d/dmd/semantic2.d
@@ -677,6 +677,11 @@  private extern(C++) final class Semantic2Visitor : Visitor
     {
         visit(cast(AggregateDeclaration) cd);
     }
+
+    override void visit(TupleDeclaration td)
+    {
+        td.foreachVar((s) { s.accept(this); });
+    }
 }
 
 /**
diff --git a/gcc/d/dmd/semantic3.d b/gcc/d/dmd/semantic3.d
index a056c99b11e..c5d7667fefc 100644
--- a/gcc/d/dmd/semantic3.d
+++ b/gcc/d/dmd/semantic3.d
@@ -483,7 +483,7 @@  private extern(C++) final class Semantic3Visitor : Visitor
                     if ((funcdecl.flags & FUNCFLAG.inferScope) && !(fparam.storageClass & STC.scope_))
                         stc |= STC.maybescope;
 
-                    stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope);
+                    stc |= fparam.storageClass & (STC.IOR | STC.return_ | STC.scope_ | STC.lazy_ | STC.final_ | STC.TYPECTOR | STC.nodtor | STC.returnScope | STC.register);
                     v.storage_class = stc;
                     v.dsymbolSemantic(sc2);
                     if (!sc2.insert(v))
diff --git a/gcc/d/types.cc b/gcc/d/types.cc
index b706c91560e..38cc7f5111c 100644
--- a/gcc/d/types.cc
+++ b/gcc/d/types.cc
@@ -392,10 +392,10 @@  layout_aggregate_members (Dsymbols *members, tree context, bool inherited_p)
 		  RootObject *ro = (*td->objects)[j];
 		  gcc_assert (ro->dyncast () == DYNCAST_EXPRESSION);
 		  Expression *e = (Expression *) ro;
-		  gcc_assert (e->op == EXP::dSymbol);
-		  DsymbolExp *se = e->isDsymbolExp ();
+		  gcc_assert (e->op == EXP::variable);
+		  VarExp *ve = e->isVarExp ();
 
-		  tmembers.push (se->s);
+		  tmembers.push (ve->var);
 		}
 
 	      fields += layout_aggregate_members (&tmembers, context,
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
index 20134f5b449..a4c6ce4ce2c 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_AnonDeclaration.d
@@ -61,9 +61,21 @@  struct S final
         int32_t innerPrivate;
         int32_t innerBar;
     };
-    S()
+    S() :
+        y(),
+        z(),
+        outerPrivate(),
+        innerPrivate(),
+        innerBar()
     {
     }
+    S(int32_t y, double z = NAN, int32_t outerPrivate = 0, int32_t innerPrivate = 0, int32_t innerBar = 0) :
+        y(y),
+        z(z),
+        outerPrivate(outerPrivate),
+        innerPrivate(innerPrivate),
+        innerBar(innerBar)
+        {}
 };
 
 extern void foo();
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
index 8c7ba9be672..2e36c7d02be 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_StructDeclaration.d
@@ -173,12 +173,16 @@  struct A final
 
     A() :
         a(),
-        s()
+        s(),
+        x(),
+        y()
     {
     }
-    A(int32_t a, S s = S()) :
+    A(int32_t a, S s = S(), int32_t x = 0, int32_t y = 0) :
         a(a),
-        s(s)
+        s(s),
+        x(x),
+        y(y)
         {}
 };
 
@@ -196,11 +200,13 @@  private:
     char smallarray[1$?:32=u|64=LLU$];
 public:
     Array() :
-        length()
+        length(),
+        data()
     {
     }
-    Array(uint32_t length) :
-        length(length)
+    Array(uint32_t length, _d_dynamicArray< char > data = {}) :
+        length(length),
+        data(data)
         {}
 };
 
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
index 1e2be909e75..1ed63180dda 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_TemplateDeclaration.d
@@ -219,9 +219,13 @@  struct ImportedBuffer final
 {
     typedef ActualBuffer Buffer;
     ActualBuffer buffer2;
-    ImportedBuffer()
+    ImportedBuffer() :
+        buffer2()
     {
     }
+    ImportedBuffer(ActualBuffer buffer2) :
+        buffer2(buffer2)
+        {}
 };
 ---
 */
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d
index 10967c83137..fda9efa5d34 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_mangling.d
@@ -64,9 +64,15 @@  struct HasMangleMember final
     int32_t someAttrC;
     int32_t someAttrCpp;
     void hasDefaultVar(int32_t i = someAttrC);
-    HasMangleMember()
+    HasMangleMember() :
+        someAttrC(),
+        someAttrCpp()
     {
     }
+    HasMangleMember(int32_t someAttrC, int32_t someAttrCpp = 0) :
+        someAttrC(someAttrC),
+        someAttrCpp(someAttrCpp)
+        {}
 };
 
 extern "C" void hasDefaultVar(int32_t i = someVarC);
diff --git a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d
index 3fd54c7de74..dc07c7b8f8b 100644
--- a/gcc/testsuite/gdc.test/compilable/dtoh_protection.d
+++ b/gcc/testsuite/gdc.test/compilable/dtoh_protection.d
@@ -50,9 +50,21 @@  protected:
 private:
     int32_t e;
 public:
-    S1()
+    S1() :
+        a(),
+        b(),
+        c(),
+        d(),
+        e()
     {
     }
+    S1(int32_t a, int32_t b = 0, int32_t c = 0, int32_t d = 0, int32_t e = 0) :
+        a(a),
+        b(b),
+        c(c),
+        d(d),
+        e(e)
+        {}
 };
 
 class S2 final
@@ -102,10 +114,12 @@  public:
     public:
         int32_t publicInner;
         PublicInnerStruct() :
+            privateInner(),
             publicInner()
         {
         }
-        PublicInnerStruct(int32_t publicInner) :
+        PublicInnerStruct(int32_t privateInner, int32_t publicInner = 0) :
+            privateInner(privateInner),
             publicInner(publicInner)
             {}
     };
@@ -118,10 +132,12 @@  private:
     public:
         int32_t publicInner;
         PrivateInnerClass() :
+            privateInner(),
             publicInner()
         {
         }
-        PrivateInnerClass(int32_t publicInner) :
+        PrivateInnerClass(int32_t privateInner, int32_t publicInner = 0) :
+            privateInner(privateInner),
             publicInner(publicInner)
             {}
     };
@@ -142,9 +158,13 @@  private:
 
 public:
     typedef PrivateInnerEnum PublicAlias;
-    Outer()
+    Outer() :
+        privateOuter()
     {
     }
+    Outer(int32_t privateOuter) :
+        privateOuter(privateOuter)
+        {}
 };
 ---
 */
diff --git a/gcc/testsuite/gdc.test/compilable/test23168.d b/gcc/testsuite/gdc.test/compilable/test23168.d
new file mode 100644
index 00000000000..61a4ff3b6dc
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23168.d
@@ -0,0 +1,30 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=23168
+// Issue 23168 - [DIP1000] return scope wrongly rewritten for structs with no indirections
+
+@safe:
+struct Ptr
+{
+    int* fun() return scope { return null; }
+}
+
+int* funf(ref return scope Ptr p) { return null; }
+
+int* use()
+{
+    Ptr ptr;
+    return ptr.fun;
+    return funf(ptr);
+}
+
+// Prevent forward reference 'regression'
+// See https://github.com/dlang/dmd/pull/14232#issuecomment-1162906573
+struct S
+{
+    void f() scope {}
+    alias x = _get_value;
+
+    static if (true)
+        int _get_value() {return 3;}
+    else
+        int _get_value() {return 4;}
+}
diff --git a/gcc/testsuite/gdc.test/compilable/test23169.d b/gcc/testsuite/gdc.test/compilable/test23169.d
new file mode 100644
index 00000000000..6237661a923
--- /dev/null
+++ b/gcc/testsuite/gdc.test/compilable/test23169.d
@@ -0,0 +1,14 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=23169
+// Issue 23169 - [DIP1000] Mangling does not distinguish return and return scope
+
+struct Ptr
+{
+	int* impl;
+	void* fun0() return scope {return impl;}
+	void* fun1() scope return {return impl;}
+	void* fun2() return {return &this;}
+}
+
+static assert(Ptr.fun0.mangleof == "_D9test231693Ptr4fun0MFNjNlZPv");
+static assert(Ptr.fun1.mangleof == "_D9test231693Ptr4fun1MFNlNjZPv");
+static assert(Ptr.fun2.mangleof == "_D9test231693Ptr4fun2MFNjZPv");
diff --git a/gcc/testsuite/gdc.test/compilable/testparse.d b/gcc/testsuite/gdc.test/compilable/testparse.d
index 99378a9df53..cef1575e901 100644
--- a/gcc/testsuite/gdc.test/compilable/testparse.d
+++ b/gcc/testsuite/gdc.test/compilable/testparse.d
@@ -191,3 +191,13 @@  void test22019()
             break;
     }
 }
+
+/***************************************************/
+// https://issues.dlang.org/show_bug.cgi?id=23205
+
+void test23205()
+{
+    mixin template tpl() { int x; }
+    mixin tpl!();
+    x = 123;
+}
diff --git a/gcc/testsuite/gdc.test/runnable/test23010.d b/gcc/testsuite/gdc.test/runnable/test23010.d
new file mode 100644
index 00000000000..1cbacfc9279
--- /dev/null
+++ b/gcc/testsuite/gdc.test/runnable/test23010.d
@@ -0,0 +1,43 @@ 
+// https://issues.dlang.org/show_bug.cgi?id=23010
+
+alias AliasSeq(T...) = T;
+
+mixin template faz() {
+    alias T = AliasSeq!(int);
+    T bar = 12345;
+
+    void write1() {
+        assert(bar[0] == 12345);
+    }
+
+    AliasSeq!(string, float) foo = AliasSeq!("qwerty", 1.25f);
+
+    void write2() {
+        assert(foo == AliasSeq!("qwerty", 1.25f));
+        foo = AliasSeq!("asdfg", 2.5f); // this even crashed before
+        assert(foo == AliasSeq!("asdfg", 2.5f));
+    }
+}
+
+void main() {
+    mixin faz!();
+    write1;
+    write2;
+    fun;
+}
+
+// Testing static symbol generation ('toobj.d' changes)
+
+static AliasSeq!(int, string) tup;
+
+void fun()
+{
+    auto v = tup;
+
+    struct S(T...) {
+        static T b;
+    }
+
+    alias T = S!(int, float);
+    auto p = T.b;
+}
diff --git a/libphobos/libdruntime/MERGE b/libphobos/libdruntime/MERGE
index 3f4a0ec63e3..2fc1bc1cf6a 100644
--- a/libphobos/libdruntime/MERGE
+++ b/libphobos/libdruntime/MERGE
@@ -1,4 +1,4 @@ 
-e150cca179515ce5113e828aac94c20c0b983b7c
+148608b7935c3f9a4ea3a26f74cb90cd07efc91c
 
 The first line of this file holds the git revision number of the last
 merge done from the dlang/druntime repository.