]>
Commit | Line | Data |
---|---|---|
b4c522fa IB |
1 | // PERMUTE_ARGS: |
2 | ||
3 | struct A(T) { ~this() {} } | |
4 | class C { A!int[1] array; } | |
5 | ||
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 | ||
61 | struct RefCounted14838(T) | |
62 | { | |
63 | ~this() | |
64 | { | |
65 | T t; | |
66 | .destroy14838(t); | |
67 | } | |
68 | ||
69 | void opAssign(typeof(this) rhs) {} | |
70 | } | |
71 | ||
72 | struct RangeT14838(A) | |
73 | { | |
74 | A[1] _outer_; | |
75 | } | |
76 | ||
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 | } |