Skip to content

Commit

Permalink
fix Issue 14686 - Postblit isn't sometimes called on concatenation
Browse files Browse the repository at this point in the history
  • Loading branch information
9rnsr committed Jan 31, 2016
1 parent 84f6aaf commit 795a828
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 15 deletions.
13 changes: 12 additions & 1 deletion src/dinterpret.d
Expand Up @@ -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;
}
Expand Down
47 changes: 33 additions & 14 deletions src/expression.d
Expand Up @@ -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:
Expand All @@ -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:
Expand All @@ -13261,7 +13283,7 @@ public:
e1 = new ArrayLiteralExp(e1.loc, e1);
e1.type = type;
}
return this;
return optimize(WANTvalue);
}
}
Lpeer:
Expand Down Expand Up @@ -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;
}

Expand Down
45 changes: 45 additions & 0 deletions test/runnable/sdtor.d
Expand Up @@ -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

Expand Down Expand Up @@ -4315,6 +4359,7 @@ int main()
test13669();
test13095();
test14264();
test14686();
test14815();
test14860();
test14696();
Expand Down

0 comments on commit 795a828

Please sign in to comment.