From 371e9e8a28517f4da559fed3d44877a5a1b3e785 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 6 Dec 2017 03:00:51 +0000 Subject: [PATCH] Fix a bunch of wrong "tautological unsigned enum compare" diagnostics in C++. An enumeration with a fixed underlying type can have any value in its underlying type, not just those spanned by the values of its enumerators. llvm-svn: 319875 --- clang/lib/Sema/SemaChecking.cpp | 7 +-- ...autological-unsigned-enum-zero-compare.cpp | 53 ++++++++++--------- 2 files changed, 33 insertions(+), 27 deletions(-) diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index e23db3e6eea9..184f98d28765 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -8260,11 +8260,12 @@ struct IntRange { } else if (const EnumType *ET = dyn_cast(T)) { // For enum types in C++, use the known bit width of the enumerators. EnumDecl *Enum = ET->getDecl(); - // In C++11, enums without definitions can have an explicitly specified - // underlying type. Use this type to compute the range. - if (!Enum->isCompleteDefinition()) + // In C++11, enums can have a fixed underlying type. Use this type to + // compute the range. + if (Enum->isFixed()) { return IntRange(C.getIntWidth(QualType(T, 0)), !ET->isSignedIntegerOrEnumerationType()); + } unsigned NumPositive = Enum->getNumPositiveBits(); unsigned NumNegative = Enum->getNumNegativeBits(); diff --git a/clang/test/Sema/tautological-unsigned-enum-zero-compare.cpp b/clang/test/Sema/tautological-unsigned-enum-zero-compare.cpp index f8d4560ef21d..5577b68b5ebd 100644 --- a/clang/test/Sema/tautological-unsigned-enum-zero-compare.cpp +++ b/clang/test/Sema/tautological-unsigned-enum-zero-compare.cpp @@ -2,11 +2,11 @@ // RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s // RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSILENCE -Wno-tautological-unsigned-enum-zero-compare -verify %s -// Okay, this is where it gets complicated. -// Then default enum sigdness is target-specific. -// On windows, it is signed by default. We do not want to warn in that case. - int main() { + // On Windows, all enumerations have a fixed underlying type, which is 'int' + // if not otherwise specified, so A is identical to C on Windows. Otherwise, + // we follow the C++ rules, which say that the only valid values of A are 0 + // and 1. enum A { A_foo = 0, A_bar, }; enum A a; @@ -87,21 +87,23 @@ int main() { if (c < 0) return 0; - if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + if (0 >= c) return 0; - if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + if (c > 0) return 0; if (0 <= c) return 0; - if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + if (c <= 0) return 0; if (0 > c) return 0; if (c >= 0) return 0; - if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + if (0 < c) return 0; + // FIXME: These diagnostics are terrible. The issue here is that the signed + // enumeration value was promoted to an unsigned type. if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; if (0U >= c) @@ -121,21 +123,23 @@ int main() { #elif defined(SIGNED) if (a < 0) return 0; - if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} + if (0 >= a) return 0; - if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} + if (a > 0) return 0; if (0 <= a) return 0; - if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + if (a <= 0) return 0; if (0 > a) return 0; if (a >= 0) return 0; - if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + if (0 < a) return 0; + // FIXME: As above, the issue here is that the enumeration is promoted to + // unsigned. if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; if (0U >= a) @@ -189,19 +193,19 @@ int main() { if (c < 0) return 0; - if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + if (0 >= c) return 0; - if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + if (c > 0) return 0; if (0 <= c) return 0; - if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + if (c <= 0) return 0; if (0 > c) return 0; if (c >= 0) return 0; - if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + if (0 < c) return 0; if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} @@ -221,21 +225,22 @@ int main() { if (0U < c) return 0; #else + // expected-no-diagnostics if (a < 0) return 0; - if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} + if (0 >= a) return 0; - if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} + if (a > 0) return 0; if (0 <= a) return 0; - if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + if (a <= 0) return 0; if (0 > a) return 0; if (a >= 0) return 0; - if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + if (0 < a) return 0; if (a < 0U) @@ -291,19 +296,19 @@ int main() { if (c < 0) return 0; - if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + if (0 >= c) return 0; - if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + if (c > 0) return 0; if (0 <= c) return 0; - if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + if (c <= 0) return 0; if (0 > c) return 0; if (c >= 0) return 0; - if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + if (0 < c) return 0; if (c < 0U)