From c42dbb9a4fb35f4514fa5297d8ced4815f65e7c1 Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Fri, 15 May 2015 03:01:44 +0200 Subject: [PATCH 1/2] make inclusive __xdtor accessible - needed for attribute correct destruction of structs and classes - same function as used by TypeInfo_Struct::xdtor --- src/clone.c | 22 +++++-- src/idgen.d | 3 + src/traits.c | 7 ++- test/compilable/extra-files/json.out | 4 ++ test/runnable/traits.d | 4 +- test/runnable/xdtor.d | 86 ++++++++++++++++++++++++++++ 6 files changed, 116 insertions(+), 10 deletions(-) create mode 100644 test/runnable/xdtor.d diff --git a/src/clone.c b/src/clone.c index 4dad9d57cd8a..9e6241250969 100644 --- a/src/clone.c +++ b/src/clone.c @@ -969,20 +969,22 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) if (e || (stc & STCdisable)) { //printf("Building __fieldDtor()\n"); - DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Identifier::idPool("__fieldDtor")); + DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__fieldDtor); dd->fbody = new ExpStatement(loc, e); ad->dtors.shift(dd); ad->members->push(dd); dd->semantic(sc); } + FuncDeclaration *xdtor = NULL; switch (ad->dtors.dim) { case 0: - return NULL; + break; case 1: - return ad->dtors[0]; + xdtor = ad->dtors[0]; + break; default: e = NULL; @@ -1001,12 +1003,22 @@ FuncDeclaration *buildDtor(AggregateDeclaration *ad, Scope *sc) ex = new CallExp(loc, ex); e = Expression::combine(ex, e); } - DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Identifier::idPool("__aggrDtor")); + DtorDeclaration *dd = new DtorDeclaration(declLoc, Loc(), stc, Id::__aggrDtor); dd->fbody = new ExpStatement(loc, e); ad->members->push(dd); dd->semantic(sc); - return dd; + xdtor = dd; + break; + } + // Add an __xdtor alias to make the inclusive dtor accessible + if (xdtor) + { + AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xdtor, xdtor); + alias->semantic(sc); + ad->members->push(alias); + alias->addMember(sc, ad); // add to symbol table } + return xdtor; } /****************************************** diff --git a/src/idgen.d b/src/idgen.d index cc8a24507448..6b3e128888b6 100644 --- a/src/idgen.d +++ b/src/idgen.d @@ -39,6 +39,9 @@ Msgtable[] msgtable = { "super" }, { "ctor", "__ctor" }, { "dtor", "__dtor" }, + { "__xdtor", "__xdtor" }, + { "__fieldDtor", "__fieldDtor" }, + { "__aggrDtor", "__aggrDtor" }, { "_postblit", "__postblit" }, { "classInvariant", "__invariant" }, { "unitTest", "__unitTest" }, diff --git a/src/traits.c b/src/traits.c index ba88578777ab..4ca3a4972fde 100644 --- a/src/traits.c +++ b/src/traits.c @@ -973,10 +973,11 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) //printf("\t[%i] %s %s\n", i, sm->kind(), sm->toChars()); if (sm->ident) { - if (sm->ident != Id::ctor && + if (sm->ident->string[0] == '_' && sm->ident->string[1] == '_' && + sm->ident != Id::ctor && sm->ident != Id::dtor && - sm->ident != Id::_postblit && - memcmp(sm->ident->string, "__", 2) == 0) + sm->ident != Id::__xdtor && + sm->ident != Id::_postblit) { return 0; } diff --git a/test/compilable/extra-files/json.out b/test/compilable/extra-files/json.out index 706a6e6b621f..b5b1dcd899d4 100644 --- a/test/compilable/extra-files/json.out +++ b/test/compilable/extra-files/json.out @@ -211,6 +211,10 @@ "overrides" : [ "json.Baz!(int, 2, null).Baz.t" ] + }, + { + "name" : "__xdtor", + "kind" : "alias" } ] }, diff --git a/test/runnable/traits.d b/test/runnable/traits.d index 934f68ad7f9e..7ed6ab834167 100644 --- a/test/runnable/traits.d +++ b/test/runnable/traits.d @@ -427,7 +427,7 @@ void test14() { auto a = [__traits(derivedMembers, D14)]; writeln(a); - assert(a == ["__ctor","__dtor","foo"]); + assert(a == ["__ctor","__dtor","foo", "__xdtor"]); } /********************************************************/ @@ -1254,7 +1254,7 @@ struct S10096X } static assert( [__traits(allMembers, S10096X)] == - ["str", "__ctor", "__postblit", "__dtor", "opAssign"]); + ["str", "__ctor", "__postblit", "__dtor", "__xdtor", "opAssign"]); // -------- diff --git a/test/runnable/xdtor.d b/test/runnable/xdtor.d new file mode 100644 index 000000000000..a3755617bc2e --- /dev/null +++ b/test/runnable/xdtor.d @@ -0,0 +1,86 @@ +// PERMUTE_ARGS: + +struct Field +{ + ~this() @safe @nogc pure nothrow {} +} + +struct Counter +{ + static size_t cnt; + ~this() @safe @nogc nothrow { ++cnt; } +} + +struct Foo +{ + ~this() @safe @nogc pure nothrow {} + Field field; +} + +class Bar +{ + ~this() @safe @nogc pure nothrow {} + Field field; +} + +void test1() @safe @nogc pure nothrow +{ + Foo foo; + foo.__xdtor(); + scope bar = new Bar(); + bar.__xdtor(); +} + +static assert(__traits(hasMember, Foo, "__xdtor")); +static assert(__traits(hasMember, Bar, "__xdtor")); + +// + +struct FieldDtor +{ + Counter counter; +} + +struct AggrDtor +{ + static size_t cnt; + ~this() @safe @nogc nothrow { ++cnt; } +} + +struct MixedDtor +{ + static size_t cnt; + Counter counter; + ~this() @safe @nogc nothrow { ++cnt; } +} + +struct SNoDtor {} +class CNoDtor {} + +static assert(!__traits(hasMember, SNoDtor, "__xdtor")); +static assert(!__traits(hasMember, CNoDtor, "__xdtor")); + +void test2() @safe @nogc nothrow +{ + FieldDtor a; + assert(Counter.cnt == 0); + a.__xdtor(); + assert(Counter.cnt == 1); + AggrDtor b; + assert(AggrDtor.cnt == 0); + b.__xdtor(); + assert(AggrDtor.cnt == 1); + Counter.cnt = 0; + MixedDtor c; + assert(MixedDtor.cnt == 0); + assert(Counter.cnt == 0); + c.__xdtor(); + assert(MixedDtor.cnt == 1); + assert(Counter.cnt == 1); +} + +void main() +{ + test1(); + test2(); +} From a6b73d22203ccac50681c7b5b581da81976441ff Mon Sep 17 00:00:00 2001 From: Martin Nowak Date: Fri, 15 May 2015 03:02:01 +0200 Subject: [PATCH 2/2] same same for postblit --- src/clone.c | 26 ++++++++--- src/func.c | 2 +- src/idgen.d | 6 ++- src/parse.c | 2 +- src/traits.c | 3 +- test/fail_compilation/fail4421.d | 3 +- test/runnable/traits.d | 2 +- test/runnable/xpostblit.d | 77 ++++++++++++++++++++++++++++++++ 8 files changed, 106 insertions(+), 15 deletions(-) create mode 100644 test/runnable/xpostblit.d diff --git a/src/clone.c b/src/clone.c index 9e6241250969..e48595c9fcb9 100644 --- a/src/clone.c +++ b/src/clone.c @@ -833,13 +833,13 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) ea = new CastExp(loc, ea, Type::tvoid->pointerTo()); Expression *et = getTypeInfo(v->type, sc); - et = new DotIdExp(loc, et, Id::postblit); + et = new DotIdExp(loc, et, Identifier::idPool("postblit")); ex = new CallExp(loc, et, ea); } a->push(new ExpStatement(loc, ex)); // combine in forward order /* Bugzilla 10972: When the following field postblit calls fail, - * this field should be destructed for Excetion Safety. + * this field should be destructed for Exception Safety. */ if (!sdv->dtor) continue; @@ -869,20 +869,22 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) if (a || (stc & STCdisable)) { //printf("Building __fieldPostBlit()\n"); - PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Identifier::idPool("__fieldPostBlit")); + PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__fieldPostblit); dd->fbody = a ? new CompoundStatement(loc, a) : NULL; sd->postblits.shift(dd); sd->members->push(dd); dd->semantic(sc); } + FuncDeclaration *xpostblit = NULL; switch (sd->postblits.dim) { case 0: - return NULL; + break; case 1: - return sd->postblits[0]; + xpostblit = sd->postblits[0]; + break; default: Expression *e = NULL; @@ -901,12 +903,22 @@ FuncDeclaration *buildPostBlit(StructDeclaration *sd, Scope *sc) ex = new CallExp(loc, ex); e = Expression::combine(e, ex); } - PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Identifier::idPool("__aggrPostBlit")); + PostBlitDeclaration *dd = new PostBlitDeclaration(declLoc, Loc(), stc, Id::__aggrPostblit); dd->fbody = new ExpStatement(loc, e); sd->members->push(dd); dd->semantic(sc); - return dd; + xpostblit = dd; + break; + } + // Add an __xpostblit alias to make the inclusive postblit accessible + if (xpostblit) + { + AliasDeclaration *alias = new AliasDeclaration(Loc(), Id::__xpostblit, xpostblit); + alias->semantic(sc); + sd->members->push(alias); + alias->addMember(sc, sd); // add to symbol table } + return xpostblit; } /***************************************** diff --git a/src/func.c b/src/func.c index 196afc978d3e..78021f59a2b7 100644 --- a/src/func.c +++ b/src/func.c @@ -4691,7 +4691,7 @@ void PostBlitDeclaration::semantic(Scope *sc) errors = true; return; } - if (ident == Id::_postblit && semanticRun < PASSsemantic) + if (ident == Id::postblit && semanticRun < PASSsemantic) ad->postblits.push(this); if (!type) type = new TypeFunction(NULL, Type::tvoid, false, LINKd, storage_class); diff --git a/src/idgen.d b/src/idgen.d index 6b3e128888b6..a16977503f7a 100644 --- a/src/idgen.d +++ b/src/idgen.d @@ -42,7 +42,10 @@ Msgtable[] msgtable = { "__xdtor", "__xdtor" }, { "__fieldDtor", "__fieldDtor" }, { "__aggrDtor", "__aggrDtor" }, - { "_postblit", "__postblit" }, + { "postblit", "__postblit" }, + { "__xpostblit", "__xpostblit" }, + { "__fieldPostblit", "__fieldPostblit" }, + { "__aggrPostblit", "__aggrPostblit" }, { "classInvariant", "__invariant" }, { "unitTest", "__unitTest" }, { "require", "__require" }, @@ -107,7 +110,6 @@ Msgtable[] msgtable = { "_arguments" }, { "_argptr" }, { "destroy" }, - { "postblit" }, { "xopEquals", "__xopEquals" }, { "xopCmp", "__xopCmp" }, { "xtoHash", "__xtoHash" }, diff --git a/src/parse.c b/src/parse.c index e04a7904f8c9..3f476f4901a3 100644 --- a/src/parse.c +++ b/src/parse.c @@ -1470,7 +1470,7 @@ Dsymbol *Parser::parseCtor(PrefixAttributes *pAttrs) if (stc & STCstatic) error(loc, "postblit cannot be static"); - PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::_postblit); + PostBlitDeclaration *f = new PostBlitDeclaration(loc, Loc(), stc, Id::postblit); if (pAttrs) pAttrs->storageClass = STCundefined; Dsymbol *s = parseContracts(f); diff --git a/src/traits.c b/src/traits.c index 4ca3a4972fde..cf6ecd9abaa7 100644 --- a/src/traits.c +++ b/src/traits.c @@ -977,7 +977,8 @@ Expression *semanticTraits(TraitsExp *e, Scope *sc) sm->ident != Id::ctor && sm->ident != Id::dtor && sm->ident != Id::__xdtor && - sm->ident != Id::_postblit) + sm->ident != Id::postblit && + sm->ident != Id::__xpostblit) { return 0; } diff --git a/test/fail_compilation/fail4421.d b/test/fail_compilation/fail4421.d index a691ab6b535f..1cd4961af47c 100644 --- a/test/fail_compilation/fail4421.d +++ b/test/fail_compilation/fail4421.d @@ -6,7 +6,7 @@ fail_compilation/fail4421.d(17): Error: destructor fail4421.U1.~this destructors fail_compilation/fail4421.d(18): Error: function fail4421.U1.__invariant1 destructors, postblits and invariants are not allowed in union U1 fail_compilation/fail4421.d(14): Error: function fail4421.U1.__invariant destructors, postblits and invariants are not allowed in union U1 fail_compilation/fail4421.d(28): Error: destructor fail4421.U2.~this destructors, postblits and invariants are not allowed in union U2 -fail_compilation/fail4421.d(28): Error: function fail4421.U2.__fieldPostBlit destructors, postblits and invariants are not allowed in union U2 +fail_compilation/fail4421.d(28): Error: function fail4421.U2.__fieldPostblit destructors, postblits and invariants are not allowed in union U2 fail_compilation/fail4421.d(33): Error: struct fail4421.S2 destructors, postblits and invariants are not allowed in overlapping fields s1 and j --- */ @@ -38,4 +38,3 @@ struct S2 int j; } } - diff --git a/test/runnable/traits.d b/test/runnable/traits.d index 7ed6ab834167..7e69371d2c0b 100644 --- a/test/runnable/traits.d +++ b/test/runnable/traits.d @@ -1254,7 +1254,7 @@ struct S10096X } static assert( [__traits(allMembers, S10096X)] == - ["str", "__ctor", "__postblit", "__dtor", "__xdtor", "opAssign"]); + ["str", "__ctor", "__postblit", "__dtor", "__xdtor", "__xpostblit", "opAssign"]); // -------- diff --git a/test/runnable/xpostblit.d b/test/runnable/xpostblit.d new file mode 100644 index 000000000000..b364c4cff63a --- /dev/null +++ b/test/runnable/xpostblit.d @@ -0,0 +1,77 @@ +// PERMUTE_ARGS: + +struct Field +{ + this(this) @safe @nogc pure nothrow {} +} + +struct Counter +{ + static size_t cnt; + this(this) @safe @nogc nothrow { ++cnt; } +} + +struct Foo +{ + this(this) @safe @nogc pure nothrow {} + Field field; +} + +void test1() @safe @nogc pure nothrow +{ + Foo foo; + foo.__xpostblit(); +} + +static assert(__traits(hasMember, Foo, "__xpostblit")); + +// + +struct FieldPostblit +{ + Counter counter; +} + +struct AggrPostblit +{ + static size_t cnt; + this(this) @safe @nogc nothrow { ++cnt; } +} + +struct MixedPostblit +{ + static size_t cnt; + Counter counter; + this(this) @safe @nogc nothrow { ++cnt; } +} + +struct SNoPostblit {} +class CNoPostblit {} + +static assert(!__traits(hasMember, SNoPostblit, "__xpostblit")); +static assert(!__traits(hasMember, CNoPostblit, "__xpostblit")); + +void test2() @safe @nogc nothrow +{ + FieldPostblit a; + assert(Counter.cnt == 0); + a.__xpostblit(); + assert(Counter.cnt == 1); + AggrPostblit b; + assert(AggrPostblit.cnt == 0); + b.__xpostblit(); + assert(AggrPostblit.cnt == 1); + Counter.cnt = 0; + MixedPostblit c; + assert(MixedPostblit.cnt == 0); + assert(Counter.cnt == 0); + c.__xpostblit(); + assert(MixedPostblit.cnt == 1); + assert(Counter.cnt == 1); +} + +void main() +{ + test1(); + test2(); +}