1 // PERMUTE_ARGS:
2 
A(T)3 struct A(T) { ~this() {} }
4 class C { A!int[1] array; }
5 
test14838()6 void test14838() pure nothrow @nogc @safe
7 {
8     C c;
9     c.__xdtor();    // C.~this() will also be inferred to
10                     // pure nothrow @nogc @safe
11 
12     A!int[1] array;
13     // scope destructor call does not cause attribute violation.
14 }
15 
16 // ----
17 
18 /*
19  * This is a reduced test case comes from std.container.Array template,
20  * to fix the semantic analysis order issue for correct destructor attribute inference.
21  *
22  * Before the bugfix:
23  *   1. StructDeclaration('Array!int').semantic() instantiates
24  *      RangeT!(Array!int) at the `alias Range = ...;`, but
25  *      StructDeclaration('RangeT!(Array!int)').semantic() exits
26  *      with sizeok == SIZEOKfwd, because the size of _outer_ field is not yet determined.
27  *   2. StructDeclaration('Array!int').semantic() succeeds to determine the size
28  *      (sizeok = SIZEOKdone).
29  *   3. StructDeclaration('Array!int').buildOpAssign() will generate opAssign because
30  *      Array!int._data field has identity opAssign member function.
31  *   4. The semantic3 will get called for the generated opAssign, then
32  *         6-1. Array!int.~this() semantic3, and
33  *         6-2. RefCounted!(Array!int.Payload).~this() semantic3
34  *      will also get called to infer their attributes.
35  *   5. In RefCounted!(Array!int.Payload).~this(), destroy(t) will be instantiated.
36  *      At that, TemplateInstance.expandMembers() will invoke runDeferredSemantic()
37  *      and it will re-run StructDeclaration('RangeT!(Array!int)').semantic().
38  *   6. StructDeclaration('RangeT!(Array!int)').semantic() determines the size
39  *      (sizeok = SIZEOKdone). Then, it will generate identity opAssign and run its semantic3.
40  *      It will need to infer RangeT!(Array!int).~this() attribute, then it requires the
41  *      correct attribute of Array!int.~this().
42  *
43  *      However, the Array!int.~this() attribute is not yet determined! [bug]
44  *      -> it's wongly handled as impure/system/throwable/gc-able.
45  *
46  *      -> then, the attribute inference results for
47  *         RangeT!(Array!int).~this() and Array!int.~this() will be incorrect.
48  *
49  * After the bugfix:
50  *   In 6, StructDeclaration('RangeT!(Array!int)').semantic() will check that:
51  *   all base struct types of the instance fields have completed addition of
52  *   special functions (dtor, opAssign, etc).
53  *   If not, it will defer the completion of its semantic pass.
54  */
55 
56 void destroy14838(S)(ref S s) if (is(S == struct))
57 {
58     s.__xdtor();
59 }
60 
RefCounted14838(T)61 struct RefCounted14838(T)
62 {
63     ~this()
64     {
65         T t;
66         .destroy14838(t);
67     }
68 
69     void opAssign(typeof(this) rhs) {}
70 }
71 
RangeT14838(A)72 struct RangeT14838(A)
73 {
74     A[1] _outer_;
75 }
76 
Array14838(T)77 struct Array14838(T)
78 {
79     struct Payload
80     {
81         ~this() {}
82     }
83     RefCounted14838!Payload _data;
84 
85     alias Range = RangeT14838!Array14838;
86 }
87 
88 class Test14838
89 {
90     Array14838!int[1] field;
91 }
92