diff --git a/src/dinterpret.d b/src/dinterpret.d index cb0de7557063..289db034e096 100644 --- a/src/dinterpret.d +++ b/src/dinterpret.d @@ -5446,7 +5446,18 @@ public: } // We know we still own it, because we interpreted both e1 and e2 if (result.op == TOKarrayliteral) - (cast(ArrayLiteralExp)result).ownedByCtfe = OWNEDctfe; + { + ArrayLiteralExp ale = cast(ArrayLiteralExp)result; + ale.ownedByCtfe = OWNEDctfe; + + // Bugzilla 14686 + for (size_t i = 0; i < ale.elements.dim; i++) + { + Expression ex = evaluatePostblit(istate, (*ale.elements)[i]); + if (exceptionOrCant(ex)) + return; + } + } if (result.op == TOKstring) (cast(StringExp)result).ownedByCtfe = OWNEDctfe; } diff --git a/src/expression.d b/src/expression.d index e11937edd462..e4d9d8b0ca35 100644 --- a/src/expression.d +++ b/src/expression.d @@ -13213,18 +13213,31 @@ public: // Check for: array ~ element if ((tb1.ty == Tsarray || tb1.ty == Tarray) && tb2.ty != Tvoid) { - if (e1.op == TOKarrayliteral && e1.implicitConvTo(tb2.arrayOf())) + if (e1.op == TOKarrayliteral) + { + e2 = e2.isLvalue() ? callCpCtor(sc, e2) : valueNoDtor(e2); + // Bugzilla 14686: Postblit call appears in AST, and this is + // finally translated to an ArrayLiteralExp in below otpimize(). + } + else if (e1.op == TOKstring) + { + // No postblit call exists on character (integer) value. + } + else { if (e2.checkPostblit(sc, tb2)) return new ErrorExp(); + // Postblit call will be done in runtime helper function + } + + if (e1.op == TOKarrayliteral && e1.implicitConvTo(tb2.arrayOf())) + { e1 = e1.implicitCastTo(sc, tb2.arrayOf()); type = tb2.arrayOf(); goto L2elem; } if (e2.implicitConvTo(tb1next) >= MATCHconvert) { - if (e2.checkPostblit(sc, tb2)) - return new ErrorExp(); e2 = e2.implicitCastTo(sc, tb1next); type = tb1next.arrayOf(); L2elem: @@ -13234,24 +13247,33 @@ public: e2 = new ArrayLiteralExp(e2.loc, e2); e2.type = type; } - return this; + return optimize(WANTvalue); } } // Check for: element ~ array if ((tb2.ty == Tsarray || tb2.ty == Tarray) && tb1.ty != Tvoid) { - if (e2.op == TOKarrayliteral && e2.implicitConvTo(tb1.arrayOf())) + if (e2.op == TOKarrayliteral) + { + e1 = e1.isLvalue() ? callCpCtor(sc, e1) : valueNoDtor(e1); + } + else if (e2.op == TOKstring) + { + } + else { if (e1.checkPostblit(sc, tb1)) return new ErrorExp(); + } + + if (e2.op == TOKarrayliteral && e2.implicitConvTo(tb1.arrayOf())) + { e2 = e2.implicitCastTo(sc, tb1.arrayOf()); type = tb1.arrayOf(); goto L1elem; } if (e1.implicitConvTo(tb2next) >= MATCHconvert) { - if (e1.checkPostblit(sc, tb1)) - return new ErrorExp(); e1 = e1.implicitCastTo(sc, tb2next); type = tb2next.arrayOf(); L1elem: @@ -13261,7 +13283,7 @@ public: e1 = new ArrayLiteralExp(e1.loc, e1); e1.type = type; } - return this; + return optimize(WANTvalue); } } Lpeer: @@ -13302,20 +13324,17 @@ public: } Type t1 = e1.type.toBasetype(); Type t2 = e2.type.toBasetype(); - if (e1.op == TOKstring && e2.op == TOKstring) + if ((t1.ty == Tarray || t1.ty == Tsarray) && + (t2.ty == Tarray || t2.ty == Tsarray)) { + // Normalize to ArrayLiteralExp or StringExp as far as possible e = optimize(WANTvalue); } - else if ((t1.ty == Tarray || t1.ty == Tsarray) && (t2.ty == Tarray || t2.ty == Tsarray)) - { - e = this; - } else { //printf("(%s) ~ (%s)\n", e1->toChars(), e2->toChars()); return incompatibleTypes(); } - e.type = e.type.semantic(loc, sc); return e; } diff --git a/test/runnable/sdtor.d b/test/runnable/sdtor.d index 97208a96bdbb..97182cd78aa2 100644 --- a/test/runnable/sdtor.d +++ b/test/runnable/sdtor.d @@ -3942,6 +3942,50 @@ void test14264() assert(dtor == 4); } +/**********************************/ +// 14686 + +int test14686() +{ + string r; + + struct S + { + int n; + this(this) { r ~= cast(char)('0' + n); } + } + + S s1 = S(1); + S s2 = S(2); + S[] a1 = [S(1)]; + + S[2] sa1 = [s1, s2]; + assert(r == "12", r); // OK + + r = ""; + S[] a2 = a1 ~ s2; // runtime concatenation + assert(r == "12", r); // OK <- NG only in CTFE + + r = ""; + S[2] sa2a = [s1] ~ s2; + assert(r == "12", r); // OK <- NG, s2 is not copied + + r = ""; + S[2] sa2b = s2 ~ [s1]; + assert(r == "21", r); // OK <- NG, s2 is not copied + + r = ""; + S[3] sa3a = ([s1] ~ [s1]) ~ s2; + assert(r == "112", r); // OK <- NG, s2 is not copied + + r = ""; + S[3] sa3b = s2 ~ ([s1] ~ [s1]); + assert(r == "211", r); // OK <- NG, s2 is not copied + + return 1; +} +static assert(test14686()); + /**********************************/ // 14815 @@ -4315,6 +4359,7 @@ int main() test13669(); test13095(); test14264(); + test14686(); test14815(); test14860(); test14696();