llvm-project/clang/test/Sema/tautological-constant-enum-compare.c
Roman Lebedev c5417aafec [Sema] -Wtautological-constant-compare is too good. Cripple it.
Summary:
The diagnostic was mostly introduced in D38101 by me, as a reaction to wasting a lot of time, see [[ https://lists.llvm.org/pipermail/cfe-commits/Week-of-Mon-20171009/206427.html | mail ]].
However, the diagnostic is pretty dumb. While it works with no false-positives,
there are some questionable cases that are diagnosed when one would argue that they should not be.

The common complaint is that it diagnoses the comparisons between an `int` and
`long` when compiling for a 32-bit target as tautological, but not when
compiling for 64-bit targets. The underlying problem is obvious: data model.
In most cases, 64-bit target is `LP64` (`int` is 32-bit, `long` and pointer are
64-bit), and the 32-bit target is `ILP32` (`int`, `long`, and pointer are 32-bit).

I.e. the common pattern is: (pseudocode)
```
#include <limits>
#include <cstdint>
int main() {
  using T1 = long;
  using T2 = int;

  T1 r;
  if (r < std::numeric_limits<T2>::min()) {}
  if (r > std::numeric_limits<T2>::max()) {}
}
```
As an example, D39149 was trying to fix this diagnostic in libc++, and it was not well-received.

This *could* be "fixed", by changing the diagnostics logic to something like
`if the types of the values being compared are different, but are of the same size, then do diagnose`,
and i even attempted to do so in D39462, but as @rjmccall rightfully commented,
that implementation is incomplete to say the least.

So to stop causing trouble, and avoid contaminating upcoming release, lets do this workaround:
* move these three diags (`warn_unsigned_always_true_comparison`, `warn_unsigned_enum_always_true_comparison`, `warn_tautological_constant_compare`) into it's own `-Wtautological-constant-in-range-compare`
* Disable them by default
* Make them part of `-Wextra`
* Additionally, give `warn_tautological_constant_compare` it's own flag `-Wtautological-type-limit-compare`.
  I'm not happy about that name, but i can't come up with anything better.

This way all three of them can be enabled/disabled either altogether, or one-by-one.

Reviewers: aaron.ballman, rsmith, smeenai, rjmccall, rnk, mclow.lists, dim

Reviewed By: aaron.ballman, rsmith, dim

Subscribers: thakis, compnerd, mehdi_amini, dim, hans, cfe-commits, rjmccall

Tags: #clang

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

llvm-svn: 321691
2018-01-03 08:45:19 +00:00

407 lines
10 KiB
C

// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only -DUNSIGNED -Wtautological-constant-in-range-compare -verify %s
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only -DSIGNED -Wtautological-constant-in-range-compare -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
#else
// If we promote to unsigned, it doesn't matter whether the enum's underlying
// type was signed.
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 < 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;
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
#if defined(UNSIGNED) && !defined(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 < 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;
#else // SIGNED || 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;
#ifndef SILENCE
if (a < 4294967295) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always true}}
return 0;
if (4294967295 >= a) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always true}}
return 0;
if (a > 4294967295) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always false}}
return 0;
if (4294967295 <= a) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always false}}
return 0;
if (a <= 4294967295) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always true}}
return 0;
if (4294967295 > a) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always true}}
return 0;
if (a >= 4294967295) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always false}}
return 0;
if (4294967295 < a) // expected-warning {{comparison of constant 4294967295 with expression of type 'enum A' is always false}}
return 0;
#else
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;
#endif
#endif
#if defined(SIGNED) && !defined(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;
#elif defined(UNSIGNED) && !defined(SILENCE)
#ifndef SILENCE
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 true}}
return 0;
if (-2147483648 < a) // expected-warning {{comparison of constant -2147483648 with expression of type 'enum A' is always true}}
return 0;
#else
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
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;
#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;
}