lebedev.ri created this revision.
lebedev.ri added a project: clang.

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


Repository:
  rL LLVM

https://reviews.llvm.org/D39122

Files:
  lib/Sema/SemaChecking.cpp
  test/Sema/outof-range-enum-constant-compare.c
  test/Sema/tautological-constant-enum-compare.c
  test/Sema/tautological-unsigned-enum-zero-compare.c
  test/Sema/tautological-unsigned-enum-zero-compare.cpp

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
@@ -7,169 +7,321 @@
 // 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 };
   enum A a;
 
-  enum B : unsigned { B_foo, B_bar };
+  enum B : unsigned { B_foo = 0 };
   enum B b;
 
-  enum C : signed { c_foo, c_bar };
+  enum C : signed { C_foo = 0 };
   enum C c;
 
 #ifdef ALL_WARN
   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(SIGN_WARN)
+  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;
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,68 +1,260 @@
-// 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.
 // 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_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-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/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: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -8585,7 +8585,8 @@
 
 enum class LimitType {
   Max, // e.g. 32767 for short
-  Min  // e.g. -32768 for short
+  Min, // e.g. -32768 for short
+  Both // e.g. in C++, A::a in enum A { a = 0 };
 };
 
 /// Checks whether Expr 'Constant' may be the
@@ -8606,8 +8607,16 @@
   if (const auto *AT = OtherT->getAs<AtomicType>())
     OtherT = AT->getValueType();
 
+  if(!S.getLangOpts().CPlusPlus && OtherT->isEnumeralType()) {
+    OtherT = OtherT->getAs<EnumType>()->getDecl()->getIntegerType();
+  }
+
   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()),
@@ -8653,14 +8662,18 @@
         (ValueType = IsTypeLimit(S, Constant, Other, Value))))
     return false;
 
+  bool Result;
   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;
+  Result = ResultWhenConstEqualsOther;
 
   unsigned Diag = (isNonBooleanUnsignedValue(Other) && Value == 0)
                       ? (HasEnumType(Other)
@@ -8695,6 +8708,12 @@
   QualType OtherT = Other->getType();
   if (const auto *AT = OtherT->getAs<AtomicType>())
     OtherT = AT->getValueType();
+
+  QualType WrittenType = OtherT;
+  if(!S.getLangOpts().CPlusPlus && OtherT->isEnumeralType()) {
+    OtherT = OtherT->getAs<EnumType>()->getDecl()->getIntegerType();
+  }
+
   IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
   unsigned OtherWidth = OtherRange.Width;
 
@@ -8883,7 +8902,8 @@
     E->getOperatorLoc(), E,
     S.PDiag(diag::warn_out_of_range_compare)
         << OS.str() << LiteralOrBoolConstant
-        << OtherT << (OtherIsBooleanType && !OtherT->isBooleanType()) << IsTrue
+        << WrittenType << (OtherIsBooleanType && !OtherT->isBooleanType())
+        << IsTrue
         << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange());
 
    return true;
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to