diff --git a/src/backend/rtlsym.h b/src/backend/rtlsym.h index adf65ba4a3d0..6a207de2397d 100644 --- a/src/backend/rtlsym.h +++ b/src/backend/rtlsym.h @@ -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) \ diff --git a/src/e2ir.c b/src/e2ir.c index 3d7c38a52885..cf3a6f7c2c3a 100644 --- a/src/e2ir.c +++ b/src/e2ir.c @@ -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); } } diff --git a/src/interpret.c b/src/interpret.c index 74a142a7f525..797e50e91ede 100644 --- a/src/interpret.c +++ b/src/interpret.c @@ -4011,12 +4011,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) @@ -4031,35 +4032,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) diff --git a/test/runnable/sdtor.d b/test/runnable/sdtor.d index 6dec1be84ea0..30976eb3b925 100644 --- a/test/runnable/sdtor.d +++ b/test/runnable/sdtor.d @@ -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) @@ -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; @@ -3576,6 +3622,7 @@ int main() test13303(); test13673(); test13586(); + test13661(); test13095(); printf("Success\n");