diff --git a/src/core/lifetime.d b/src/core/lifetime.d index d4452d1c94..b45e95f422 100644 --- a/src/core/lifetime.d +++ b/src/core/lifetime.d @@ -2221,3 +2221,74 @@ pure nothrow @nogc @system unittest static assert(!__traits(compiles, f(ncarray))); f(move(ncarray)); } + +/** + * This is called for a delete statement where the value + * being deleted is a pointer to a struct with a destructor + * but doesn't have an overloaded delete operator. + * + * Params: + * p = pointer to the value to be deleted + */ +void _d_delstruct(T)(ref T *p) +{ + if (p) + { + debug(PRINTF) printf("_d_delstruct(%p)\n", p); + + import core.memory : GC; + + destroy(*p); + GC.free(p); + p = null; + } +} + +@system unittest +{ + int dtors = 0; + struct S { ~this() { ++dtors; } } + + S *s = new S(); + _d_delstruct(s); + + assert(s == null); + assert(dtors == 1); +} + +@system unittest +{ + int innerDtors = 0; + int outerDtors = 0; + + struct Inner { ~this() { ++innerDtors; } } + struct Outer + { + Inner *i1; + Inner *i2; + + this(int x) + { + i1 = new Inner(); + i2 = new Inner(); + } + + ~this() + { + ++outerDtors; + + _d_delstruct(i1); + assert(i1 == null); + + _d_delstruct(i2); + assert(i2 == null); + } + } + + Outer *o = new Outer(0); + _d_delstruct(o); + + assert(o == null); + assert(innerDtors == 2); + assert(outerDtors == 1); +} diff --git a/src/object.d b/src/object.d index 3360eb92e8..95fb6eccd3 100644 --- a/src/object.d +++ b/src/object.d @@ -4637,6 +4637,8 @@ public import core.internal.array.construction : _d_arrayctor; public import core.internal.array.construction : _d_arraysetctor; public import core.internal.array.capacity: _d_arraysetlengthTImpl; +public import core.lifetime : _d_delstruct; + public import core.internal.dassert: _d_assert_fail; public import core.internal.destruction: __ArrayDtor;