]> granicus.if.org Git - clang/commitdiff
[Sema] Fixes for enum handling for tautological comparison diagnostics
authorRoman Lebedev <lebedev.ri@gmail.com>
Sat, 21 Oct 2017 16:44:03 +0000 (16:44 +0000)
committerRoman Lebedev <lebedev.ri@gmail.com>
Sat, 21 Oct 2017 16:44:03 +0000 (16:44 +0000)
Summary:
As Mattias Eriksson has reported in PR35009, in C, for enums, the underlying type should
be used when checking for the tautological comparison, unlike C++, where the enumerator
values define the value range. So if not in CPlusPlus mode, use the enum underlying type.

Also, i have discovered a problem (a crash) when evaluating tautological-ness of the following comparison:
```
enum A { A_a = 0 };
if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
return 0;
```
This affects both the C and C++, but after the first fix, only C++ code was affected.
That was also fixed, while preserving (i think?) the proper diagnostic output.

And while there, attempt to enhance the test coverage.
Yes, some tests got moved around, sorry about that :)

Fixes PR35009

Reviewers: aaron.ballman, rsmith, rjmccall

Reviewed By: aaron.ballman

Subscribers: Rakete1111, efriedma, materi, cfe-commits

Tags: #clang

Differential Revision: https://reviews.llvm.org/D39122

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@316268 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/Sema/outof-range-enum-constant-compare.c [new file with mode: 0644]
test/Sema/tautological-constant-enum-compare.c [new file with mode: 0644]
test/Sema/tautological-unsigned-enum-zero-compare.c
test/Sema/tautological-unsigned-enum-zero-compare.cpp

index 79263f1e3ac1b2dc47467e74e26801366218e6e2..53e710d7b726aba044ef4d1154f8c57994f0562c 100644 (file)
@@ -8181,8 +8181,12 @@ struct IntRange {
     if (const AtomicType *AT = dyn_cast<AtomicType>(T))
       T = AT->getValueType().getTypePtr();
 
-    // For enum types, use the known bit width of the enumerators.
-    if (const EnumType *ET = dyn_cast<EnumType>(T)) {
+    if (!C.getLangOpts().CPlusPlus) {
+      // For enum types in C code, use the underlying datatype.
+      if (const EnumType *ET = dyn_cast<EnumType>(T))
+        T = ET->getDecl()->getIntegerType().getDesugaredType(C).getTypePtr();
+    } else if (const EnumType *ET = dyn_cast<EnumType>(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 @@ bool isNonBooleanUnsignedValue(Expr *E) {
 }
 
 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 @@ llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other,
 
   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<LimitType>();
+
   if (llvm::APSInt::isSameValue(
           llvm::APSInt::getMaxValue(OtherRange.Width,
                                     OtherT->isUnsignedIntegerType()),
@@ -8620,7 +8630,7 @@ llvm::Optional<LimitType> IsTypeLimit(Sema &S, Expr *Constant, Expr *Other,
           Value))
     return LimitType::Min;
 
-  return llvm::Optional<LimitType>();
+  return llvm::None;
 }
 
 bool HasEnumType(Expr *E) {
@@ -8655,9 +8665,12 @@ bool CheckTautologicalComparison(Sema &S, BinaryOperator *E, Expr *Constant,
 
   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;
diff --git a/test/Sema/outof-range-enum-constant-compare.c b/test/Sema/outof-range-enum-constant-compare.c
new file mode 100644 (file)
index 0000000..b9ce08f
--- /dev/null
@@ -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;
+}
diff --git a/test/Sema/tautological-constant-enum-compare.c b/test/Sema/tautological-constant-enum-compare.c
new file mode 100644 (file)
index 0000000..1f09865
--- /dev/null
@@ -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 49982a9fd71f6f24650cf6ab2bfddfaa7674f714..43b768433dbf96943f21a6f10e3c6a34f246db52 100644 (file)
@@ -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.
 // 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
+  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 (a >= 0) // ok
+  if (0U < b)
     return 0;
-  if (0 <= a) // ok
+#elif defined(SIGNED)
+  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) // ok
+  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 (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)
+    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 (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)
     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 3e78626745e759bd7b741bc46830e003f3031205..f8d4560ef21db63d07398a5e79045ba75dc7e796 100644 (file)
-// 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 >= 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 (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 (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+    return 0;
+  if (0U < b)
+    return 0;
 
-  if (c < 0) // ok
+  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 (c >= 0) // ok
+  if (0 > c)
     return 0;
-  if (0 <= c) // ok
+  if (c >= 0)
     return 0;
-  if (0 > c) // ok
+  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 (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  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;
-#elif defined(SIGN_WARN)
-  if (a < 0) // ok
+  if (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
     return 0;
-  if (a >= 0) // ok
+  if (0U < c)
     return 0;
-  if (0 <= a) // ok
+#elif defined(SIGNED)
+  if (a < 0)
+    return 0;
+  if (0 >= a) // expected-warning {{comparison 0 >= 'enum A' is always true}}
     return 0;
-  if (0 > a) // ok
+  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 (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 >= 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 (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 (b >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+    return 0;
+  if (0U < b)
+    return 0;
 
-  if (c < 0) // ok
+  if (c < 0)
     return 0;
-  if (c >= 0) // ok
+  if (0 >= c) // expected-warning {{comparison 0 >= 'enum C' is always true}}
     return 0;
-  if (0 <= c) // ok
+  if (c > 0) // expected-warning {{comparison 'enum C' > 0 is always false}}
+    return 0;
+  if (0 <= c)
     return 0;
-  if (0 > c) // ok
+  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 (c >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
+  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
-  // expected-no-diagnostics
   if (a < 0)
     return 0;
-  if (a >= 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 (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 (b >= 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 (b >= 0U)
+  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 (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)
     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