| // PERMUTE_ARGS: |
| |
| struct A(T) { ~this() {} } |
| class C { A!int[1] array; } |
| |
| void test14838() pure nothrow @nogc @safe |
| { |
| C c; |
| c.__xdtor(); // C.~this() will also be inferred to |
| // pure nothrow @nogc @safe |
| |
| A!int[1] array; |
| // scope destructor call does not cause attribute violation. |
| } |
| |
| // ---- |
| |
| /* |
| * This is a reduced test case comes from std.container.Array template, |
| * to fix the semantic analysis order issue for correct destructor attribute inference. |
| * |
| * Before the bugfix: |
| * 1. StructDeclaration('Array!int').semantic() instantiates |
| * RangeT!(Array!int) at the `alias Range = ...;`, but |
| * StructDeclaration('RangeT!(Array!int)').semantic() exits |
| * with sizeok == SIZEOKfwd, because the size of _outer_ field is not yet determined. |
| * 2. StructDeclaration('Array!int').semantic() succeeds to determine the size |
| * (sizeok = SIZEOKdone). |
| * 3. StructDeclaration('Array!int').buildOpAssign() will generate opAssign because |
| * Array!int._data field has identity opAssign member function. |
| * 4. The semantic3 will get called for the generated opAssign, then |
| * 6-1. Array!int.~this() semantic3, and |
| * 6-2. RefCounted!(Array!int.Payload).~this() semantic3 |
| * will also get called to infer their attributes. |
| * 5. In RefCounted!(Array!int.Payload).~this(), destroy(t) will be instantiated. |
| * At that, TemplateInstance.expandMembers() will invoke runDeferredSemantic() |
| * and it will re-run StructDeclaration('RangeT!(Array!int)').semantic(). |
| * 6. StructDeclaration('RangeT!(Array!int)').semantic() determines the size |
| * (sizeok = SIZEOKdone). Then, it will generate identity opAssign and run its semantic3. |
| * It will need to infer RangeT!(Array!int).~this() attribute, then it requires the |
| * correct attribute of Array!int.~this(). |
| * |
| * However, the Array!int.~this() attribute is not yet determined! [bug] |
| * -> it's wongly handled as impure/system/throwable/gc-able. |
| * |
| * -> then, the attribute inference results for |
| * RangeT!(Array!int).~this() and Array!int.~this() will be incorrect. |
| * |
| * After the bugfix: |
| * In 6, StructDeclaration('RangeT!(Array!int)').semantic() will check that: |
| * all base struct types of the instance fields have completed addition of |
| * special functions (dtor, opAssign, etc). |
| * If not, it will defer the completion of its semantic pass. |
| */ |
| |
| void destroy14838(S)(ref S s) if (is(S == struct)) |
| { |
| s.__xdtor(); |
| } |
| |
| struct RefCounted14838(T) |
| { |
| ~this() |
| { |
| T t; |
| .destroy14838(t); |
| } |
| |
| void opAssign(typeof(this) rhs) {} |
| } |
| |
| struct RangeT14838(A) |
| { |
| A[1] _outer_; |
| } |
| |
| struct Array14838(T) |
| { |
| struct Payload |
| { |
| ~this() {} |
| } |
| RefCounted14838!Payload _data; |
| |
| alias Range = RangeT14838!Array14838; |
| } |
| |
| class Test14838 |
| { |
| Array14838!int[1] field; |
| } |