Index: lib/Sema/SemaChecking.cpp =================================================================== --- lib/Sema/SemaChecking.cpp +++ lib/Sema/SemaChecking.cpp @@ -8181,8 +8181,12 @@ if (const AtomicType *AT = dyn_cast(T)) T = AT->getValueType().getTypePtr(); - // For enum types, use the known bit width of the enumerators. - if (const EnumType *ET = dyn_cast(T)) { + if (!C.getLangOpts().CPlusPlus) { + // For enum types in C code, use the underlying datatype. + if (const EnumType *ET = dyn_cast(T)) + T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr(); + } 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. @@ -8584,8 +8588,10 @@ } enum class LimitType { - Max, // e.g. 32767 for short - Min // e.g. -32768 for short + Max = 1U << 0U, // e.g. 32767 for short + Min = 1U << 1U, // e.g. -32768 for short + Both = Max | Min // When the value is both the Min and the Max limit at the + // same time; e.g. in C++, A::a in enum A { a = 0 }; }; /// Checks whether Expr 'Constant' may be the @@ -8608,6 +8614,10 @@ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT); + // Special-case for C++ for enum with one enumerator with value of 0. + if (OtherRange.Width == 0) + return Value == 0 ? LimitType::Both : llvm::Optional(); + if (llvm::APSInt::isSameValue( llvm::APSInt::getMaxValue(OtherRange.Width, OtherT->isUnsignedIntegerType()), @@ -8620,7 +8630,7 @@ Value)) return LimitType::Min; - return llvm::Optional(); + return llvm::None; } bool HasEnumType(Expr *E) { @@ -8655,9 +8665,12 @@ bool ConstIsLowerBound = (Op == BO_LT || Op == BO_LE) ^ RhsConstant; bool ResultWhenConstEqualsOther = (Op == BO_LE || Op == BO_GE); - bool ResultWhenConstNeOther = - ConstIsLowerBound ^ (ValueType == LimitType::Max); - if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) + if (ValueType != LimitType::Both) { + bool ResultWhenConstNeOther = + ConstIsLowerBound ^ (ValueType == LimitType::Max); + if (ResultWhenConstEqualsOther != ResultWhenConstNeOther) + return false; // The comparison is not tautological. + } else if (ResultWhenConstEqualsOther == ConstIsLowerBound) return false; // The comparison is not tautological. const bool Result = ResultWhenConstEqualsOther; Index: test/Sema/outof-range-enum-constant-compare.c =================================================================== --- /dev/null +++ test/Sema/outof-range-enum-constant-compare.c @@ -0,0 +1,379 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-out-of-range-compare -verify %s + +int main() { + enum A { A_a = 2 }; + enum A a; + +#ifdef SILENCE + // expected-no-diagnostics +#endif + +#ifdef UNSIGNED +#ifndef SILENCE + if (a < 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a > 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a <= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a >= 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a == 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296 != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a != 4294967296) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296 == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + + if (a < 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U >= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a > 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U <= a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a <= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U > a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a >= 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U < a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (a == 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; + if (4294967296U != a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (a != 4294967296U) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always true}} + return 0; + if (4294967296U == a) // expected-warning {{comparison of constant 4294967296 with expression of type 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < 4294967296) + return 0; + if (4294967296 >= a) + return 0; + if (a > 4294967296) + return 0; + if (4294967296 <= a) + return 0; + if (a <= 4294967296) + return 0; + if (4294967296 > a) + return 0; + if (a >= 4294967296) + return 0; + if (4294967296 < a) + return 0; + if (a == 4294967296) + return 0; + if (4294967296 != a) + return 0; + if (a != 4294967296) + return 0; + if (4294967296 == a) + return 0; + + if (a < 4294967296U) + return 0; + if (4294967296U >= a) + return 0; + if (a > 4294967296U) + return 0; + if (4294967296U <= a) + return 0; + if (a <= 4294967296U) + return 0; + if (4294967296U > a) + return 0; + if (a >= 4294967296U) + return 0; + if (4294967296U < a) + return 0; + if (a == 4294967296U) + return 0; + if (4294967296U != a) + return 0; + if (a != 4294967296U) + return 0; + if (4294967296U == a) + return 0; +#endif +#elif defined(SIGNED) +#ifndef SILENCE + if (a < -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 >= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (a > -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 <= a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a <= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 > a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (a >= -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 < a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a == -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + if (-2147483649 != a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (a != -2147483649) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always true}} + return 0; + if (-2147483649 == a) // expected-warning {{comparison of constant -2147483649 with expression of type 'enum A' is always false}} + return 0; + + if (a < 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 >= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a > 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 <= a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (a <= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 > a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a >= 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 < a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (a == 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; + if (2147483648 != a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (a != 2147483648) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always true}} + return 0; + if (2147483648 == a) // expected-warning {{comparison of constant 2147483648 with expression of type 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < -2147483649) + return 0; + if (-2147483649 >= a) + return 0; + if (a > -2147483649) + return 0; + if (-2147483649 <= a) + return 0; + if (a <= -2147483649) + return 0; + if (-2147483649 > a) + return 0; + if (a >= -2147483649) + return 0; + if (-2147483649 < a) + return 0; + if (a == -2147483649) + return 0; + if (-2147483649 != a) + return 0; + if (a != -2147483649) + return 0; + if (-2147483649 == a) + return 0; + + if (a < 2147483648) + return 0; + if (2147483648 >= a) + return 0; + if (a > 2147483648) + return 0; + if (2147483648 <= a) + return 0; + if (a <= 2147483648) + return 0; + if (2147483648 > a) + return 0; + if (a >= 2147483648) + return 0; + if (2147483648 < a) + return 0; + if (a == 2147483648) + return 0; + if (2147483648 != a) + return 0; + if (a != 2147483648) + return 0; + if (2147483648 == a) + return 0; +#endif +#endif +} + +// https://bugs.llvm.org/show_bug.cgi?id=35009 +int PR35009() { + enum A { A_a = 2 }; + enum A a; + + // in C, this should not warn. + + if (a < 1) + return 0; + if (1 >= a) + return 0; + if (a > 1) + return 0; + if (1 <= a) + return 0; + if (a <= 1) + return 0; + if (1 > a) + return 0; + if (a >= 1) + return 0; + if (1 < a) + return 0; + if (a == 1) + return 0; + if (1 != a) + return 0; + if (a != 1) + return 0; + if (1 == a) + return 0; + + if (a < 1U) + return 0; + if (1U >= a) + return 0; + if (a > 1U) + return 0; + if (1U <= a) + return 0; + if (a <= 1U) + return 0; + if (1U > a) + return 0; + if (a >= 1U) + return 0; + if (1U < a) + return 0; + if (a == 1U) + return 0; + if (1U != a) + return 0; + if (a != 1U) + return 0; + if (1U == a) + return 0; + + if (a < 2) + return 0; + if (2 >= a) + return 0; + if (a > 2) + return 0; + if (2 <= a) + return 0; + if (a <= 2) + return 0; + if (2 > a) + return 0; + if (a >= 2) + return 0; + if (2 < a) + return 0; + if (a == 2) + return 0; + if (2 != a) + return 0; + if (a != 2) + return 0; + if (2 == a) + return 0; + + if (a < 2U) + return 0; + if (2U >= a) + return 0; + if (a > 2U) + return 0; + if (2U <= a) + return 0; + if (a <= 2U) + return 0; + if (2U > a) + return 0; + if (a >= 2U) + return 0; + if (2U < a) + return 0; + if (a == 2U) + return 0; + if (2U != a) + return 0; + if (a != 2U) + return 0; + if (2U == a) + return 0; + + if (a < 3) + return 0; + if (3 >= a) + return 0; + if (a > 3) + return 0; + if (3 <= a) + return 0; + if (a <= 3) + return 0; + if (3 > a) + return 0; + if (a >= 3) + return 0; + if (3 < a) + return 0; + if (a == 3) + return 0; + if (3 != a) + return 0; + if (a != 3) + return 0; + if (3 == a) + return 0; + + if (a < 3U) + return 0; + if (3U >= a) + return 0; + if (a > 3U) + return 0; + if (3U <= a) + return 0; + if (a <= 3U) + return 0; + if (3U > a) + return 0; + if (a >= 3U) + return 0; + if (3U < a) + return 0; + if (a == 3U) + return 0; + if (3U != a) + return 0; + if (a != 3U) + return 0; + if (3U == a) + return 0; + + return 1; +} Index: test/Sema/tautological-constant-enum-compare.c =================================================================== --- /dev/null +++ test/Sema/tautological-constant-enum-compare.c @@ -0,0 +1,419 @@ +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -DSILENCE -Wno-tautological-constant-compare -verify %s + +int main() { + enum A { A_a = 2 }; + enum A a; + +#ifdef SILENCE + // expected-no-diagnostics +#endif + +#ifdef UNSIGNED +#ifndef SILENCE + if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0) + return 0; + if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0U) + return 0; + if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (a < 4294967295) + return 0; + if (4294967295 >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}} + return 0; + if (a > 4294967295) // expected-warning {{comparison 'enum A' > 4294967295 is always false}} + return 0; + if (4294967295 <= a) + return 0; + if (a <= 4294967295) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}} + return 0; + if (4294967295 > a) + return 0; + if (a >= 4294967295) + return 0; + if (4294967295 < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}} + return 0; + + if (a < 4294967295U) + return 0; + if (4294967295U >= a) // expected-warning {{comparison 4294967295 >= 'enum A' is always true}} + return 0; + if (a > 4294967295U) // expected-warning {{comparison 'enum A' > 4294967295 is always false}} + return 0; + if (4294967295U <= a) + return 0; + if (a <= 4294967295U) // expected-warning {{comparison 'enum A' <= 4294967295 is always true}} + return 0; + if (4294967295U > a) + return 0; + if (a >= 4294967295U) + return 0; + if (4294967295U < a) // expected-warning {{comparison 4294967295 < 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < 0) + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) + return 0; + if (a <= 0) + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + + if (a < 0U) + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) + return 0; + if (a <= 0U) + return 0; + if (0U > a) + return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; + + if (a < 4294967295) + return 0; + if (4294967295 >= a) + return 0; + if (a > 4294967295) + return 0; + if (4294967295 <= a) + return 0; + if (a <= 4294967295) + return 0; + if (4294967295 > a) + return 0; + if (a >= 4294967295) + return 0; + if (4294967295 < a) + return 0; + + if (a < 4294967295U) + return 0; + if (4294967295U >= a) + return 0; + if (a > 4294967295U) + return 0; + if (4294967295U <= a) + return 0; + if (a <= 4294967295U) + return 0; + if (4294967295U > a) + return 0; + if (a >= 4294967295U) + return 0; + if (4294967295U < a) + return 0; +#endif +#elif defined(SIGNED) +#ifndef SILENCE + if (a < -2147483648) // expected-warning {{comparison 'enum A' < -2147483648 is always false}} + return 0; + if (-2147483648 >= a) + return 0; + if (a > -2147483648) + return 0; + if (-2147483648 <= a) // expected-warning {{comparison -2147483648 <= 'enum A' is always true}} + return 0; + if (a <= -2147483648) + return 0; + if (-2147483648 > a) // expected-warning {{comparison -2147483648 > 'enum A' is always false}} + return 0; + if (a >= -2147483648) // expected-warning {{comparison 'enum A' >= -2147483648 is always true}} + return 0; + if (-2147483648 < a) + return 0; + + if (a < 2147483647) + return 0; + if (2147483647 >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}} + return 0; + if (a > 2147483647) // expected-warning {{comparison 'enum A' > 2147483647 is always false}} + return 0; + if (2147483647 <= a) + return 0; + if (a <= 2147483647) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}} + return 0; + if (2147483647 > a) + return 0; + if (a >= 2147483647) + return 0; + if (2147483647 < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}} + return 0; + + if (a < 2147483647U) + return 0; + if (2147483647U >= a) // expected-warning {{comparison 2147483647 >= 'enum A' is always true}} + return 0; + if (a > 2147483647U) // expected-warning {{comparison 'enum A' > 2147483647 is always false}} + return 0; + if (2147483647U <= a) + return 0; + if (a <= 2147483647U) // expected-warning {{comparison 'enum A' <= 2147483647 is always true}} + return 0; + if (2147483647U > a) + return 0; + if (a >= 2147483647U) + return 0; + if (2147483647U < a) // expected-warning {{comparison 2147483647 < 'enum A' is always false}} + return 0; +#else // SILENCE + if (a < -2147483648) + return 0; + if (-2147483648 >= a) + return 0; + if (a > -2147483648) + return 0; + if (-2147483648 <= a) + return 0; + if (a <= -2147483648) + return 0; + if (-2147483648 > a) + return 0; + if (a >= -2147483648) + return 0; + if (-2147483648 < a) + return 0; + + if (a < 2147483647) + return 0; + if (2147483647 >= a) + return 0; + if (a > 2147483647) + return 0; + if (2147483647 <= a) + return 0; + if (a <= 2147483647) + return 0; + if (2147483647 > a) + return 0; + if (a >= 2147483647) + return 0; + if (2147483647 < a) + return 0; + + if (a < 2147483647U) + return 0; + if (2147483647U >= a) + return 0; + if (a > 2147483647U) + return 0; + if (2147483647U <= a) + return 0; + if (a <= 2147483647U) + return 0; + if (2147483647U > a) + return 0; + if (a >= 2147483647U) + return 0; + if (2147483647U < a) + return 0; +#endif +#endif + + return 1; +} + +// https://bugs.llvm.org/show_bug.cgi?id=35009 +int PR35009() { + enum A { A_a = 2 }; + enum A a; + + // in C, this should not warn. + + if (a < 1) + return 0; + if (1 >= a) + return 0; + if (a > 1) + return 0; + if (1 <= a) + return 0; + if (a <= 1) + return 0; + if (1 > a) + return 0; + if (a >= 1) + return 0; + if (1 < a) + return 0; + if (a == 1) + return 0; + if (1 != a) + return 0; + if (a != 1) + return 0; + if (1 == a) + return 0; + + if (a < 1U) + return 0; + if (1U >= a) + return 0; + if (a > 1U) + return 0; + if (1U <= a) + return 0; + if (a <= 1U) + return 0; + if (1U > a) + return 0; + if (a >= 1U) + return 0; + if (1U < a) + return 0; + if (a == 1U) + return 0; + if (1U != a) + return 0; + if (a != 1U) + return 0; + if (1U == a) + return 0; + + if (a < 2) + return 0; + if (2 >= a) + return 0; + if (a > 2) + return 0; + if (2 <= a) + return 0; + if (a <= 2) + return 0; + if (2 > a) + return 0; + if (a >= 2) + return 0; + if (2 < a) + return 0; + if (a == 2) + return 0; + if (2 != a) + return 0; + if (a != 2) + return 0; + if (2 == a) + return 0; + + if (a < 2U) + return 0; + if (2U >= a) + return 0; + if (a > 2U) + return 0; + if (2U <= a) + return 0; + if (a <= 2U) + return 0; + if (2U > a) + return 0; + if (a >= 2U) + return 0; + if (2U < a) + return 0; + if (a == 2U) + return 0; + if (2U != a) + return 0; + if (a != 2U) + return 0; + if (2U == a) + return 0; + + if (a < 3) + return 0; + if (3 >= a) + return 0; + if (a > 3) + return 0; + if (3 <= a) + return 0; + if (a <= 3) + return 0; + if (3 > a) + return 0; + if (a >= 3) + return 0; + if (3 < a) + return 0; + if (a == 3) + return 0; + if (3 != a) + return 0; + if (a != 3) + return 0; + if (3 == a) + return 0; + + if (a < 3U) + return 0; + if (3U >= a) + return 0; + if (a > 3U) + return 0; + if (3U <= a) + return 0; + if (a <= 3U) + return 0; + if (3U > a) + return 0; + if (a >= 3U) + return 0; + if (3U < a) + return 0; + if (a == 3U) + return 0; + if (3U != a) + return 0; + if (a != 3U) + return 0; + if (3U == a) + return 0; + + return 1; +} Index: test/Sema/tautological-unsigned-enum-zero-compare.c =================================================================== --- test/Sema/tautological-unsigned-enum-zero-compare.c +++ test/Sema/tautological-unsigned-enum-zero-compare.c @@ -1,5 +1,5 @@ -// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DALL_WARN -verify %s -// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGN_WARN -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -verify %s // RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s // Okay, this is where it gets complicated. @@ -7,62 +7,254 @@ // On windows, it is signed by default. We do not want to warn in that case. int main() { - enum A { A_foo, A_bar }; + enum A { A_a = 0 }; enum A a; + enum B { B_a = -1 }; + enum B b; -#ifdef ALL_WARN +#ifdef UNSIGNED if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0) + return 0; if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; -#elif defined(SIGN_WARN) - if (a < 0) // ok - return 0; - if (a >= 0) // ok - return 0; - if (0 <= a) // ok - return 0; - if (0 > a) // ok - return 0; - if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} return 0; - if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + if (0U < a) return 0; - if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + + if (b < 0) return 0; -#else - // expected-no-diagnostics + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0U) + return 0; + if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; +#elif defined(SIGNED) if (a < 0) return 0; - if (a >= 0) + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) return 0; + if (a <= 0) + return 0; if (0 > a) return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0U) + return 0; + if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0U) + return 0; + if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; +#else + // expected-no-diagnostics + + if (a < 0) + return 0; + if (0 >= a) + return 0; + if (a > 0) + return 0; + if (0 <= a) + return 0; + if (a <= 0) + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) + return 0; + if (a < 0U) return 0; - if (a >= 0U) + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) return 0; + if (a <= 0U) + return 0; if (0U > a) return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) + return 0; + if (b <= 0U) + return 0; + if (0U > b) + return 0; + if (b >= 0U) + return 0; + if (0U < b) + return 0; #endif + if (a == 0) + return 0; + if (0 != a) + return 0; + if (a != 0) + return 0; + if (0 == a) + return 0; + + if (a == 0U) + return 0; + if (0U != a) + return 0; + if (a != 0U) + return 0; + if (0U == a) + return 0; + + if (b == 0) + return 0; + if (0 != b) + return 0; + if (b != 0) + return 0; + if (0 == b) + return 0; + + if (b == 0U) + return 0; + if (0U != b) + return 0; + if (b != 0U) + return 0; + if (0U == b) + return 0; + return 1; } Index: test/Sema/tautological-unsigned-enum-zero-compare.cpp =================================================================== --- test/Sema/tautological-unsigned-enum-zero-compare.cpp +++ test/Sema/tautological-unsigned-enum-zero-compare.cpp @@ -1,176 +1,347 @@ -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DALL_WARN -verify %s -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -DSIGN_WARN -verify %s -// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s +// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -verify %s +// 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() { - enum A { A_foo, A_bar }; + enum A { A_foo = 0, A_bar, }; enum A a; - enum B : unsigned { B_foo, B_bar }; + enum B : unsigned { B_foo = 0, B_bar, }; enum B b; - enum C : signed { c_foo, c_bar }; + enum C : signed { C_foo = 0, C_bar, }; enum C c; -#ifdef ALL_WARN +#ifdef UNSIGNED if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= a) + return 0; + if (a > 0) return 0; if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0) + return 0; if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < a) + return 0; + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= a) + return 0; + if (a > 0U) return 0; if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (a <= 0U) + return 0; if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0 >= b) + return 0; + if (b > 0) return 0; if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0) + return 0; if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; - if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; - if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} - return 0; - if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} - return 0; - if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} - return 0; - - if (c < 0) // ok - return 0; - if (c >= 0) // ok - return 0; - if (0 <= c) // ok - return 0; - if (0 > c) // ok - return 0; - if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; - if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} - return 0; - if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} - return 0; - if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} - return 0; -#elif defined(SIGN_WARN) - if (a < 0) // ok - return 0; - if (a >= 0) // ok - return 0; - if (0 <= a) // ok - return 0; - if (0 > a) // ok - return 0; - if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; - if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} - return 0; - if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} - return 0; - if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} - return 0; - - if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} return 0; - if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} - return 0; - if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + if (0 < b) return 0; + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} return 0; - if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + if (0U >= b) + return 0; + if (b > 0U) return 0; if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} return 0; + if (b <= 0U) + return 0; if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} return 0; - - if (c < 0) // ok + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} return 0; - if (c >= 0) // ok - return 0; - if (0 <= c) // ok - return 0; - if (0 > c) // ok - return 0; - if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} - return 0; - if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} - return 0; - if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} - return 0; - if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} - return 0; -#else - // expected-no-diagnostics - if (a < 0) - return 0; - if (a >= 0) - return 0; - if (0 <= a) - return 0; - if (0 > a) - return 0; - if (a < 0U) - return 0; - if (a >= 0U) - return 0; - if (0U <= a) - return 0; - if (0U > a) - return 0; - - if (b < 0) - return 0; - if (b >= 0) - return 0; - if (0 <= b) - return 0; - if (0 > b) - return 0; - if (b < 0U) - return 0; - if (b >= 0U) - return 0; - if (0U <= b) - return 0; - if (0U > b) + if (0U < b) return 0; if (c < 0) return 0; - if (c >= 0) + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + return 0; + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} return 0; if (0 <= c) return 0; + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + return 0; if (0 > c) return 0; + if (c >= 0) + return 0; + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + return 0; + + if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= c) + return 0; + if (c > 0U) + return 0; + if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (c <= 0U) + return 0; + if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < c) + return 0; +#elif defined(SIGNED) + if (a < 0) + return 0; + if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} + return 0; + if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} + return 0; + if (0 <= a) + return 0; + if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + return 0; + + if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (a <= 0U) + return 0; + if (0U > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < a) + return 0; + + if (b < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0) + return 0; + if (0 > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0 < b) + return 0; + + if (b < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (b <= 0U) + return 0; + if (0U > b) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < b) + return 0; + + if (c < 0) + return 0; + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + return 0; + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + return 0; + if (0 <= c) + return 0; + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + return 0; + if (0 > c) + return 0; + if (c >= 0) + return 0; + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + return 0; + + if (c < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} + return 0; + if (0U >= c) + return 0; + if (c > 0U) + return 0; + if (0U <= c) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}} + return 0; + if (c <= 0U) + return 0; + if (0U > c) // expected-warning {{comparison of 0 > unsigned enum expression is always false}} + return 0; + if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}} + return 0; + if (0U < c) + return 0; +#else + if (a < 0) + return 0; + if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}} + return 0; + if (a > 0) // expected-warning {{comparison 'enum A' > 0 is always false}} + return 0; + if (0 <= a) + return 0; + if (a <= 0) // expected-warning {{comparison 'enum A' <= 0 is always true}} + return 0; + if (0 > a) + return 0; + if (a >= 0) + return 0; + if (0 < a) // expected-warning {{comparison 0 < 'enum A' is always false}} + return 0; + + if (a < 0U) + return 0; + if (0U >= a) + return 0; + if (a > 0U) + return 0; + if (0U <= a) + return 0; + if (a <= 0U) + return 0; + if (0U > a) + return 0; + if (a >= 0U) + return 0; + if (0U < a) + return 0; + + if (b < 0) + return 0; + if (0 >= b) + return 0; + if (b > 0) + return 0; + if (0 <= b) + return 0; + if (b <= 0) + return 0; + if (0 > b) + return 0; + if (b >= 0) + return 0; + if (0 < b) + return 0; + + if (b < 0U) + return 0; + if (0U >= b) + return 0; + if (b > 0U) + return 0; + if (0U <= b) + return 0; + if (b <= 0U) + return 0; + if (0U > b) + return 0; + if (b >= 0U) + return 0; + if (0U < b) + return 0; + + if (c < 0) + return 0; + if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}} + return 0; + if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}} + return 0; + if (0 <= c) + return 0; + if (c <= 0) // expected-warning {{comparison 'enum C' <= 0 is always true}} + return 0; + if (0 > c) + return 0; + if (c >= 0) + return 0; + if (0 < c) // expected-warning {{0 < 'enum C' is always false}} + return 0; + if (c < 0U) return 0; - if (c >= 0U) + if (0U >= c) + return 0; + if (c > 0U) return 0; if (0U <= c) return 0; + if (c <= 0U) + return 0; if (0U > c) return 0; + if (c >= 0U) + return 0; + if (0U < c) + return 0; #endif return 1; } + +namespace crash_enum_zero_width { +int test() { + enum A : unsigned { + A_foo = 0 + }; + enum A a; + + // used to crash in llvm::APSInt::getMaxValue() +#ifndef SILENCE + if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}} +#else + if (a > 0) +#endif + return 0; + + return 1; +} +} // namespace crash_enum_zero_width