diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-12-08 22:57:11 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2017-12-08 22:57:11 +0000 |
commit | 7bc2da619c0bba92606ef94d96921d7f4d83c925 (patch) | |
tree | b2369c4d11c14c583192064940aed2b21ffdfa9d /test/Sema/tautological-constant-compare.c | |
parent | 5e1ed772d8e34afe9be999cbc16c6252d0846bc4 (diff) |
Unify implementation of our two different flavours of -Wtautological-compare,
and fold together into a single function.
In so doing, fix a handful of remaining bugs where we would report false
positives or false negatives if we promote a signed value to an unsigned type
for the comparison.
This re-commits r320122 and r320124, minus two changes:
* Comparisons between a constant and a non-constant expression of enumeration
type never warn, not even if the constant is out of range. We should be
warning about the creation of such a constant, not about its use.
* We do not use more precise bit-widths for comparisons against bit-fields.
The more precise diagnostics probably are the right thing, but we should
consider moving them under their own warning flag.
Other than the refactoring, this patch should only change the behavior for the
buggy cases (where the warnings didn't take into account that promotion from
signed to unsigned can leave a range of inaccessible values in the middle of
the promoted type).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@320211 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test/Sema/tautological-constant-compare.c')
-rw-r--r-- | test/Sema/tautological-constant-compare.c | 83 |
1 files changed, 77 insertions, 6 deletions
diff --git a/test/Sema/tautological-constant-compare.c b/test/Sema/tautological-constant-compare.c index b9ade2a2db..c48aa99444 100644 --- a/test/Sema/tautological-constant-compare.c +++ b/test/Sema/tautological-constant-compare.c @@ -94,15 +94,17 @@ int main() if (-32768 >= s) return 0; + // Note: both sides are promoted to unsigned long prior to the comparison, so + // it is perfectly possible for a short to compare greater than 32767UL. if (s == 32767UL) return 0; if (s != 32767UL) return 0; if (s < 32767UL) return 0; - if (s <= 32767UL) // expected-warning {{comparison 'short' <= 32767 is always true}} + if (s <= 32767UL) return 0; - if (s > 32767UL) // expected-warning {{comparison 'short' > 32767 is always false}} + if (s > 32767UL) return 0; if (s >= 32767UL) return 0; @@ -111,13 +113,66 @@ int main() return 0; if (32767UL != s) return 0; - if (32767UL < s) // expected-warning {{comparison 32767 < 'short' is always false}} + if (32767UL < s) return 0; if (32767UL <= s) return 0; if (32767UL > s) return 0; - if (32767UL >= s) // expected-warning {{comparison 32767 >= 'short' is always true}} + if (32767UL >= s) + return 0; + + if (s == 0UL) + return 0; + if (s != 0UL) + return 0; + if (s < 0UL) // expected-warning {{comparison of unsigned expression < 0 is always false}} + return 0; + if (s <= 0UL) + return 0; + if (s > 0UL) + return 0; + if (s >= 0UL) // expected-warning {{comparison of unsigned expression >= 0 is always true}} + return 0; + + if (0UL == s) + return 0; + if (0UL != s) + return 0; + if (0UL < s) + return 0; + if (0UL <= s) // expected-warning {{comparison of 0 <= unsigned expression is always true}} + return 0; + if (0UL > s) // expected-warning {{comparison of 0 > unsigned expression is always false}} + return 0; + if (0UL >= s) + return 0; + + enum { ULONG_MAX = (2UL * (unsigned long)__LONG_MAX__ + 1UL) }; + if (s == 2UL * (unsigned long)__LONG_MAX__ + 1UL) + return 0; + if (s != 2UL * (unsigned long)__LONG_MAX__ + 1UL) + return 0; + if (s < 2UL * (unsigned long)__LONG_MAX__ + 1UL) + return 0; + if (s <= 2UL * (unsigned long)__LONG_MAX__ + 1UL) // expected-warning-re {{comparison 'short' <= {{.*}} is always true}} + return 0; + if (s > 2UL * (unsigned long)__LONG_MAX__ + 1UL) // expected-warning-re {{comparison 'short' > {{.*}} is always false}} + return 0; + if (s >= 2UL * (unsigned long)__LONG_MAX__ + 1UL) + return 0; + + if (2UL * (unsigned long)__LONG_MAX__ + 1UL == s) + return 0; + if (2UL * (unsigned long)__LONG_MAX__ + 1UL != s) + return 0; + if (2UL * (unsigned long)__LONG_MAX__ + 1UL < s) // expected-warning-re {{comparison {{.*}} < 'short' is always false}} + return 0; + if (2UL * (unsigned long)__LONG_MAX__ + 1UL <= s) + return 0; + if (2UL * (unsigned long)__LONG_MAX__ + 1UL > s) + return 0; + if (2UL * (unsigned long)__LONG_MAX__ + 1UL >= s) // expected-warning-re {{comparison {{.*}} >= 'short' is always true}} return 0; // FIXME: assumes two's complement @@ -281,8 +336,6 @@ int main() if (0 >= s) return 0; - // However the comparison with 0U would warn - unsigned short us = value(); #ifdef TEST @@ -510,5 +563,23 @@ int main() if (maybe >= e) return 0; + // For the time being, use the declared type of bit-fields rather than their + // length when determining whether a value is in-range. + // FIXME: Reconsider this. + struct A { + int a : 3; + unsigned b : 3; + long c : 3; + unsigned long d : 3; + } a; + if (a.a < 3) {} + if (a.a < 4) {} + if (a.b < 7) {} + if (a.b < 8) {} + if (a.c < 3) {} + if (a.c < 4) {} + if (a.d < 7) {} + if (a.d < 8) {} + return 1; } |