aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gdc.test/compilable/test7815.d
blob: 405d9fc9d90426cd21f16e6c36b2190405e7a364 (plain)
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
// REQUIRED_ARGS: -o-
/*
TEST_OUTPUT:
---
---
*/

mixin template Helpers()
{
    static if (is(Flags!Move))
    {
        Flags!Move flags;
    }
    else
    {
        pragma(msg, "X: ", __traits(derivedMembers, Flags!Move));
    }
}

template Flags(T)
{
    mixin({
        int defs = 1;
        foreach (name; __traits(derivedMembers, Move))
        {
            defs++;
        }
        if (defs)
        {
            return "struct Flags { bool x; }";
        }
        else
        {
            return "";
        }
    }());
}

struct Move
{
    int a;
    mixin Helpers!();
}

enum a7815 = Move.init.flags;

/+
This originally was an invalid case:
When the Move struct member is analyzed:
1. mixin Helpers!() is instantiated.
2. In Helpers!(), static if and its condition is(Flags!Move)) evaluated.
3. In Flags!Move, string mixin evaluates and CTFE lambda.
4. __traits(derivedMembers, Move) tries to see the member of Move.
   4a. mixin Helpers!() member is analyzed.
   4b. `static if (is(Flags!Move))` in Helpers!() is evaluated
   4c. The Flags!Move instantiation is already in progress, so it cannot be resolved.
   4d. `static if` fails because Flags!Move cannot be determined as a type.
5. __traits(derivedMembers, Move) returns a 1-length tuple("a").
6. The lambda in Flags!Move returns a string "struct Flags {...}", then
   Flags!Move is instantiated to a new struct Flags.
7. Finally Move struct does not have flags member, then the `enum a7815`
   definition will fail in its initializer.

Now, static if will behave like a string mixin: it is invisible during its own expansion.
+/