217 lines · cpp
1// RUN: %clang_cc1 -std=c++11 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify2// RUN: %clang_cc1 -std=c++14 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify3// RUN: %clang_cc1 -std=c++20 -Wredeclared-class-member -Wconstant-conversion -Wdeprecated-declarations -Wc++11-narrowing -fsyntax-only %s -verify4 5// Test that opaque-enum-declarations are handled correctly w.r.t integral promotions.6// The key sections in the C++11 standard are:7// C++11 [dcl.enum]p3: An enumeration declared by an opaque-enum-declaration8// has a fixed underlying type and is a complete type.9// C++11 [conv.prom]: A prvalue of an unscoped enumeration type whose underlying type10// is fixed ([dcl.enum]) can be converted to a prvalue of its underlying type.11 12// This program causes clang 19 and earlier to crash because13// EnumDecl::PromotionType has not been set on the instantiated enum.14// See GitHub Issue #117960.15namespace Issue117960 {16template <typename T>17struct A {18 enum E : T;19};20 21int b = A<int>::E{} + 0;22}23 24 25namespace test {26template <typename T1, typename T2>27struct IsSame {28 static constexpr bool check() { return false; }29};30 31template <typename T>32struct IsSame<T, T> {33 static constexpr bool check() { return true; }34};35} // namespace test36 37 38template <typename T>39struct S1 {40 enum E : T;41};42// checks if EnumDecl::PromotionType is set43int X1 = S1<int>::E{} + 0;44int Y1 = S1<unsigned>::E{} + 0;45static_assert(test::IsSame<decltype(S1<int>::E{}+0), int>::check(), "");46static_assert(test::IsSame<decltype(S1<unsigned>::E{}+0), unsigned>::check(), "");47char Z1 = S1<unsigned>::E(-1) + 0; // expected-warning{{implicit conversion from 'unsigned int' to 'char'}}48 49template <typename Traits>50struct S2 {51 enum E : typename Traits::IntegerType;52};53 54template <typename T>55struct Traits {56 typedef T IntegerType;57};58 59int X2 = S2<Traits<int>>::E{} + 0;60int Y2 = S2<Traits<unsigned>>::E{} + 0;61static_assert(test::IsSame<decltype(S2<Traits<int>>::E{}+0), int>::check(), "");62static_assert(test::IsSame<decltype(S2<Traits<unsigned>>::E{}+0), unsigned>::check(), "");63// C++11 [conv.prom]p4:64// A prvalue of an unscoped enumeration type whose underlying type is fixed can be converted to a65// prvalue of its underlying type. Moreover, if integral promotion can be applied to its underlying type, a66// prvalue of an unscoped enumeration type whose underlying type is fixed can also be converted to a prvalue67// of the promoted underlying type.68static_assert(test::IsSame<decltype(S2<Traits<char>>::E{}+char(0)), int>::check(), "");69 70 71template <typename T>72struct S3 {73 enum E : unsigned;74};75 76int X3 = S3<float>::E{} + 0;77 78// fails in clang 19 and earlier (see the discussion on GitHub Issue #117960):79static_assert(test::IsSame<decltype(S3<float>::E{}+0), unsigned>::check(), "");80 81template <typename T>82struct S4 {83 enum E1 : char;84 enum E2 : T;85};86 87int X4 = S4<char>::E1{} + '\0';88int Y4 = S4<char>::E2{} + '\0';89 90template <typename T>91struct S5 {92 enum class E1 : char;93 enum class E2 : T;94};95 96int X5 = S5<char>::E1{} + '\0'; // expected-error{{invalid operands to binary expression}}97 // expected-note@-1{{no implicit conversion for scoped enum; consider casting to underlying type}}98int Y5 = S5<char>::E2{} + '\0'; // expected-error{{invalid operands to binary expression}}99 // expected-note@-1{{no implicit conversion for scoped enum; consider casting to underlying type}}100 101 102template <typename T>103struct S6 {104 enum E1 : T;105 enum E2 : E1; // expected-error{{invalid underlying type}}106};107 108template struct S6<int>; // expected-note{{in instantiation of template class 'S6<int>' requested here}}109 110 111template <typename T>112struct S7 {113 enum E : T;114 enum E : T { X, Y, Z }; // expected-note{{previous declaration is here}}115 enum E : T; // expected-warning{{class member cannot be redeclared}}116};117 118template struct S7<int>;119 120template <typename T>121struct S8 {122 enum E : char;123 enum E : char { X, Y, Z }; // expected-note{{previous declaration is here}}124 enum E : char; // expected-warning{{class member cannot be redeclared}}125};126 127template struct S8<float>;128 129template <typename T>130struct S9 {131 enum class E1 : T;132 enum class E1 : T { X, Y, Z }; // expected-note{{previous declaration is here}}133 enum class E1 : T; // expected-warning{{class member cannot be redeclared}}134 enum class E2 : char;135 enum class E2 : char { X, Y, Z }; // expected-note{{previous declaration is here}}136 enum class E2 : char; // expected-warning{{class member cannot be redeclared}}137};138 139template struct S9<int>;140 141#if defined(__cplusplus) && __cplusplus >= 201402L142template <typename T>143struct S10 {144 enum [[deprecated("for reasons")]] E : T; // expected-note{{explicitly marked deprecated here}}145};146 147int X10 = S10<int>::E{} + 0; // expected-warning{{deprecated: for reasons}}148#endif149 150template <typename T>151struct S11 {};152 153template <>154struct S11<unsigned> {155 enum E : unsigned;156};157 158unsigned X11 = S11<unsigned>::E{} + 0u;159 160#if defined(__cplusplus) && __cplusplus >= 201402L161template <typename T>162struct S12 {163 enum [[deprecated("for reasons")]] E1 : T; // expected-note{{explicitly marked deprecated here}}164 enum [[deprecated("for reasons")]] E2 : T;165};166 167template <>168struct S12<float> {169 enum E1 : unsigned;170 enum E2 : unsigned;171};172 173unsigned X12 = S12<float>::E1{} + 0u;174unsigned Y12 = S12<float>::E2{} + 0u;175int Z12 = S12<int>::E1{} + 0; // expected-warning{{deprecated: for reasons}}176#endif177 178template <typename T>179struct S13 {180 enum __attribute__((packed)) E { X, Y };181};182 183static_assert(sizeof(S13<int>::E) == 1, "");184 185template<typename T>186struct S14 {187 enum E : float; // expected-error {{invalid underlying type}}188};189 190template<typename T>191struct S15 {192 enum E : T; // expected-error {{invalid underlying type}}193};194 195template struct S15<float>; // expected-note {{in instantiation of template class 'S15<float>' requested here}}196 197 198 199 200template <typename T>201int f1() {202 enum E : T;203 return E{} + 0;204}205 206int F1 = f1<int>();207 208template <typename T>209int f2() {210 struct LocalClass {211 enum E : T;212 };213 return typename LocalClass::E{} + 0;214}215 216int F2 = f2<int>();217