Showing with 390 additions and 109 deletions.
  1. +75 −34 src/clone.c
  2. +32 −26 src/declaration.c
  3. +8 −4 src/e2ir.c
  4. +2 −0 src/idgen.d
  5. +30 −37 src/interpret.c
  6. +63 −0 src/module.c
  7. +35 −8 src/struct.c
  8. +91 −0 test/compilable/test14838.d
  9. +54 −0 test/runnable/sdtor.d
109 changes: 75 additions & 34 deletions src/clone.c
Original file line number Diff line number Diff line change
Expand Up @@ -499,11 +499,6 @@ FuncDeclaration *buildXopEquals(StructDeclaration *sd, Scope *sc)
e = new DotIdExp(sd->loc, e, id);
e = e->semantic(sc);
Dsymbol *s = getDsymbol(e);
if (!s)
{
::error(Loc(), "Internal Compiler Error: %s not found in object module. You must update druntime", id->toChars());
fatal();
}
assert(s);
sd->xerreq = s->isFuncDeclaration();
}
Expand Down Expand Up @@ -624,11 +619,6 @@ FuncDeclaration *buildXopCmp(StructDeclaration *sd, Scope *sc)
e = new DotIdExp(sd->loc, e, id);
e = e->semantic(sc);
Dsymbol *s = getDsymbol(e);
if (!s)
{
::error(Loc(), "Internal Compiler Error: %s not found in object module. You must update druntime", id->toChars());
fatal();
}
assert(s);
sd->xerrcmp = s->isFuncDeclaration();
}
Expand Down Expand Up @@ -822,19 +812,36 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
ex = new DotVarExp(loc, ex, v, 0);
if (v->type->toBasetype()->ty == Tstruct)
{
// this.v.__postblit()
// this.v.__xpostblit()

// This is a hack so we can call postblits on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv->postblit, 0);
ex = new CallExp(loc, ex);
}
else
{
// typeid(typeof(v)).postblit(cast(void*)&this.v);
Expression *ea = new AddrExp(loc, ex);
ea = new CastExp(loc, ea, Type::tvoid->pointerTo());

Expression *et = new TypeidExp(loc, v->type);
et = new DotIdExp(loc, et, Identifier::idPool("postblit"));
ex = new CallExp(loc, et, ea);
// _ArrayPostblit((cast(S*)this.v.ptr)[0 .. n])

// This is a hack so we can call postblits on const/immutable objects.
ex = new DotIdExp(loc, ex, Id::ptr);
ex = new CastExp(loc, ex, sdv->type->pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

uinteger_t n = v->type->size() / sdv->type->size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
new IntegerExp(loc, n, Type::tsize_t));
// Prevent redundant bounds check
((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = true;

ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayPostblit), ex);
}
a->push(new ExpStatement(loc, ex)); // combine in forward order

Expand All @@ -847,19 +854,36 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc)
ex = new DotVarExp(loc, ex, v, 0);
if (v->type->toBasetype()->ty == Tstruct)
{
// this.v.__dtor()
// this.v.__xdtor()

// This is a hack so we can call destructors on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv->dtor, 0);
ex = new CallExp(loc, ex);
}
else
{
// Typeinfo.destroy(cast(void*)&this.v);
Expression *ea = new AddrExp(loc, ex);
ea = new CastExp(loc, ea, Type::tvoid->pointerTo());

Expression *et = new TypeidExp(loc, v->type);
et = new DotIdExp(loc, et, Id::destroy);
ex = new CallExp(loc, et, ea);
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

// This is a hack so we can call destructors on const/immutable objects.
ex = new DotIdExp(loc, ex, Id::ptr);
ex = new CastExp(loc, ex, sdv->type->pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

uinteger_t n = v->type->size() / sdv->type->size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
new IntegerExp(loc, n, Type::tsize_t));
// Prevent redundant bounds check
((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = true;

ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
}
a->push(new OnScopeStatement(loc, TOKon_scope_failure, new ExpStatement(loc, ex)));
}
Expand Down Expand Up @@ -959,19 +983,36 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc)
ex = new DotVarExp(loc, ex, v, 0);
if (v->type->toBasetype()->ty == Tstruct)
{
// this.v.__dtor()
// this.v.__xdtor()

// This is a hack so we can call destructors on const/immutable objects.
ex = new AddrExp(loc, ex);
ex = new CastExp(loc, ex, v->type->mutableOf()->pointerTo());
ex = new PtrExp(loc, ex);
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

ex = new DotVarExp(loc, ex, sdv->dtor, 0);
ex = new CallExp(loc, ex);
}
else
{
// Typeinfo.destroy(cast(void*)&this.v);
Expression *ea = new AddrExp(loc, ex);
ea = new CastExp(loc, ea, Type::tvoid->pointerTo());

Expression *et = new TypeidExp(loc, v->type);
et = new DotIdExp(loc, et, Id::destroy);
ex = new CallExp(loc, et, ea);
// _ArrayDtor((cast(S*)this.v.ptr)[0 .. n])

// This is a hack so we can call destructors on const/immutable objects.
ex = new DotIdExp(loc, ex, Id::ptr);
ex = new CastExp(loc, ex, sdv->type->pointerTo());
if (stc & STCsafe)
stc = (stc & ~STCsafe) | STCtrusted;

uinteger_t n = v->type->size() / sdv->type->size();
ex = new SliceExp(loc, ex, new IntegerExp(loc, 0, Type::tsize_t),
new IntegerExp(loc, n, Type::tsize_t));
// Prevent redundant bounds check
((SliceExp *)ex)->upperIsInBounds = true;
((SliceExp *)ex)->lowerIsLessThanUpper = true;

ex = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), ex);
}
e = Expression::combine(ex, e); // combine in reverse order
}
Expand Down
58 changes: 32 additions & 26 deletions src/declaration.c
Original file line number Diff line number Diff line change
Expand Up @@ -2063,36 +2063,42 @@ Expression *VarDeclaration::callScopeDtor(Scope *sc)
Type *tv = type->baseElemOf();
if (tv->ty == Tstruct)
{
TypeStruct *ts = (TypeStruct *)tv;
StructDeclaration *sd = ts->sym;
if (sd->dtor)
StructDeclaration *sd = ((TypeStruct *)tv)->sym;
if (!sd->dtor || !type->size())
return NULL;

if (type->toBasetype()->ty == Tstruct)
{
if (type->toBasetype()->ty == Tsarray)
{
// Typeinfo.destroy(cast(void*)&v);
Expression *ea = new SymOffExp(loc, this, 0, 0);
ea = new CastExp(loc, ea, Type::tvoid->pointerTo());
Expressions *args = new Expressions();
args->push(ea);
// v.__xdtor()
e = new VarExp(loc, this);

Expression *et = new TypeidExp(loc, type);
et = new DotIdExp(loc, et, Id::destroy);
/* This is a hack so we can call destructors on const/immutable objects.
* Need to add things like "const ~this()" and "immutable ~this()" to
* fix properly.
*/
e->type = e->type->mutableOf();

e = new CallExp(loc, et, args);
}
else
{
e = new VarExp(loc, this);
/* This is a hack so we can call destructors on const/immutable objects.
* Need to add things like "const ~this()" and "immutable ~this()" to
* fix properly.
*/
e->type = e->type->mutableOf();
e = new DotVarExp(loc, e, sd->dtor, 0);
e = new CallExp(loc, e);
}
return e;
e = new DotVarExp(loc, e, sd->dtor, 0);
e = new CallExp(loc, e);
}
else
{
// _ArrayDtor(v[0 .. n])
e = new VarExp(loc, this);

uinteger_t n = type->size() / sd->type->size();
e = new SliceExp(loc, e, new IntegerExp(loc, 0, Type::tsize_t),
new IntegerExp(loc, n, Type::tsize_t));
// Prevent redundant bounds check
((SliceExp *)e)->upperIsInBounds = true;
((SliceExp *)e)->lowerIsLessThanUpper = true;

// This is a hack so we can call destructors on const/immutable objects.
e->type = sd->type->arrayOf();

e = new CallExp(loc, new IdentifierExp(loc, Id::_ArrayDtor), e);
}
return e;
}

// Destructors for classes
Expand Down
12 changes: 8 additions & 4 deletions src/e2ir.c
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,8 @@ StructDeclaration *needsPostblit(Type *t)
*/

elem *setArray(elem *eptr, elem *edim, Type *tb, elem *evalue, IRState *irs, int op)
{ int r;
{
int r;
elem *e;
unsigned sz = tb->size();

Expand Down Expand Up @@ -760,10 +761,11 @@ elem *setArray(elem *eptr, elem *edim, Type *tb, elem *evalue, IRState *irs, int
break;

case Tstruct:
{
if (I32)
goto Ldefault;

{ TypeStruct *tc = (TypeStruct *)tb;
TypeStruct *tc = (TypeStruct *)tb;
StructDeclaration *sd = tc->sym;
if (sd->arg1type && !sd->arg2type)
{
Expand Down Expand Up @@ -795,12 +797,14 @@ elem *setArray(elem *eptr, elem *edim, Type *tb, elem *evalue, IRState *irs, int
{
StructDeclaration *sd = needsPostblit(tb);
if (sd)
{ /* Need to do postblit.
{
/* Need to do postblit.
* void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti);
*/
r = (op == TOKconstruct) ? RTLSYM_ARRAYSETCTOR : RTLSYM_ARRAYSETASSIGN;
evalue = el_una(OPaddr, TYnptr, evalue);
elem *eti = getTypeInfo(tb, irs);
// This is a hack so we can call postblits on const/immutable objects.
elem *eti = getTypeInfo(tb->unSharedOf()->mutableOf(), irs);
e = el_params(eti, edim, evalue, eptr, NULL);
e = el_bin(OPcall,TYnptr,el_var(rtlsym[r]),e);
return e;
Expand Down
2 changes: 2 additions & 0 deletions src/idgen.d
Original file line number Diff line number Diff line change
Expand Up @@ -265,6 +265,8 @@ Msgtable[] msgtable =
{ "criticalenter", "_d_criticalenter" },
{ "criticalexit", "_d_criticalexit" },
{ "_ArrayEq" },
{ "_ArrayPostblit" },
{ "_ArrayDtor" },

// For pragma's
{ "Pinline", "inline" },
Expand Down
67 changes: 30 additions & 37 deletions src/interpret.c
Original file line number Diff line number Diff line change
Expand Up @@ -4759,48 +4759,41 @@ class Interpreter : public Visitor

if (pthis->op == TOKdottype)
pthis = ((DotTypeExp *)dve->e1)->e1;

// Special handling for: typeid(T[n]).destroy(ea)
if (pthis->op == TOKtypeid)
{
TypeidExp *tie = (TypeidExp *)pthis;
Type *t = isType(tie->obj);
if (t &&
t->toBasetype()->ty == Tsarray &&
fd->ident == Id::destroy &&
e->arguments->dim == 1)
{
Type *tb = t->baseElemOf();
if (tb->ty == Tstruct && ((TypeStruct *)tb)->sym->dtor)
{
Expression *ea = (*e->arguments)[0];
// ea would be:
// &var <-- SymOffExp
// cast(void*)&var
// cast(void*)&this.field
// etc.
if (ea->op == TOKcast)
ea = ((CastExp *)ea)->e1;
if (ea->op == TOKsymoff)
result = getVarExp(e->loc, istate, ((SymOffExp *)ea)->var, ctfeNeedRvalue);
else if (ea->op == TOKaddress)
result = interpret(((AddrExp *)ea)->e1, istate);
else
assert(0);
if (CTFEExp::isCantExp(result))
return;
result = evaluateDtor(istate, result);
if (!result)
result = CTFEExp::voidexp;
return;
}
}
}
}
else if (ecall->op == TOKvar)
{
fd = ((VarExp *)ecall)->var->isFuncDeclaration();
assert(fd);

if (fd->ident == Id::_ArrayPostblit ||
fd->ident == Id::_ArrayDtor)
{
assert(e->arguments->dim == 1);
Expression *ea = (*e->arguments)[0];
//printf("1 ea = %s %s\n", ea->type->toChars(), ea->toChars());
if (ea->op == TOKslice)
ea = ((SliceExp *)ea)->e1;
if (ea->op == TOKcast)
ea = ((CastExp *)ea)->e1;

//printf("2 ea = %s, %s %s\n", ea->type->toChars(), Token::toChars(ea->op), ea->toChars());
if (ea->op == TOKvar || ea->op == TOKsymoff)
result = getVarExp(e->loc, istate, ((SymbolExp *)ea)->var, ctfeNeedRvalue);
else if (ea->op == TOKaddress)
result = interpret(((AddrExp *)ea)->e1, istate);
else
assert(0);
if (CTFEExp::isCantExp(result))
return;

if (fd->ident == Id::_ArrayPostblit)
result = evaluatePostblit(istate, result);
else
result = evaluateDtor(istate, result);
if (!result)
result = CTFEExp::voidexp;
return;
}
}
else if (ecall->op == TOKsymoff)
{
Expand Down
Loading