|
|
@@ -0,0 +1,91 @@ |
|
|
// 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; |
|
|
} |