blob: 766406898e6d060881103f6d2b86b43d8231f60a [file] [log] [blame]
// 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;
}