summaryrefslogtreecommitdiff
path: root/clang/test/CXX/temp/temp.decls/temp.class/temp.mem.enum/p1.cpp
blob: f8cc00947480b59af9101030ae054f220a4fbdc5 (about) (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
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
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
// RUN: %clang_cc1 -std=c++11 -verify %s

template<typename T> struct A {
  enum E : T; // expected-note {{here}}
  E v;
  E f() { return A::e1; } // expected-error {{no member named 'e1' in 'A<T>'}}
  E g() { return E::e1; }
  E h();
};

A<int> a;
A<int>::E a0 = A<int>().v;
int n = A<int>::E::e1; // expected-error {{implicit instantiation of undefined member}}

template<typename T> enum A<T>::E : T { e1, e2 };

// FIXME: Now that A<T>::E is defined, we are supposed to inject its enumerators
// into the already-instantiated class A<T>. This seems like a really bad idea,
// though, so we don't implement that, but what we do implement is inconsistent.
//
// Either do as the standard says, or only include enumerators lexically defined
// within the class in its scope.
A<int>::E a1 = A<int>::e1; // expected-error {{no member named 'e1' in 'A<int>'}}

A<char>::E a2 = A<char>::e2;

template<typename T> typename A<T>::E A<T>::h() { return e2; }
A<short>::E a3 = A<short>().h();


template<typename T> struct B {
  enum class E;
  E v;
  E f() { return E::e1; }
  E g();
};

B<int> b;
B<int>::E b0 = B<int>().v;

template<typename T> enum class B<T>::E { e1, e2 };
B<int>::E b1 = B<int>::E::e1;

B<char>::E b2 = B<char>::E::e2;

template<typename T> typename B<T>::E B<T>::g() { return e2; }
B<short>::E b3 = B<short>().g();


// Enumeration members of class templates can be explicitly specialized. For
// unscoped enumerations, specializations must be defined before the primary
// template is, since otherwise the primary template will be implicitly
// instantiated when we parse the nested name specifier.
template<> enum A<long long>::E : long long { e3, e4 }; // expected-error {{explicit specialization of 'E' after instantiation}} expected-note {{first required here}}

template<> enum class B<long long>::E { e3, e4 };
B<long long>::E b4 = B<long long>::E::e4;

B<long>::E b5;
template<> enum class B<long>::E { e5 };
void fb5() { b5 = decltype(b5)::e5; }
B<long>::E b6 = B<long>::E::e5;


template<typename T> struct C {
  enum class E : T;
};

template<> enum class C<long long>::E : long long { e3, e4 };
C<long long>::E c0 = C<long long>::E::e3;

C<long>::E c1;
template<> enum class C<long>::E : long { e5 };
void fc1() { c1 = decltype(c1)::e5; }
C<long>::E c2 = C<long>::E::e5;

template<> enum class C<int>::E : int { e6 };
template<typename T> enum class C<T>::E : T { e0 };
C<int>::E c3 = C<int>::E::e6;
C<int>::E c4 = C<int>::E::e0; // expected-error {{no member named 'e0' in 'C<int>::E'}}


// Enumeration members can't be partially-specialized.
template<typename T> enum class B<T*>::E { e5, e6 }; // expected-error {{nested name specifier for a declaration cannot depend on a template parameter}}


// Explicit specializations can be forward-declared.
template<typename T>
struct D {
  enum class E { e1 };
};
template<> enum class D<int>::E;
D<int>::E d1 = D<int>::E::e1; // expected-error {{incomplete type 'D<int>::E'}}
template<> enum class D<int>::E { e2 };
D<int>::E d2 = D<int>::E::e2;
D<char>::E d3 = D<char>::E::e1; // expected-note {{first required here}}
D<char>::E d4 = D<char>::E::e2; // expected-error {{no member named 'e2'}}
template<> enum class D<char>::E { e3 }; // expected-error {{explicit specialization of 'E' after instantiation}}

template<> enum class D<short>::E;
struct F {
  // Per C++11 [class.friend]p3, these friend declarations have no effect.
  // Only classes and functions can be friends.
  template<typename T> friend enum D<T>::E;
  template<> friend enum D<short>::E;

  template<> friend enum D<double>::E { e3 }; // expected-error {{cannot define a type in a friend declaration}}

private:
  static const int n = 1; // expected-note {{private here}}
};
template<> enum class D<short>::E {
  e = F::n // expected-error {{private member}}
};

class Access {
  friend class X;

  template<typename T>
  class Priv {
    friend class X;

    enum class E : T;
  };

  class S {
    typedef int N; // expected-note {{here}}
    static const int k = 3; // expected-note {{here}}

    friend class Priv<char>;
  };

  static const int k = 5;
};

template<> enum class Access::Priv<Access::S::N>::E
  : Access::S::N { // expected-error {{private member}}
  a = Access::k, // ok
  b = Access::S::k // expected-error {{private member}}
};

template<typename T> enum class Access::Priv<T>::E : T {
  c = Access::k,
  d = Access::S::k
};

class X {
  Access::Priv<int>::E a = Access::Priv<int>::E::a;
  Access::Priv<char>::E c = Access::Priv<char>::E::d;
  // FIXME: We should see an access error for this enumerator.
  Access::Priv<short>::E b = Access::Priv<short>::E::d;
};