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/declaration.d b/gcc/d/dmd/declaration.d
index 7b50c050487..6c83c196f72 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 DsymbolExp (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 se = e.isDsymbolExp())
+                    dg(se.s);
         }
-        return false;
+    }
+
+    /***********************************************************
+     * Calls dg(Dsymbol) for each Dsymbol, which should be a VarDeclaration
+     * inside DsymbolExp (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 se = e.isDsymbolExp())
+                    if(auto ret = dg(se.s))
+                        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 e96f1806982..485b2dec1a1 100644
--- a/gcc/d/dmd/dinterpret.d
+++ b/gcc/d/dmd/dinterpret.d
@@ -2291,16 +2291,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)
@@ -2310,7 +2306,7 @@ public:
                         {
                             einit = interpretRegion(ie.exp, istate, goal);
                             if (exceptionOrCant(einit))
-                                return;
+                                return 1;
                         }
                         else if (v2._init.isVoidInitializer())
                         {
@@ -2320,11 +2316,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/dsymbolsem.d b/gcc/d/dmd/dsymbolsem.d
index c5766787bf0..dfaaff93d35 100644
--- a/gcc/d/dmd/dsymbolsem.d
+++ b/gcc/d/dmd/dsymbolsem.d
@@ -650,7 +650,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);
@@ -659,14 +659,6 @@ 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);
                 (*exps)[i] = e;
             }
@@ -6819,7 +6811,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 17abb7d3b00..ecc637eff53 100644
--- a/gcc/d/dmd/dtoh.d
+++ b/gcc/d/dmd/dtoh.d
@@ -877,7 +877,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;
@@ -1667,6 +1671,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 107e85b0793..832ab7dda37 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/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/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/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/testsuite/gdc.dg/pr110959.d b/gcc/testsuite/gdc.dg/pr110959.d
new file mode 100644
index 00000000000..b1da90fad83
--- /dev/null
+++ b/gcc/testsuite/gdc.dg/pr110959.d
@@ -0,0 +1,32 @@
+// https://gcc.gnu.org/bugzilla/show_bug.cgi?id=110959
+// { dg-do compile }
+class ArsdExceptionBase : object.Exception {
+    this(string operation, string file = __FILE__, size_t line = __LINE__, Throwable next = null) {
+        super(operation, file, line, next);
+    }
+}
+
+template ArsdException(alias Type, DataTuple...) {
+    static if(DataTuple.length)
+        alias Parent = ArsdException!(Type, DataTuple[0 .. $-1]);
+    else
+        alias Parent = ArsdExceptionBase;
+
+    class ArsdException : Parent {
+        DataTuple data;
+
+        this(DataTuple data, string file = __FILE__, size_t line = __LINE__) {
+            this.data = data;
+            static if(is(Parent == ArsdExceptionBase))
+                super(null, file, line);
+            else
+                super(data[0 .. $-1], file, line);
+        }
+
+        static opCall(R...)(R r, string file = __FILE__, size_t line = __LINE__) {
+            return new ArsdException!(Type, DataTuple, R)(r, file, line);
+        }
+    }
+}
+
+__gshared pr110959 = ArsdException!"Test"(4, "four");
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;
+}
