| // 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); |
| } |
| |
| /**************************************************************** |
| This test is intended to verify the exception safety of field |
| postblits |
| */ |
| string trace = ""; |
| |
| struct FieldThrow |
| { |
| string name; |
| this(string n) |
| { |
| name = n; |
| } |
| |
| bool throwExcept; |
| this(this) |
| { |
| if (throwExcept) |
| { |
| throw new Exception(""); |
| } |
| } |
| |
| ~this() { trace ~= name ~ ".dtor"; } |
| } |
| |
| struct S |
| { |
| auto f1 = FieldThrow("f1"); |
| FieldThrow[2] f2f3= [FieldThrow("f2"), FieldThrow("f3")]; |
| auto f4 = FieldThrow("f4"); |
| } |
| |
| void test3() |
| { |
| trace = ""; |
| |
| S s1; |
| |
| // Cause `s1.f4`'s postblit to throw |
| s1.f4.throwExcept = true; |
| |
| try |
| { |
| // `s`'s postblit will be a combination of `f1`, `f2f3`, and `f4`'s |
| // postblit in that order. However, `f4`'s postblit will throw, |
| // causing `s1.f2f3` and `s1.f1`'s destructors to execute in that |
| // order |
| S s2 = s1; |
| } |
| catch(Exception ex){ } |
| |
| // Confirm the field destructors were called and were called in the |
| // corrrect order |
| assert(trace == "f3.dtor" ~ "f2.dtor" ~ "f1.dtor"); |
| } |
| /****************************************************************************/ |
| |
| void main() |
| { |
| test1(); |
| test2(); |
| test3(); |
| } |