File: opaque-enum-declaration-in-class-template.cpp

package info (click to toggle)
llvm-toolchain-20 1%3A20.1.8-1~exp1
  • links: PTS, VCS
  • area: main
  • in suites: experimental
  • size: 2,111,388 kB
  • sloc: cpp: 7,438,767; ansic: 1,393,871; asm: 1,012,926; python: 241,728; f90: 86,635; objc: 75,411; lisp: 42,144; pascal: 17,286; sh: 10,027; ml: 5,082; perl: 4,730; awk: 3,523; makefile: 3,349; javascript: 2,251; xml: 892; fortran: 672
file content (214 lines) | stat: -rw-r--r-- 5,986 bytes parent folder | download | duplicates (6)
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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
// RUN: %clang_cc1 -std=c++11 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify
// RUN: %clang_cc1 -std=c++14 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify
// RUN: %clang_cc1 -std=c++20 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify

// Test that opaque-enum-declarations are handled correctly w.r.t integral promotions.
// The key sections in the C++11 standard are:
// C++11 [dcl.enum]p3: An enumeration declared by an opaque-enum-declaration
// has a fixed underlying type and is a complete type.
// C++11 [conv.prom]: A prvalue of an unscoped enumeration type whose underlying type
// is fixed ([dcl.enum]) can be converted to a prvalue of its underlying type.

// This program causes clang 19 and earlier to crash because
// EnumDecl::PromotionType has not been set on the instantiated enum.
// See GitHub Issue #117960.
namespace Issue117960 {
template <typename T>
struct A {
  enum E : T;
};

int b = A<int>::E{} + 0;
}


namespace test {
template <typename T1, typename T2>
struct IsSame {
  static constexpr bool check() { return false; }
};

template <typename T>
struct IsSame<T, T> {
  static constexpr bool check() { return true; }
};
}  // namespace test


template <typename T>
struct S1 {
  enum E : T;
};
// checks if EnumDecl::PromotionType is set
int X1 = S1<int>::E{} + 0;
int Y1 = S1<unsigned>::E{} + 0;
static_assert(test::IsSame<decltype(S1<int>::E{}+0), int>::check(), "");
static_assert(test::IsSame<decltype(S1<unsigned>::E{}+0), unsigned>::check(), "");
char Z1 = S1<unsigned>::E(-1) + 0; // expected-warning{{implicit conversion from 'unsigned int' to 'char'}}

template <typename Traits>
struct S2 {
  enum E : typename Traits::IntegerType;
};

template <typename T>
struct Traits {
  typedef T IntegerType;
};

int X2 = S2<Traits<int>>::E{} + 0;
int Y2 = S2<Traits<unsigned>>::E{} + 0;
static_assert(test::IsSame<decltype(S2<Traits<int>>::E{}+0), int>::check(), "");
static_assert(test::IsSame<decltype(S2<Traits<unsigned>>::E{}+0), unsigned>::check(), "");
// C++11 [conv.prom]p4:
// A prvalue of an unscoped enumeration type whose underlying type is fixed can be converted to a
// prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a
// prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue
// of the promoted underlying type.
static_assert(test::IsSame<decltype(S2<Traits<char>>::E{}+char(0)), int>::check(), "");


template <typename T>
struct S3 {
  enum E : unsigned;
};

int X3 = S3<float>::E{} + 0;

// fails in clang 19 and earlier (see the discussion on GitHub Issue #117960):
static_assert(test::IsSame<decltype(S3<float>::E{}+0), unsigned>::check(), "");

template <typename T>
struct S4 {
  enum E1 : char;
  enum E2 : T;
};

int X4 = S4<char>::E1{} + '\0';
int Y4 = S4<char>::E2{} + '\0';

template <typename T>
struct S5 {
  enum class E1 : char;
  enum class E2 : T;
};

int X5 = S5<char>::E1{} + '\0'; // expected-error{{invalid operands to binary expression}}
int Y5 = S5<char>::E2{} + '\0'; // expected-error{{invalid operands to binary expression}}


template <typename T>
struct S6 {
  enum E1 : T;
  enum E2 : E1; // expected-error{{invalid underlying type}}
};

template struct S6<int>; // expected-note{{in instantiation of template class 'S6<int>' requested here}}


template <typename T>
struct S7 {
  enum E : T;
  enum E : T { X, Y, Z }; // expected-note{{previous declaration is here}}
  enum E : T; // expected-warning{{class member cannot be redeclared}}
};

template struct S7<int>;

template <typename T>
struct S8 {
  enum E : char;
  enum E : char { X, Y, Z }; // expected-note{{previous declaration is here}}
  enum E : char; // expected-warning{{class member cannot be redeclared}}
};

template struct S8<float>;

template <typename T>
struct S9 {
  enum class E1 : T;
  enum class E1 : T { X, Y, Z }; // expected-note{{previous declaration is here}}
  enum class E1 : T; // expected-warning{{class member cannot be redeclared}}
  enum class E2 : char;
  enum class E2 : char { X, Y, Z }; // expected-note{{previous declaration is here}}
  enum class E2 : char; // expected-warning{{class member cannot be redeclared}}
};

template struct S9<int>;

#if defined(__cplusplus) && __cplusplus >= 201402L
template <typename T>
struct S10 {
  enum [[deprecated("for reasons")]] E : T; // expected-note{{explicitly marked deprecated here}}
};

int X10 = S10<int>::E{} + 0; // expected-warning{{deprecated: for reasons}}
#endif

template <typename T>
struct S11 {};

template <>
struct S11<unsigned> {
  enum E : unsigned;
};

unsigned X11 = S11<unsigned>::E{} + 0u;

#if defined(__cplusplus) && __cplusplus >= 201402L
template <typename T>
struct S12 {
  enum [[deprecated("for reasons")]] E1 : T; // expected-note{{explicitly marked deprecated here}}
  enum [[deprecated("for reasons")]] E2 : T;
};

template <>
struct S12<float> {
  enum E1 : unsigned;
  enum E2 : unsigned;
};

unsigned X12 = S12<float>::E1{} + 0u;
unsigned Y12 = S12<float>::E2{} + 0u;
int Z12 = S12<int>::E1{} + 0; // expected-warning{{deprecated: for reasons}}
#endif

template <typename T>
struct S13 {
  enum __attribute__((packed)) E { X, Y };
};

static_assert(sizeof(S13<int>::E) == 1, "");

template<typename T>
struct S14 {
  enum E : float; // expected-error {{invalid underlying type}}
};

template<typename T>
struct S15 {
  enum E : T; // expected-error {{invalid underlying type}}
};

template struct S15<float>; // expected-note {{in instantiation of template class 'S15<float>' requested here}}




template <typename T>
int f1() {
  enum E : T;
  return E{} + 0;
}

int F1 = f1<int>();

template <typename T>
int f2() {
  struct LocalClass {
    enum E : T;
  };
  return typename LocalClass::E{} + 0;
}

int F2 = f2<int>();