Skip to content

Commit

Permalink
fix Issue 13661 - static array init does not call destructors
Browse files Browse the repository at this point in the history
  • Loading branch information
9rnsr committed Nov 21, 2014
1 parent 6ee121d commit 36ef681
Show file tree
Hide file tree
Showing 4 changed files with 135 additions and 28 deletions.
2 changes: 2 additions & 0 deletions src/backend/rtlsym.h
Expand Up @@ -115,6 +115,8 @@ SYMBOL_MARS(ARRAYSETLENGTHT,FLfunc,FREGSAVED,"_d_arraysetlengthT", 0, t) \
SYMBOL_MARS(ARRAYSETLENGTHIT,FLfunc,FREGSAVED,"_d_arraysetlengthiT", 0, t) \
SYMBOL_MARS(ARRAYCOPY, FLfunc,FREGSAVED,"_d_arraycopy", 0, t) \
SYMBOL_MARS(ARRAYASSIGN, FLfunc,FREGSAVED,"_d_arrayassign", 0, t) \
SYMBOL_MARS(ARRAYASSIGN_R, FLfunc,FREGSAVED,"_d_arrayassign_r", 0, t) \
SYMBOL_MARS(ARRAYASSIGN_L, FLfunc,FREGSAVED,"_d_arrayassign_l", 0, t) \
SYMBOL_MARS(ARRAYCTOR, FLfunc,FREGSAVED,"_d_arrayctor", 0, t) \
SYMBOL_MARS(ARRAYSETASSIGN, FLfunc,FREGSAVED,"_d_arraysetassign", 0, t) \
SYMBOL_MARS(ARRAYSETCTOR, FLfunc,FREGSAVED,"_d_arraysetctor", 0, t) \
Expand Down
54 changes: 37 additions & 17 deletions src/e2ir.c
Expand Up @@ -2800,46 +2800,66 @@ elem *toElem(Expression *e, IRState *irs)
goto Lret;
}

/* Determine if we need to do postblit
/* Bugzilla 13661: Even if the elements in rhs are all rvalues and
* don't have to call postblits, this assignment should call
* destructors on old assigned elements.
*/
if (postblit &&
!(ae->e2->op == TOKslice && ((UnaExp *)ae->e2)->e1->isLvalue() ||
ae->e2->op == TOKcast && ((UnaExp *)ae->e2)->e1->isLvalue() ||
ae->e2->op != TOKslice && ae->e2->isLvalue()))
bool lvalueElem = false;
if (ae->e2->op == TOKslice && ((UnaExp *)ae->e2)->e1->isLvalue() ||
ae->e2->op == TOKcast && ((UnaExp *)ae->e2)->e1->isLvalue() ||
ae->e2->op != TOKslice && ae->e2->isLvalue())
{
postblit = false;
lvalueElem = true;
}

elem *e2 = toElem(ae->e2, irs);

if (!postblit || ae->op == TOKblit || type_size(e1->ET) == 0)
if (!postblit || (!lvalueElem && ae->op == TOKconstruct) ||
ae->op == TOKblit || type_size(e1->ET) == 0)
{
e = el_bin(OPstreq, tym, e1, e2);
e->ET = Type_toCtype(ae->e1->type);
if (type_size(e->ET) == 0)
e->Eoper = OPcomma;
}
else if (ae->op == TOKconstruct)
{
e1 = sarray_toDarray(ae->e1->loc, ae->e1->type, NULL, e1);
e2 = sarray_toDarray(ae->e2->loc, ae->e2->type, NULL, e2);

/* Generate:
* _d_arrayctor(ti, e2, e1)
*/
Expression *ti = t1b->nextOf()->toBasetype()->getTypeInfo(NULL);
if (config.exe == EX_WIN64)
{
e1 = addressElem(e1, Type::tvoid->arrayOf());
e2 = addressElem(e2, Type::tvoid->arrayOf());
}
elem *ep = el_params(e1, e2, toElem(ti, irs), NULL);
e = el_bin(OPcall, TYdarray, el_var(rtlsym[RTLSYM_ARRAYCTOR]), ep);
}
else
{
elem *eto = e1;
elem *efrom = e2;
e1 = sarray_toDarray(ae->e1->loc, ae->e1->type, NULL, e1);
e2 = sarray_toDarray(ae->e2->loc, ae->e2->type, NULL, e2);

eto = sarray_toDarray(ae->e1->loc, ae->e1->type, NULL, eto);
efrom = sarray_toDarray(ae->e2->loc, ae->e2->type, NULL, efrom);
symbol *stmp = symbol_genauto(Type_toCtype(t1b->nextOf()));
elem *etmp = el_una(OPaddr, TYnptr, el_var(stmp));

/* Generate:
* _d_arrayassign(ti, efrom, eto)
* _d_arrayassign_r(ti, e2, e1, etmp)
* or:
* _d_arrayctor(ti, efrom, eto)
* _d_arrayassign_r(ti, e2, e1, etmp)
*/
Expression *ti = t1b->nextOf()->toBasetype()->getTypeInfo(NULL);
if (config.exe == EX_WIN64)
{
eto = addressElem(eto, Type::tvoid->arrayOf());
efrom = addressElem(efrom, Type::tvoid->arrayOf());
e1 = addressElem(e1, Type::tvoid->arrayOf());
e2 = addressElem(e2, Type::tvoid->arrayOf());
}
elem *ep = el_params(eto, efrom, toElem(ti, irs), NULL);
int rtl = (ae->op == TOKconstruct) ? RTLSYM_ARRAYCTOR : RTLSYM_ARRAYASSIGN;
elem *ep = el_params(etmp, e1, e2, toElem(ti, irs), NULL);
int rtl = lvalueElem ? RTLSYM_ARRAYASSIGN_L : RTLSYM_ARRAYASSIGN_R;
e = el_bin(OPcall, TYdarray, el_var(rtlsym[rtl]), ep);
}
}
Expand Down
60 changes: 49 additions & 11 deletions src/interpret.c
Expand Up @@ -4012,12 +4012,13 @@ class Interpreter : public Visitor
{
VarExp *ve = (VarExp *)e1;
VarDeclaration *v = ve->var->isVarDeclaration();
Type *t1b = e1->type->toBasetype();
if (wantRef)
{
setValueNull(v);
setValue(v, newval);
}
else if (e1->type->toBasetype()->ty == Tstruct)
else if (t1b->ty == Tstruct)
{
// In-place modification
if (newval->op != TOKstructliteral)
Expand All @@ -4032,35 +4033,72 @@ class Interpreter : public Visitor
else
setValue(v, newval);
}
else
else if (t1b->ty == Tsarray)
{
TY tyE1 = e1->type->toBasetype()->ty;
if (tyE1 == Tsarray && newval->op == TOKslice)
if (newval->op == TOKslice)
{
// Newly set value is non-ref static array,
// so making new ArrayLiteralExp is legitimate.
newval = resolveSlice(newval);
assert(newval->op == TOKarrayliteral);
((ArrayLiteralExp *)newval)->ownedByCtfe = true;
}
if (tyE1 == Tarray || tyE1 == Taarray)
if (e->op == TOKassign)
{
// arr op= arr
setValue(v, newval);
Expression *oldval = getValue(v);
assert(oldval->op == TOKarrayliteral);
assert(newval->op == TOKarrayliteral);

Expressions *oldelems = ((ArrayLiteralExp *)oldval)->elements;
Expressions *newelems = ((ArrayLiteralExp *)newval)->elements;
assert(oldelems->dim == newelems->dim);

Type *elemtype = oldval->type->nextOf();
for (size_t j = 0; j < newelems->dim; j++)
{
Expression *newelem = paintTypeOntoLiteral(elemtype, (*newelems)[j]);
// Bugzilla 9245
if (Expression *x = evaluatePostblit(istate, newelem))
{
result = x;
return;
}
// Bugzilla 13661
if (Expression *x = evaluateDtor(istate, (*oldelems)[j]))
{
result = x;
return;
}
(*oldelems)[j] = newelem;
}
}
else
{
setValue(v, newval);
if (e->op != TOKblit && tyE1 == Tsarray && e->e2->isLvalue())

if (e->op == TOKconstruct && e->e2->isLvalue())
{
assert(newval->op == TOKarrayliteral);
ArrayLiteralExp *ale = (ArrayLiteralExp *)newval;
if (Expression *x = evaluatePostblits(istate, ale, 0, ale->elements->dim))
// Bugzilla 9245
if (Expression *x = evaluatePostblit(istate, newval))
{
result = x;
return;
}
}
}
return;
}
else
{
if (t1b->ty == Tarray || t1b->ty == Taarray)
{
// arr op= arr
setValue(v, newval);
}
else
{
setValue(v, newval);
}
}
}
else if (e1->op == TOKstructliteral && newval->op == TOKstructliteral)
Expand Down
47 changes: 47 additions & 0 deletions test/runnable/sdtor.d
Expand Up @@ -2300,6 +2300,7 @@ void g8335(lazy S8335[3] arr)
{
assert(S8335.postblit == 0);
auto x = arr;
assert(S8335.postblit == 3);
}

void h8335(lazy S8335 s)
Expand Down Expand Up @@ -3448,6 +3449,51 @@ void test13586()
}
}

/**********************************/
// 13661

bool test13661()
{
string postblit;
string dtor;

struct S
{
char x = 'x';

this(this) { postblit ~= x; }
~this() { dtor ~= x; }

ref auto opAssign(T)(T arg)
{
assert(0);
return this;
}
}

{
S[2] a;

a[0].x = 'a';
a[1].x = 'b';

a = a.init;
assert(dtor == "ab");
assert(a[0].x == 'x' && a[1].x == 'x');

a[0].x = 'c';
a[1].x = 'd';

a = [S(), S()]; // equivalent a = a.init
assert(dtor == "abcd");
assert(a[0].x == 'x' && a[1].x == 'x');
}
assert(dtor == "abcdxx");

return true;
}
static assert(test13661()); // CTFE

/**********************************/

__gshared bool b13095 = false;
Expand Down Expand Up @@ -3576,6 +3622,7 @@ int main()
test13303();
test13673();
test13586();
test13661();
test13095();

printf("Success\n");
Expand Down

0 comments on commit 36ef681

Please sign in to comment.