Showing with 75 additions and 13 deletions.
  1. +26 −8 src/e2ir.c
  2. +5 −5 src/interpret.c
  3. +44 −0 test/runnable/sdtor.d
34 changes: 26 additions & 8 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -715,9 +715,8 @@ elem *getTypeInfo(Type *t, IRState *irs)
}

/********************************************
* Determine if t is an array of structs that need a postblit.
* Determine if t is a struct that has postblit.
*/

StructDeclaration *needsPostblit(Type *t)
{
t = t->baseElemOf();
Expand All @@ -730,6 +729,21 @@ StructDeclaration *needsPostblit(Type *t)
return NULL;
}

/********************************************
* Determine if t is a struct that has destructor.
*/
StructDeclaration *needsDtor(Type *t)
{
t = t->baseElemOf();
if (t->ty == Tstruct)
{
StructDeclaration *sd = ((TypeStruct *)t)->sym;
if (sd->dtor)
return sd;
}
return NULL;
}

/*******************************************
* Set an array pointed to by eptr to evalue:
* eptr[0..edim] = evalue;
Expand Down Expand Up @@ -2601,18 +2615,19 @@ elem *toElem(Expression *e, IRState *irs)

/* Determine if we need to do postblit
*/
int postblit = 0;
bool postblit = false;
if (needsPostblit(t1->nextOf()) &&
(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 = 1;
postblit = true;
}
bool destructor = needsDtor(t1->nextOf()) != NULL;

assert(ae->e2->type->ty != Tpointer);

if (!postblit && !irs->arrayBoundsCheck())
if (!postblit && !destructor && !irs->arrayBoundsCheck())
{
elem *ex = el_same(&eto);

Expand All @@ -2637,7 +2652,7 @@ elem *toElem(Expression *e, IRState *irs)
e = el_pair(eto->Ety, el_copytree(elen), e);
e = el_combine(eto, e);
}
else if (postblit && ae->op != TOKblit)
else if ((postblit || destructor) && ae->op != TOKblit)
{
/* Generate:
* _d_arrayassign(ti, efrom, eto)
Expand Down Expand Up @@ -2825,6 +2840,7 @@ elem *toElem(Expression *e, IRState *irs)
assert(ae->e2->type->toBasetype()->ty == Tsarray);

bool postblit = needsPostblit(t1b->nextOf()) != NULL;
bool destructor = needsDtor(t1b->nextOf()) != NULL;

/* Optimize static array assignment with array literal.
* Rewrite:
Expand Down Expand Up @@ -2917,8 +2933,10 @@ elem *toElem(Expression *e, IRState *irs)

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

if (!postblit || (!lvalueElem && ae->op == TOKconstruct) ||
ae->op == TOKblit || type_size(e1->ET) == 0)
if (!postblit && !destructor ||
ae->op == TOKconstruct && !lvalueElem && postblit ||
ae->op == TOKblit ||
type_size(e1->ET) == 0)
{
e = el_bin(OPstreq, tym, e1, e2);
e->ET = Type_toCtype(ae->e1->type);
Expand Down
10 changes: 5 additions & 5 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -4194,11 +4194,11 @@ class Interpreter : public Visitor
Expression *aggr2 = se->e1;
dinteger_t srclower = se->lwr->toInteger();
dinteger_t srcupper = se->upr->toInteger();
bool wantCopy = (newval->type->toBasetype()->baseElemOf()->ty == Tstruct);
bool wantCopy = (newval->type->toBasetype()->nextOf()->baseElemOf()->ty == Tstruct);

//printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu]\n",
//printf("oldval = %p %s[%d..%u]\nnewval = %p %s[%llu..%llu] wantCopy = %d\n",
// aggregate, aggregate->toChars(), lowerbound, upperbound,
// aggr2, aggr2->toChars(), srclower, srcupper);
// aggr2, aggr2->toChars(), srclower, srcupper, wantCopy);
if (wantCopy)
{
// Currently overlapping for struct array is allowed.
Expand Down Expand Up @@ -4228,7 +4228,7 @@ class Interpreter : public Visitor
}
if (Expression *x = evaluateDtor(istate, oldelem))
return x;
(*oldelems)[i] = newelem;
(*oldelems)[lowerbound + i] = newelem;
}
}
else
Expand All @@ -4247,7 +4247,7 @@ class Interpreter : public Visitor
}
if (Expression *x = evaluateDtor(istate, oldelem))
return x;
(*oldelems)[i] = newelem;
(*oldelems)[lowerbound + i] = newelem;
}
}

Expand Down
44 changes: 44 additions & 0 deletions test/runnable/sdtor.d
Original file line number Diff line number Diff line change
Expand Up @@ -3942,6 +3942,49 @@ void test14264()
assert(dtor == 4);
}

/**********************************/
// 14815

int test14815()
{
uint dtorCount;

struct S
{
uint x;
~this() { ++dtorCount; }
}

S[2] sa1;
sa1[0].x = 42;
sa1 = (S[2]).init; // S[2] <- rvalue
assert(sa1[0].x == 0);
assert(dtorCount == 2);

S[2] sa2;
sa2[0].x = 42;
S[] da2 = sa2[];
da2[] = (S[2]).init[]; // S[] <- rvalue slice
assert(sa2[0].x == 0);
assert(dtorCount == 4);

S[2] sa3;
S[2] sa4;
sa3[0].x = 42;
sa3 = sa4; // S[2] <- lvalue
assert(sa3[0].x == 0);
assert(dtorCount == 6);

S[2] sa5;
S[] da4 = sa4[];
da4[] = sa5[]; // S[] <- lvalue slice
assert(sa4[0].x == 0);
assert(dtorCount == 8);

return 1;
}
static assert(test14815());

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

int main()
Expand Down Expand Up @@ -4058,6 +4101,7 @@ int main()
test13669();
test13095();
test14264();
test14815();

printf("Success\n");
return 0;
Expand Down