File: test14838.d

package info (click to toggle)
gcc-arm-none-eabi 15%3A12.2.rel1-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm
  • size: 959,712 kB
  • sloc: cpp: 3,275,382; ansic: 2,061,766; ada: 840,956; f90: 208,513; makefile: 76,132; asm: 73,433; xml: 50,448; exp: 34,146; sh: 32,436; objc: 15,637; fortran: 14,012; python: 11,991; pascal: 6,787; awk: 4,779; perl: 3,054; yacc: 338; ml: 285; lex: 201; haskell: 122
file content (91 lines) | stat: -rw-r--r-- 2,897 bytes parent folder | download | duplicates (7)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
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;
}