David Blaikie 83225936af PR51158: Don't emit -Wswitch or -Wcovered-switch-default for empty enums
An empty enum is used to implement C++'s new-ish "byte" type (to make
sure it's a separate type for overloading, etc - compared to a typedef)
- without any enumerators. Some clang warnings don't make sense in this
sort of situation, so let's skip them for empty enums.

It's arguable that possibly some situations of enumerations without
enumerators might want the previous-to-this-patch behavior (if the enum
is autogenerated and in some cases comes up empty, then maybe a default
in an empty switch would still be considered problematic - so that when
you add the first enumeration you do get a -Wswitch warning). But I
think that's niche enough & this std::byte case is mainstream enough
that we should prioritize the latter over the former.

If someone's got a middle ground proposal to account for both of those
situations, I'm open to patches/suggestions/etc.
2021-07-22 14:51:56 -07:00

149 lines
3.1 KiB
C++

// RUN: %clang_cc1 -fsyntax-only -verify -std=c++11 %s
void test() {
bool x = true;
switch (x) { // expected-warning {{bool}}
case 0:
break;
}
int n = 3;
switch (n && true) { // expected-warning {{bool}}
case 1:
break;
}
}
// PR5518
struct A {
operator int(); // expected-note{{conversion to integral type}}
};
void x() {
switch(A()) {
}
}
enum E { e1, e2 };
struct B : A {
operator E() const; // expected-note{{conversion to enumeration type}}
};
void x2() {
switch (B()) { // expected-error{{multiple conversions}}
}
}
struct C; // expected-note{{forward declaration}}
void x3(C &c) {
switch (c) { // expected-error{{incomplete class type}}
}
}
namespace test3 {
enum En { A, B, C };
template <En how> void foo() {
int x = 0, y = 5;
switch (how) { //expected-warning {{no case matching constant switch condition '2'}}
case A: x *= y; break;
case B: x += y; break;
// No case for C, but it's okay because we have a constant condition.
}
}
template void foo<A>();
template void foo<B>();
template void foo<C>(); //expected-note {{in instantiation}}
}
// PR9304 and rdar://9045501
void click_check_header_sizes() {
switch (0 == 8) { // expected-warning {{switch condition has boolean value}}
case 0: ;
}
}
void local_class(int n) {
for (;;) switch (n) {
case 0:
struct S {
void f() {
case 1: // expected-error {{'case' statement not in switch statement}}
break; // expected-error {{'break' statement not in loop or switch statement}}
default: // expected-error {{'default' statement not in switch statement}}
continue; // expected-error {{'continue' statement not in loop statement}}
}
};
S().f();
[]{
case 2: // expected-error {{'case' statement not in switch statement}}
break; // expected-error {{'break' statement not in loop or switch statement}}
default: // expected-error {{'default' statement not in switch statement}}
continue; // expected-error {{'continue' statement not in loop statement}}
}();
}
}
namespace Conversion {
struct S {
explicit operator int(); // expected-note {{conversion}}
};
template<typename T> void f(T t) {
switch (t) { // expected-error {{explicit conversion}}
case 0:
return;
default:
break;
}
}
template void f(S); // expected-note {{instantiation of}}
}
// rdar://29230764
namespace OpaqueEnumWarnings {
enum Opaque : int;
enum class OpaqueClass : int;
enum class Defined : int;
enum class Defined : int { a };
void test(Opaque o, OpaqueClass oc, Defined d) {
// Don't warn that case value is not present in opaque enums.
switch (o) {
case (Opaque)1:
break;
}
switch (oc) {
case (OpaqueClass)1:
break;
}
switch (d) {
case Defined::a:
break;
case (Defined)2: // expected-warning {{case value not in enumerated type 'OpaqueEnumWarnings::Defined'}}
break;
}
}
}
namespace EmptyEnum {
enum Empty : int {};
void test(Empty e) {
switch (e) {
case (Empty)0:
break;
}
switch (e) {
default:
break;
}
}
} // namespace EmptyEnum