From 237f58885fb230499a800ba592f02c33abfd58b3 Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Mon, 23 Feb 2026 05:26:43 +0000 Subject: [PATCH 1/4] Refactor: Extract combine and extractLast to expressionsem As part of the 'Separate Semantic Routines' project, this extracts the AST-mutating static methods `combine` and `extractLast` from the `Expression` class in `expression.d` and moves them to `expressionsem.d` as free functions. Also adds the appropriate D-to-C++ wrappers in `cxxfrontend.d` under the dmd namespace to maintain compatibility for GDC/LDC consumers. --- compiler/src/dmd/clone.d | 14 +-- compiler/src/dmd/cxxfrontend.d | 24 +++++ compiler/src/dmd/dcast.d | 4 +- compiler/src/dmd/dsymbolsem.d | 4 +- compiler/src/dmd/expression.d | 64 ------------- compiler/src/dmd/expressionsem.d | 154 ++++++++++++++++++++++--------- compiler/src/dmd/inline.d | 32 +++---- compiler/src/dmd/opover.d | 16 ++-- compiler/src/dmd/optimize.d | 2 +- compiler/src/dmd/semantic3.d | 2 +- compiler/src/dmd/sideeffect.d | 2 +- compiler/src/dmd/statementsem.d | 8 +- 12 files changed, 175 insertions(+), 151 deletions(-) diff --git a/compiler/src/dmd/clone.d b/compiler/src/dmd/clone.d index 610dd756ec62..b3d716558741 100644 --- a/compiler/src/dmd/clone.d +++ b/compiler/src/dmd/clone.d @@ -342,7 +342,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) e4 = new BlitExp(loc, new IdentifierExp(loc, Id.p), new VarExp(loc, swap)); } - e = Expression.combine(e1, e2, e3, e4); + e = combine(e1, e2, e3, e4); } /* postblit was called when the value was passed to opAssign, we just need to blit the result */ else if (sd.postblit) @@ -367,7 +367,7 @@ FuncDeclaration buildOpAssign(StructDeclaration sd, Scope* sc) auto ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v), new DotVarExp(loc, new IdentifierExp(loc, Id.p), v)); - e = Expression.combine(e, ec); + e = combine(e, ec); } } if (e) @@ -991,7 +991,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) ex = new CallExp(loc, new IdentifierExp(loc, Id.__ArrayDtor), se); } - e = Expression.combine(ex, e); // combine in reverse order + e = combine(ex, e); // combine in reverse order } if (e || (stc & STC.disable)) @@ -1051,7 +1051,7 @@ void buildDtors(AggregateDeclaration ad, Scope* sc) ex = new DotVarExp(loc, ex, fd, false); CallExp ce = new CallExp(loc, ex); ce.directcall = true; - e = Expression.combine(e, ce); + e = combine(e, ce); } auto dd = new DtorDeclaration(declLoc, Loc.initial, stc, Id.__aggrDtor); dd.isGenerated = true; @@ -1248,7 +1248,7 @@ FuncDeclaration buildInv(AggregateDeclaration ad, Scope* sc) break; } } - e = Expression.combine(e, new CallExp(Loc.initial, new VarExp(Loc.initial, inv, false))); + e = combine(e, new CallExp(Loc.initial, new VarExp(Loc.initial, inv, false))); } auto inv = new InvariantDeclaration(ad.loc, Loc.initial, stc | stcx, Id.classInvariant, new ExpStatement(Loc.initial, e)); @@ -1501,7 +1501,7 @@ FuncDeclaration buildPostBlit(StructDeclaration sd, Scope* sc) Expression ex = new ThisExp(loc); ex = new DotVarExp(loc, ex, fd, false); ex = new CallExp(loc, ex); - e = Expression.combine(e, ex); + e = combine(e, ex); } checkShared(); @@ -1606,7 +1606,7 @@ private Statement generateCtorBody(StructDeclaration sd, bool move) auto ec = new AssignExp(loc, new DotVarExp(loc, new ThisExp(loc), v), rhs); - e = Expression.combine(e, ec); + e = combine(e, ec); //printf("e.toChars = %s\n", e.toChars()); } Statement s1 = new ExpStatement(loc, e); diff --git a/compiler/src/dmd/cxxfrontend.d b/compiler/src/dmd/cxxfrontend.d index b4524a465bcf..19fe5f9de550 100644 --- a/compiler/src/dmd/cxxfrontend.d +++ b/compiler/src/dmd/cxxfrontend.d @@ -393,6 +393,30 @@ Expression getDefaultValue(EnumDeclaration ed, Loc loc) * expressionsem.d */ +Expression combine(Expression e1, Expression e2) +{ + import dmd.expressionsem; + return dmd.expressionsem.combine(e1, e2); +} + +Expression combine(Expression e1, Expression e2, Expression e3) +{ + import dmd.expressionsem; + return dmd.expressionsem.combine(e1, e2, e3); +} + +Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) +{ + import dmd.expressionsem; + return dmd.expressionsem.combine(e1, e2, e3, e4); +} + +Expression extractLast(Expression e, out Expression e0) +{ + import dmd.expressionsem; + return dmd.expressionsem.extractLast(e, e0); +} + void expandTuples(Expressions* exps, ArgumentLabels* names = null) { import dmd.expressionsem; diff --git a/compiler/src/dmd/dcast.d b/compiler/src/dmd/dcast.d index fdc29094aa0e..a52a31bc0191 100644 --- a/compiler/src/dmd/dcast.d +++ b/compiler/src/dmd/dcast.d @@ -3181,7 +3181,7 @@ Expression castTo(Expression e, Scope* sc, Type t, Type att = null) } auto ini = t.defaultInitLiteral(e.loc); - return Expression.combine(e, ini); + return combine(e, ini); } switch (e.op) @@ -4593,5 +4593,5 @@ IntRange getIntRange(Expression e) */ Expression specialNoreturnCast(Expression toBeCasted, Type to) { - return Expression.combine(toBeCasted, to.defaultInitLiteral(toBeCasted.loc)); + return combine(toBeCasted, to.defaultInitLiteral(toBeCasted.loc)); } diff --git a/compiler/src/dmd/dsymbolsem.d b/compiler/src/dmd/dsymbolsem.d index 3e372b58e996..f938af20aaf3 100644 --- a/compiler/src/dmd/dsymbolsem.d +++ b/compiler/src/dmd/dsymbolsem.d @@ -2397,7 +2397,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor iexps.remove(pos); iexps.insert(pos, te.exps); - (*iexps)[pos] = Expression.combine(te.e0, (*iexps)[pos]); + (*iexps)[pos] = combine(te.e0, (*iexps)[pos]); goto Lexpand1; } else if (isAliasThisTuple(e)) @@ -2479,7 +2479,7 @@ private extern(C++) final class DsymbolSemanticVisitor : Visitor { einit = (*te.exps)[i]; if (i == 0) - einit = Expression.combine(te.e0, einit); + einit = combine(te.e0, einit); } // Use the original initializer location, not the tuple element's location, // so error messages point to the declaration site diff --git a/compiler/src/dmd/expression.d b/compiler/src/dmd/expression.d index f5fbf805de17..d0323ad13a67 100644 --- a/compiler/src/dmd/expression.d +++ b/compiler/src/dmd/expression.d @@ -215,70 +215,6 @@ extern (C++) abstract class Expression : ASTNode return .toChars(this); } - /********************************** - * Combine e1 and e2 by CommaExp if both are not NULL. - */ - extern (D) static Expression combine(Expression e1, Expression e2) @safe - { - if (e1) - { - if (e2) - { - e1 = new CommaExp(e1.loc, e1, e2); - e1.type = e2.type; - } - } - else - e1 = e2; - return e1; - } - - extern (D) static Expression combine(Expression e1, Expression e2, Expression e3) @safe - { - return combine(combine(e1, e2), e3); - } - - extern (D) static Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) @safe - { - return combine(combine(e1, e2), combine(e3, e4)); - } - - /********************************** - * If 'e' is a tree of commas, returns the rightmost expression - * by stripping off it from the tree. The remained part of the tree - * is returned via e0. - * Otherwise 'e' is directly returned and e0 is set to NULL. - */ - extern (D) static Expression extractLast(Expression e, out Expression e0) @trusted - { - if (e.op != EXP.comma) - { - return e; - } - - CommaExp ce = cast(CommaExp)e; - if (ce.e2.op != EXP.comma) - { - e0 = ce.e1; - return ce.e2; - } - else - { - e0 = e; - - Expression* pce = &ce.e2; - while ((cast(CommaExp)(*pce)).e2.op == EXP.comma) - { - pce = &(cast(CommaExp)(*pce)).e2; - } - assert((*pce).op == EXP.comma); - ce = cast(CommaExp)(*pce); - *pce = ce.e1; - - return ce.e2; - } - } - extern (D) static Expressions* arraySyntaxCopy(Expressions* exps) { Expressions* a = null; diff --git a/compiler/src/dmd/expressionsem.d b/compiler/src/dmd/expressionsem.d index 3dec8c5e7490..86987e49f7d2 100644 --- a/compiler/src/dmd/expressionsem.d +++ b/compiler/src/dmd/expressionsem.d @@ -100,6 +100,70 @@ import dmd.visitor.postorder; enum LOGSEMANTIC = false; +/********************************** + * Combine e1 and e2 by CommaExp if both are not NULL. + */ +extern (D) Expression combine(Expression e1, Expression e2) @safe +{ + if (e1) + { + if (e2) + { + e1 = new CommaExp(e1.loc, e1, e2); + e1.type = e2.type; + } + } + else + e1 = e2; + return e1; +} + +extern (D) Expression combine(Expression e1, Expression e2, Expression e3) @safe +{ + return combine(combine(e1, e2), e3); +} + +extern (D) Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) @safe +{ + return combine(combine(e1, e2), combine(e3, e4)); +} + +/********************************** + * If 'e' is a tree of commas, returns the rightmost expression + * by stripping off it from the tree. The remained part of the tree + * is returned via e0. + * Otherwise 'e' is directly returned and e0 is set to NULL. + */ +extern (D) Expression extractLast(Expression e, out Expression e0) @trusted +{ + if (e.op != EXP.comma) + { + return e; + } + + CommaExp ce = cast(CommaExp)e; + if (ce.e2.op != EXP.comma) + { + e0 = ce.e1; + return ce.e2; + } + else + { + e0 = e; + + Expression* pce = &ce.e2; + while ((cast(CommaExp)(*pce)).e2.op == EXP.comma) + { + pce = &(cast(CommaExp)(*pce)).e2; + } + assert((*pce).op == EXP.comma); + ce = cast(CommaExp)(*pce); + *pce = ce.e1; + + return ce.e2; + } +} + /******************************* * Merge results of `ctorflow` into `_this`. * Params: @@ -282,7 +346,7 @@ VarDeclaration expToVariable(Expression e, out int deref) // Temporaries for rvalues that need destruction // are of form: (T s = rvalue, s). For these cases // we can just return var declaration of `s`. However, - // this is intentionally not calling `Expression.extractLast` + // this is intentionally not calling `extractLast` // because at this point we cannot infer the var declaration // of more complex generated comma expressions such as the // one for the array append hook. @@ -409,7 +473,7 @@ void expandTuples(Expressions* exps, ArgumentLabels* names = null) expandNames(i, te.exps.length); if (i == exps.length) return; // empty tuple, no more arguments - (*exps)[i] = Expression.combine(te.e0, (*exps)[i]); + (*exps)[i] = combine(te.e0, (*exps)[i]); arg = (*exps)[i]; } } @@ -1623,7 +1687,7 @@ private Expression checkOpAssignTypes(BinExp binExp, Scope* sc) private Expression extractOpDollarSideEffect(Scope* sc, UnaExp ue) { Expression e0; - Expression e1 = Expression.extractLast(ue.e1, e0); + Expression e1 = extractLast(ue.e1, e0); // https://issues.dlang.org/show_bug.cgi?id=12585 // Extract the side effect part if ue.e1 is comma. @@ -1782,7 +1846,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, out Expression pe0) // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); - pe0 = Expression.combine(pe0, de); + pe0 = combine(pe0, de); } sc = sc.pop(); @@ -1863,7 +1927,7 @@ Expression resolveOpDollar(Scope* sc, ArrayExp ae, IntervalExp ie, ref Expressio // If $ was used, declare it now Expression de = new DeclarationExp(ae.loc, ae.lengthVar); de = de.expressionSemantic(sc); - pe0 = Expression.combine(pe0, de); + pe0 = combine(pe0, de); } sc = sc.pop(); @@ -1941,7 +2005,7 @@ extern (D) Expression doCopyOrMove(Scope* sc, Expression e, Type t, bool nrvo, b er = new DotIdExp(e.loc, ve, Id.ctor); // ve.ctor er = new CallExp(e.loc, er, e); // ve.ctor(e) er = new CommaExp(e.loc, er, new VarExp(e.loc, vd)); // ve.ctor(e),vd - er = Expression.combine(de, er); // de,ve.ctor(e),vd + er = combine(de, er); // de,ve.ctor(e),vd e = er.expressionSemantic(sc); } @@ -2000,7 +2064,7 @@ private Expression callCpCtor(Scope* sc, Expression e, Type destinationType, boo Expression ve = new VarExp(e.loc, tmp); de.type = Type.tvoid; ve.type = e.type; - return Expression.combine(de, ve); + return combine(de, ve); } /************************************************ @@ -2257,7 +2321,7 @@ private void hookDtors(CondExp ce, Scope* sc) de = de.expressionSemantic(sc); Expression ve = new VarExp(ce.econd.loc, vcond); - ce.econd = Expression.combine(de, ve); + ce.econd = combine(de, ve); } //printf("\t++v = %s, v.edtor = %s\n", v.toChars(), v.edtor.toChars()); @@ -4528,7 +4592,7 @@ private bool functionParameters(Loc loc, Scope* sc, auto declareTmp = new DeclarationExp(ale.loc, tmp); auto castToSlice = new CastExp(ale.loc, new VarExp(ale.loc, tmp), p.type.substWildTo(MODFlags.mutable)); - arg = CommaExp.combine(declareTmp, castToSlice); + arg = combine(declareTmp, castToSlice); arg = arg.expressionSemantic(sc); } else if (auto fe = a.isFuncExp()) @@ -4796,7 +4860,7 @@ private bool functionParameters(Loc loc, Scope* sc, // eprefix => (eprefix, auto __pfx/y = arg) auto ae = new DeclarationExp(loc, tmp); - eprefix = Expression.combine(eprefix, ae.expressionSemantic(sc)); + eprefix = combine(eprefix, ae.expressionSemantic(sc)); // arg => __pfx/y arg = new VarExp(loc, tmp); @@ -4816,7 +4880,7 @@ private bool functionParameters(Loc loc, Scope* sc, if (!callerDestroysArgs && i == lastPrefix) { auto e = new AssignExp(gate.loc, new VarExp(gate.loc, gate), IntegerExp.createBool(true)); - eprefix = Expression.combine(eprefix, e.expressionSemantic(sc)); + eprefix = combine(eprefix, e.expressionSemantic(sc)); } } else // not part of 'eprefix' @@ -7090,7 +7154,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (newprefix) { - result = Expression.combine(newprefix, exp); + result = combine(newprefix, exp); return; } result = exp; @@ -8045,7 +8109,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (!exp.f.needThis()) { - exp.e1 = Expression.combine(ue.e1, new VarExp(exp.loc, exp.f, false)); + exp.e1 = combine(ue.e1, new VarExp(exp.loc, exp.f, false)); } else { @@ -8487,7 +8551,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { lowerCastExp(cex, sc); } - result = Expression.combine(argprefix, casted_exp); + result = combine(argprefix, casted_exp); return; } } @@ -8498,7 +8562,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor exp.f.tookAddressOf = 0; } - result = Expression.combine(argprefix, exp); + result = combine(argprefix, exp); if (isSuper) { @@ -8552,7 +8616,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor } exp.vthis2 = makeThis2Argument(exp.loc, sc, exp.f); Expression de = new DeclarationExp(exp.loc, exp.vthis2); - result = Expression.combine(de, result); + result = combine(de, result); result = result.expressionSemantic(sc); } } @@ -9539,7 +9603,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor tmp.dsymbolSemantic(sc); auto decl = new DeclarationExp(op.loc, tmp); - temporariesPrefix = Expression.combine(temporariesPrefix, decl); + temporariesPrefix = combine(temporariesPrefix, decl); op = new VarExp(op.loc, tmp); op = op.expressionSemantic(sc); @@ -9739,7 +9803,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor result = !temporariesPrefix ? exp - : Expression.combine(temporariesPrefix, exp).expressionSemantic(sc); + : combine(temporariesPrefix, exp).expressionSemantic(sc); } override void visit(ThrowExp te) @@ -9914,7 +9978,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { // (e1, fd) auto e = symbolToExp(fd, exp.loc, sc, false); - result = Expression.combine(exp.e1, e); + result = combine(exp.e1, e); return; } @@ -10058,7 +10122,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor VarDeclaration vthis2 = makeThis2Argument(e.loc, sc, f); e.vthis2 = vthis2; Expression de = new DeclarationExp(e.loc, vthis2); - result = Expression.combine(de, result); + result = combine(de, result); result = result.expressionSemantic(sc); } } @@ -11556,7 +11620,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { TupleExp te = cast(TupleExp)exp.e2; if (te.exps && te.exps.length == 1) - exp.e2 = Expression.combine(te.e0, (*te.exps)[0]); // bug 4444 fix + exp.e2 = combine(te.e0, (*te.exps)[0]); // bug 4444 fix } if (sc != scx) sc = sc.pop(); @@ -11667,7 +11731,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor if (exp.e1.op == EXP.tuple) { e = (*te.exps)[cast(size_t)index]; - e = Expression.combine(te.e0, e); + e = combine(te.e0, e); } else e = new TypeExp(exp.e1.loc, Parameter.getNth(tup.arguments, cast(size_t)index).type); @@ -11892,8 +11956,8 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor * e1=(e0,e2) => e0,(e1=e2) */ Expression e0; - exp.e2 = Expression.extractLast(e2comma, e0); - Expression e = Expression.combine(e0, exp); + exp.e2 = extractLast(e2comma, e0); + Expression e = combine(e0, exp); return setResult(e.expressionSemantic(sc)); } @@ -11960,7 +12024,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor else res = res.expressionSemantic(sc); if (res) - return setResult(Expression.combine(e0, res)); + return setResult(combine(e0, res)); } Lfallback: @@ -11989,7 +12053,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor res = new DotIdExp(exp.loc, ae.e1, Id.opSliceAssign); res = new CallExp(exp.loc, res, a); res = res.expressionSemantic(sc); - return setResult(Expression.combine(e0, res)); + return setResult(combine(e0, res)); } // No operator overloading member function found yet, but @@ -12139,7 +12203,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { e = IntegerExp.literal!0; e = new CastExp(exp.loc, e, Type.tvoid); // avoid "has no effect" error - e = Expression.combine(tup1.e0, tup2.e0, e); + e = combine(tup1.e0, tup2.e0, e); } else { @@ -12150,7 +12214,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression ex2 = (*tup2.exps)[i]; (*exps)[i] = new AssignExp(exp.loc, ex1, ex2); } - e = new TupleExp(exp.loc, Expression.combine(tup1.e0, tup2.e0), exps); + e = new TupleExp(exp.loc, combine(tup1.e0, tup2.e0), exps); } return setResult(e.expressionSemantic(sc)); } @@ -12336,9 +12400,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor return setError(); Expression e0; - Expression.extractLast(e2x, e0); + extractLast(e2x, e0); - auto e = Expression.combine(e0, ae, cx); + auto e = combine(e0, ae, cx); e = e.expressionSemantic(sc); result = e; return; @@ -12742,7 +12806,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor Expression se = new SliceExp(ale.loc, ale.e1, lc, lc); Expression as = new AssignExp(ale.loc, ale.e1, se); as = as.expressionSemantic(sc); - auto res = Expression.combine(as, exp.e2); + auto res = combine(as, exp.e2); res.type = ale.type; return setResult(res); } @@ -13135,7 +13199,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(ae.e2); lowering = new CallExp(ae.loc, lowering, arguments); - lowering = Expression.combine(e0, lowering).expressionSemantic(sc); + lowering = combine(e0, lowering).expressionSemantic(sc); } ae.lowering = lowering; @@ -13225,9 +13289,9 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor arguments.push(value2); Expression ce = new CallExp(ae.loc, id, arguments); - res = Expression.combine(eValue2, ce).expressionSemantic(sc); + res = combine(eValue2, ce).expressionSemantic(sc); if (isArrayAssign) - res = Expression.combine(res, ae.e1).expressionSemantic(sc).checkGC(sc); + res = combine(res, ae.e1).expressionSemantic(sc).checkGC(sc); if (global.params.v.verbose) message("lowered %s =>\n %s", ae.toChars(), res.toChars()); @@ -13286,7 +13350,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor { Expression e0 = null; Expression e = exp; - e = Expression.extractLast(e, e0); + e = extractLast(e, e0); assert(e == exp); if (exp.e1.op == EXP.variable) @@ -13305,7 +13369,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor e = new AssignExp(exp.loc, new VarExp(exp.e1.loc, v), e); e = new CommaExp(exp.loc, de, e); } - e = Expression.combine(e0, e); + e = combine(e0, e); e = e.expressionSemantic(sc); result = e; return; @@ -13521,10 +13585,10 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto elem = new IndexExp(exp.loc, value1, new MinExp(exp.loc, ale, IntegerExp.literal!1)); auto ae = new ConstructExp(exp.loc, elem, value2); - auto e0 = Expression.combine(ce, ae).expressionSemantic(sc); - e0 = Expression.combine(e0, value1); - e0 = Expression.combine(eValue1, e0); - e0 = Expression.combine(eValue2, e0); + auto e0 = combine(ce, ae).expressionSemantic(sc); + e0 = combine(e0, value1); + e0 = combine(eValue1, e0); + e0 = combine(eValue2, e0); exp.lowering = e0.expressionSemantic(sc); *output = exp; @@ -14651,7 +14715,7 @@ private extern (C++) final class ExpressionSemanticVisitor : Visitor auto arguments = new Expressions(ie.e2, ekey); auto ce = new CallExp(ie.loc, id, arguments); ce.loweredFrom = ie; - e1 = Expression.combine(e1, ce); + e1 = combine(e1, ce); return e1.expressionSemantic(sc); } @@ -19694,7 +19758,7 @@ private Expression buildAAIndexRValueX(Type t, Expression eaa, Expression ekey, Expression e0; auto arguments = new Expressions(eaa, ekey); auto call = new CallExp(loc, func, arguments); - e0 = Expression.combine(e0, call); + e0 = combine(e0, call); if (arrayBoundsCheck(sc.func)) { @@ -19863,7 +19927,7 @@ private Expression rewriteAAIndexAssign(BinExp exp, Scope* sc, ref Type[2] alias BinExp bex = cast(BinExp)exp.copy(); bex.e1 = ex; bex.e2 = ev; - ex = Expression.combine(e0, bex); + ex = combine(e0, bex); ex.isCommaExp().originalExp = exp; return ex.expressionSemantic(sc); } @@ -19893,7 +19957,7 @@ private Expression rewriteAAIndexAssign(BinExp exp, Scope* sc, ref Type[2] alias } Expression condfound = new IdentifierExp(loc, idfound); ex = new CondExp(loc, condfound, ex, ey); - ex = Expression.combine(e0, ex); + ex = combine(e0, ex); ex.isCommaExp().originalExp = exp; } else @@ -19911,7 +19975,7 @@ private Expression rewriteAAIndexAssign(BinExp exp, Scope* sc, ref Type[2] alias } else { - ex = Expression.combine(e0, ae); + ex = combine(e0, ae); ex.isCommaExp().originalExp = exp; } ex = ex.expressionSemantic(sc); diff --git a/compiler/src/dmd/inline.d b/compiler/src/dmd/inline.d index bb5821c0f136..ca4b00b66b5a 100644 --- a/compiler/src/dmd/inline.d +++ b/compiler/src/dmd/inline.d @@ -29,7 +29,7 @@ import dmd.dsymbol; import dmd.dsymbolsem; import dmd.dtemplate; import dmd.expression; -import dmd.expressionsem : canElideCopy, semanticTypeInfo; +import dmd.expressionsem : canElideCopy, semanticTypeInfo, combine, extractLast; import dmd.errors : message; import dmd.errorsink; import dmd.func; @@ -256,13 +256,13 @@ public: e2.type = Type.tvoid; e.type = Type.tvoid; } - result = Expression.combine(result, e); + result = combine(result, e); } else { ids.foundReturn = false; auto e = doInlineAs!Expression(sx, ids); - result = Expression.combine(result, e); + result = combine(result, e); } } @@ -291,7 +291,7 @@ public: static if (asStatements) as.push(r); else - result = Expression.combine(result, r); + result = combine(result, r); if (ids.foundReturn) break; @@ -396,7 +396,7 @@ public: */ auto ce = new ConstructExp(s.loc, ids.eret.copy(), exp); ce.type = exp.type; - result = Expression.combine(ce, ids.eret.copy()); + result = combine(ce, ids.eret.copy()); return; } @@ -438,7 +438,7 @@ public: // Chain the two together: // ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval - exp = Expression.combine(de, new VarExp(s.loc, vd)); + exp = combine(de, new VarExp(s.loc, vd)); } result = exp; @@ -1310,7 +1310,7 @@ public: return; Expression e0; - Expression elast = Expression.extractLast(s.exp, e0); + Expression elast = extractLast(s.exp, e0); inlineScan(e0); if (auto ce = elast.isCallExp()) @@ -1328,7 +1328,7 @@ public: inlineScan(elast); } - s.exp = Expression.combine(e0, elast); + s.exp = combine(e0, elast); } override void visit(SynchronizedStatement s) @@ -1502,7 +1502,7 @@ public: void inlineConstruction(AssignExp e) { Expression e0; - Expression elast = Expression.extractLast(e.e2, e0); + Expression elast = extractLast(e.e2, e0); inlineScan(e0); // Side effects auto ce = elast.isCallExp(); @@ -1512,14 +1512,14 @@ public: if (eresult) { - eresult = Expression.combine(e0, eresult); + eresult = combine(e0, eresult); //printf("call with nrvo: %s ==> %s\n", e.toChars(), eresult.toChars()); return; } } inlineScan(elast); - e.e2 = Expression.combine(e0, elast); + e.e2 = combine(e0, elast); } inlineScan(e.e1); // LHS @@ -2282,7 +2282,7 @@ private void expandInline(CallExp ecall, FuncDeclaration fd, FuncDeclaration par if (ethis) { Expression e0; - ethis = Expression.extractLast(ethis, e0); + ethis = extractLast(ethis, e0); if (VarDeclaration vthis2 = ecall.vthis2) { @@ -2338,7 +2338,7 @@ private void expandInline(CallExp ecall, FuncDeclaration fd, FuncDeclaration par auto de = new DeclarationExp(fd.loc, vthis); de.type = Type.tvoid; - e0 = Expression.combine(e0, de); + e0 = combine(e0, de); } ethis = e0; @@ -2386,7 +2386,7 @@ private void expandInline(CallExp ecall, FuncDeclaration fd, FuncDeclaration par auto de = new DeclarationExp(vto.loc, vto); de.type = Type.tvoid; - eparams = Expression.combine(eparams, de); + eparams = combine(eparams, de); /* If function pointer or delegate parameters are present, * inline scan again because if they are initialized to a symbol, @@ -2479,8 +2479,8 @@ private void expandInline(CallExp ecall, FuncDeclaration fd, FuncDeclaration par e.type = Type.tvoid; } - eresult = Expression.combine(eresult, eret, ethis, eparams); - eresult = Expression.combine(eresult, e); + eresult = combine(eresult, eret, ethis, eparams); + eresult = combine(eresult, e); if (ecall.rvalue || tf.isRvalue) eresult.rvalue = true; diff --git a/compiler/src/dmd/opover.d b/compiler/src/dmd/opover.d index d086927db988..08599c40b6d3 100644 --- a/compiler/src/dmd/opover.d +++ b/compiler/src/dmd/opover.d @@ -220,7 +220,7 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) result = result.expressionSemantic(sc); if (result) - return Expression.combine(e0, result); + return combine(e0, result); } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceUnary)) @@ -237,7 +237,7 @@ Expression opOverloadUnary(UnaExp e, Scope* sc) dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op), ie.lwr, ie.upr) : dotTemplateCall(ae.e1, Id.opSliceUnary, opToArg(sc, e.op)); - return Expression.combine(e0, result.expressionSemantic(sc)); + return combine(e0, result.expressionSemantic(sc)); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) @@ -366,14 +366,14 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) result = result.expressionSemantic(sc); if (result) - return Expression.combine(e0, result); + return combine(e0, result); } Lfallback: if (maybeSlice && ae.e1.isTypeExp()) { Expression result = new SliceExp(ae.loc, ae.e1, ie); result = result.expressionSemantic(sc); - return Expression.combine(e0, result); + return combine(e0, result); } if (maybeSlice && search_function(ad, Id.opSlice)) { @@ -399,7 +399,7 @@ Expression opOverloadArray(ArrayExp ae, Scope* sc) Expression result = new DotIdExp(ae.loc, ae.e1, Id.opSlice); result = new CallExp(ae.loc, result, a); result = result.expressionSemantic(sc); - return Expression.combine(e0, result); + return combine(e0, result); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) @@ -842,7 +842,7 @@ Expression opOverloadEqual(EqualExp e, Scope* sc, Type[2] aliasThisStop) } assert(result); } - result = Expression.combine(tup1.e0, tup2.e0, result); + result = combine(tup1.e0, tup2.e0, result); result = result.expressionSemantic(sc); return result; @@ -955,7 +955,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt result = result.expressionSemantic(sc); if (result) - return Expression.combine(e0, result); + return combine(e0, result); } Lfallback: if (maybeSlice && search_function(ad, Id.opSliceOpAssign)) @@ -976,7 +976,7 @@ Expression opOverloadBinaryAssign(BinAssignExp e, Scope* sc, Type[2] aliasThisSt dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2, ie.lwr, ie.upr) : dotTemplateCall(ae.e1, Id.opSliceOpAssign, opToArg(sc, e.op), e.e2); - return Expression.combine(e0, result.expressionSemantic(sc)); + return combine(e0, result.expressionSemantic(sc)); } // Didn't find it. Forward to aliasthis if (ad.aliasthis && !isRecursiveAliasThis(att, ae.e1.type)) diff --git a/compiler/src/dmd/optimize.d b/compiler/src/dmd/optimize.d index 05a3aae5198e..b48575b2d00a 100644 --- a/compiler/src/dmd/optimize.d +++ b/compiler/src/dmd/optimize.d @@ -1304,7 +1304,7 @@ Expression optimize(Expression e, int result, bool keepLvalue = false) // e1 || true -> (e1, true) // e1 && false -> (e1, false) ret = IntegerExp.createBool(oror); - ret = Expression.combine(e.e1, ret); + ret = combine(e.e1, ret); if (e.type.toBasetype().ty == Tvoid) { ret = new CastExp(e.loc, ret, Type.tvoid); diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 15677f1fc6ff..67c970170884 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -982,7 +982,7 @@ private extern(C++) final class Semantic3Visitor : Visitor exp.type = funcdecl.vresult.type; if (rs.caseDim) - exp = Expression.combine(exp, new IntegerExp(rs.caseDim)); + exp = combine(exp, new IntegerExp(rs.caseDim)); } else if (funcdecl.tintro && !tret.equals(funcdecl.tintro.nextOf())) { diff --git a/compiler/src/dmd/sideeffect.d b/compiler/src/dmd/sideeffect.d index 2e579972d359..8712a6ea8dcc 100644 --- a/compiler/src/dmd/sideeffect.d +++ b/compiler/src/dmd/sideeffect.d @@ -450,7 +450,7 @@ Expression extractSideEffect(Scope* sc, const char[] name, stc |= (e.isLvalue() ? STC.ref_ : STC.rvalue); auto vd = copyToTemp(stc, name, e); - e0 = Expression.combine(e0, new DeclarationExp(vd.loc, vd) + e0 = combine(e0, new DeclarationExp(vd.loc, vd) .expressionSemantic(sc)); return new VarExp(vd.loc, vd) diff --git a/compiler/src/dmd/statementsem.d b/compiler/src/dmd/statementsem.d index d602f8d30e65..aa3f6aa5fec8 100644 --- a/compiler/src/dmd/statementsem.d +++ b/compiler/src/dmd/statementsem.d @@ -970,7 +970,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) if (!ec) return null; - e = Expression.combine(e, ec); + e = combine(e, ec); return loopReturn(e, fs.cases, loc); } @@ -2626,7 +2626,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) } // Extract side-effect part - rs.exp = Expression.extractLast(rs.exp, e0); + rs.exp = extractLast(rs.exp, e0); if (rs.exp.isCallExp()) rs.exp = valueNoDtor(rs.exp); @@ -2665,7 +2665,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) * with: * exp; return; */ - e0 = Expression.combine(e0, rs.exp); + e0 = combine(e0, rs.exp); rs.exp = null; } if (e0) @@ -2901,7 +2901,7 @@ Statement statementSemanticVisit(Statement s, Scope* sc) { if (e0.isDeclarationExp() || e0.isCommaExp()) { - rs.exp = Expression.combine(e0, rs.exp); + rs.exp = combine(e0, rs.exp); } else { From 98238cdfa07c63b4c4e08b3acbd74707955435e9 Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Tue, 24 Feb 2026 13:53:42 +0000 Subject: [PATCH 2/4] Remove unnecessary C++ wrappers for combine and extractLast --- compiler/src/dmd/cxxfrontend.d | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/compiler/src/dmd/cxxfrontend.d b/compiler/src/dmd/cxxfrontend.d index 19fe5f9de550..b4524a465bcf 100644 --- a/compiler/src/dmd/cxxfrontend.d +++ b/compiler/src/dmd/cxxfrontend.d @@ -393,30 +393,6 @@ Expression getDefaultValue(EnumDeclaration ed, Loc loc) * expressionsem.d */ -Expression combine(Expression e1, Expression e2) -{ - import dmd.expressionsem; - return dmd.expressionsem.combine(e1, e2); -} - -Expression combine(Expression e1, Expression e2, Expression e3) -{ - import dmd.expressionsem; - return dmd.expressionsem.combine(e1, e2, e3); -} - -Expression combine(Expression e1, Expression e2, Expression e3, Expression e4) -{ - import dmd.expressionsem; - return dmd.expressionsem.combine(e1, e2, e3, e4); -} - -Expression extractLast(Expression e, out Expression e0) -{ - import dmd.expressionsem; - return dmd.expressionsem.extractLast(e, e0); -} - void expandTuples(Expressions* exps, ArgumentLabels* names = null) { import dmd.expressionsem; From 5a422cb2462efd9cb46b37c9570471f1214306fd Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Wed, 4 Mar 2026 10:46:44 +0000 Subject: [PATCH 3/4] Add import for combine in semantic3.d --- compiler/src/dmd/semantic3.d | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index 67c970170884..e87eef4283f9 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -41,7 +41,7 @@ import dmd.dversion; import dmd.errors; import dmd.escape; import dmd.expression; -import dmd.expressionsem; +import dmd.expressionsem : combine; import dmd.func; import dmd.funcsem; import dmd.globals; From 16616db88f0a41956f901a22801be8c31f165889 Mon Sep 17 00:00:00 2001 From: Aditya Singh Date: Wed, 4 Mar 2026 10:52:41 +0000 Subject: [PATCH 4/4] Fix upstream Expression.combine call and add missing semantic imports after master merge --- compiler/src/dmd/semantic3.d | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/compiler/src/dmd/semantic3.d b/compiler/src/dmd/semantic3.d index ec43262c0cf4..36030774a11d 100644 --- a/compiler/src/dmd/semantic3.d +++ b/compiler/src/dmd/semantic3.d @@ -41,7 +41,7 @@ import dmd.dversion; import dmd.errors; import dmd.escape; import dmd.expression; -import dmd.expressionsem : combine; +import dmd.expressionsem; import dmd.func; import dmd.funcsem; import dmd.globals; @@ -980,7 +980,7 @@ private extern(C++) final class Semantic3Visitor : Visitor // Create: return (vresult = exp, vresult); exp = new ConstructExp(rs.loc, funcdecl.vresult, exp); exp = exp.expressionSemantic(scret); - exp = Expression.combine(exp, new VarExp(rs.loc, funcdecl.vresult)); + exp = combine(exp, new VarExp(rs.loc, funcdecl.vresult)); if (rs.caseDim) exp = combine(exp, new IntegerExp(rs.caseDim));