(root)/
gcc-13.2.0/
gcc/
testsuite/
gdc.test/
compilable/
test14838.d
// 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;
}