Showing with 100 additions and 65 deletions.
  1. +0 −4 src/ctfe.h
  2. +0 −26 src/ctfeexpr.c
  3. +2 −3 src/e2ir.c
  4. +74 −31 src/interpret.c
  5. +0 −1 src/magicport.json
  6. +24 −0 test/runnable/sdtor.d
4 changes: 0 additions & 4 deletions src/ctfe.h
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,6 @@ StringExp *createBlockDuplicatedStringLiteral(Loc loc, Type *type,
*/
void assignInPlace(Expression *dest, Expression *src);

/// Set all elements of 'ae' to 'val'. ae may be a multidimensional array.
/// If 'wantRef', all elements of ae will hold references to the same val.
void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef);

/// Duplicate the elements array, then set field 'indexToChange' = newelem.
Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem);

Expand Down
26 changes: 0 additions & 26 deletions src/ctfeexpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1971,32 +1971,6 @@ void assignInPlace(Expression *dest, Expression *src)
}
}

void recursiveBlockAssign(ArrayLiteralExp *ae, Expression *val, bool wantRef)
{
assert(ae->type->ty == Tsarray || ae->type->ty == Tarray);
Type *desttype = ((TypeArray *)ae->type)->next->toBasetype()->castMod(0);
bool directblk = (val->type->toBasetype()->castMod(0))->equals(desttype);

bool cow = val->op != TOKstructliteral &&
val->op != TOKarrayliteral &&
val->op != TOKstring;

for (size_t k = 0; k < ae->elements->dim; k++)
{
if (!directblk && (*ae->elements)[k]->op == TOKarrayliteral)
{
recursiveBlockAssign((ArrayLiteralExp *)(*ae->elements)[k], val, wantRef);
}
else
{
if (wantRef || cow)
(*ae->elements)[k] = val;
else
assignInPlace((*ae->elements)[k], val);
}
}
}

// Duplicate the elements array, then set field 'indexToChange' = newelem.
Expressions *changeOneElement(Expressions *oldelems, size_t indexToChange, Expression *newelem)
{
Expand Down
5 changes: 2 additions & 3 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -821,10 +821,9 @@ elem *setArray(elem *eptr, elem *edim, Type *tb, elem *evalue, IRState *irs, int
*/
if (op != TOKblit)
{
StructDeclaration *sd = needsPostblit(tb);
if (sd)
if (needsPostblit(tb) || needsDtor(tb))
{
/* Need to do postblit.
/* Need to do postblit/destructor.
* void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti);
*/
r = (op == TOKconstruct) ? RTLSYM_ARRAYSETCTOR : RTLSYM_ARRAYSETASSIGN;
Expand Down
105 changes: 74 additions & 31 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -4307,42 +4307,85 @@ class Interpreter : public Visitor
* x may be a multidimensional static array. (Note that this
* only happens with array literals, never with strings).
*/
Expressions *w = existingAE->elements;
assert(existingAE->type->ty == Tsarray ||
existingAE->type->ty == Tarray);
Type *dsttype = ((TypeArray *)existingAE->type)->next->toBasetype()->castMod(0);
bool directblk = (e->e2->type->toBasetype()->castMod(0))->equals(dsttype);
bool cow = !(newval->op == TOKstructliteral ||
newval->op == TOKarrayliteral ||
newval->op == TOKstring);
Type *tn = newval->type->toBasetype();
bool wantRef = (tn->ty == Tarray || isAssocArray(tn) ||tn->ty == Tclass);
for (size_t j = 0; j < upperbound - lowerbound; j++)
struct RecursiveBlock
{
if (!directblk)
{
// Multidimensional array block assign
recursiveBlockAssign((ArrayLiteralExp *)(*w)[(size_t)(j + firstIndex)], newval, wantRef);
}
else
InterState *istate;
Expression *newval;
bool refCopy;
bool needsPostblit;
bool needsDtor;

Expression *assignTo(ArrayLiteralExp *ae)
{
if (wantRef || cow)
(*existingAE->elements)[(size_t)(j + firstIndex)] = newval;
else
assignInPlace((*existingAE->elements)[(size_t)(j + firstIndex)], newval);
return assignTo(ae, 0, ae->elements->dim);
}
}
if (!(wantRef || cow) && e->op != TOKblit && e->e2->isLvalue())
{
size_t lwr = (size_t)(firstIndex);
size_t upr = (size_t)(firstIndex + upperbound - lowerbound);
for (size_t i = lwr; i < upr; i++)

Expression *assignTo(ArrayLiteralExp *ae, size_t lwr, size_t upr)
{
Expression *ex = evaluatePostblit(istate, (*existingAE->elements)[i]);
if (exceptionOrCantInterpret(ex))
return ex;
Expressions *w = ae->elements;

assert(ae->type->ty == Tsarray ||
ae->type->ty == Tarray);
bool directblk = ((TypeArray *)ae->type)->next->equivalent(newval->type);

for (size_t k = lwr; k < upr; k++)
{
if (!directblk && (*w)[k]->op == TOKarrayliteral)
{
// Multidimensional array block assign
if (Expression *ex = assignTo((ArrayLiteralExp *)(*w)[k]))
return ex;
}
else if (refCopy)
{
(*w)[k] = newval;
}
else if (!needsPostblit && !needsDtor)
{
assignInPlace((*w)[k], newval);
}
else
{
Expression *oldelem = (*w)[k];
Expression *tmpelem = needsDtor ? copyLiteral(oldelem).copy() : NULL;

assignInPlace(oldelem, newval);

if (needsPostblit)
{
if (Expression *ex = evaluatePostblit(istate, oldelem))
return ex;
}
if (needsDtor)
{
// Bugzilla 14860
if (Expression *ex = evaluateDtor(istate, tmpelem))
return ex;
}
}
}
return NULL;
}
}
};

Type *tn = newval->type->toBasetype();
bool wantRef = (tn->ty == Tarray || isAssocArray(tn) ||tn->ty == Tclass);
bool cow = newval->op != TOKstructliteral &&
newval->op != TOKarrayliteral &&
newval->op != TOKstring;
Type *tb = tn->baseElemOf();
StructDeclaration *sd = (tb->ty == Tstruct ? ((TypeStruct *)tb)->sym : NULL);

RecursiveBlock rb;
rb.istate = istate;
rb.newval = newval;
rb.refCopy = wantRef || cow;
rb.needsPostblit = sd && sd->postblit && e->op != TOKblit && e->e2->isLvalue();
rb.needsDtor = sd && sd->dtor && e->op == TOKassign;

if (Expression *ex = rb.assignTo(existingAE, lowerbound, upperbound))
return ex;

if (goal == ctfeNeedNothing)
return NULL; // avoid creating an unused literal
SliceExp *retslice = new SliceExp(e->loc, existingAE,
Expand Down
1 change: 0 additions & 1 deletion src/magicport.json
Original file line number Diff line number Diff line change
Expand Up @@ -268,7 +268,6 @@
"function ctfeIndex",
"function ctfeCast",
"function assignInPlace",
"function recursiveBlockAssign",
"function changeOneElement",
"function modifyStructField",
"function assignAssocArrayElement",
Expand Down
24 changes: 24 additions & 0 deletions test/runnable/sdtor.d
Original file line number Diff line number Diff line change
Expand Up @@ -3985,6 +3985,29 @@ int test14815()
}
static assert(test14815());

/**********************************/
// 14860

int test14860()
{
uint dtorCount;

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

S[] a = [S(42)];
a[] = S();

assert(a[0].x == 0);
assert(dtorCount == 1);

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

/**********************************/
// 14838

Expand Down Expand Up @@ -4155,6 +4178,7 @@ int main()
test13095();
test14264();
test14815();
test14860();
test14838();

printf("Success\n");
Expand Down