Skip to content
This repository has been archived by the owner on Apr 23, 2020. It is now read-only.

Commit

Permalink
[Sema] -Wtautological-constant-compare is too good. Cripple it.
Browse files Browse the repository at this point in the history
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

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@321691 91177308-0d34-0410-b5e6-96231b3b80d8
  • Loading branch information
LebedevRI committed Jan 3, 2018
1 parent ccd63c0 commit b5b3d43
Show file tree
Hide file tree
Showing 9 changed files with 69 additions and 47 deletions.
9 changes: 7 additions & 2 deletions include/clang/Basic/DiagnosticGroups.td
Expand Up @@ -435,12 +435,16 @@ def StringCompare : DiagGroup<"string-compare">;
def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">;
def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">;
def TautologicalInRangeCompare : DiagGroup<"tautological-constant-in-range-compare",
[TautologicalTypeLimitCompare,
TautologicalUnsignedZeroCompare,
TautologicalUnsignedEnumZeroCompare]>;
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
def TautologicalConstantCompare : DiagGroup<"tautological-constant-compare",
[TautologicalUnsignedZeroCompare,
TautologicalUnsignedEnumZeroCompare,
[TautologicalInRangeCompare,
TautologicalOutOfRangeCompare]>;
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
Expand Down Expand Up @@ -715,6 +719,7 @@ def IntToPointerCast : DiagGroup<"int-to-pointer-cast",
def Move : DiagGroup<"move", [PessimizingMove, RedundantMove, SelfMove]>;

def Extra : DiagGroup<"extra", [
TautologicalInRangeCompare,
MissingFieldInitializers,
IgnoredQualifiers,
InitializerOverrides,
Expand Down
6 changes: 3 additions & 3 deletions include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -5946,15 +5946,15 @@ def note_typecheck_assign_const : Note<
def warn_unsigned_always_true_comparison : Warning<
"result of comparison of %select{%3|unsigned expression}0 %2 "
"%select{unsigned expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedZeroCompare>;
InGroup<TautologicalUnsignedZeroCompare>, DefaultIgnore;
def warn_unsigned_enum_always_true_comparison : Warning<
"result of comparison of %select{%3|unsigned enum expression}0 %2 "
"%select{unsigned enum expression|%3}0 is always %4">,
InGroup<TautologicalUnsignedEnumZeroCompare>;
InGroup<TautologicalUnsignedEnumZeroCompare>, DefaultIgnore;
def warn_tautological_constant_compare : Warning<
"result of comparison %select{%3|%1}0 %2 "
"%select{%1|%3}0 is always %4">,
InGroup<TautologicalConstantCompare>;
InGroup<TautologicalTypeLimitCompare>, DefaultIgnore;

def warn_mixed_sign_comparison : Warning<
"comparison of integers of different signs: %0 and %1">,
Expand Down
2 changes: 1 addition & 1 deletion test/Sema/compare.c
@@ -1,4 +1,4 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare %s -Wno-unreachable-code
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtautological-constant-in-range-compare %s -Wno-unreachable-code

int test(char *C) { // nothing here should warn.
return C != ((void*)0);
Expand Down
44 changes: 12 additions & 32 deletions test/Sema/tautological-constant-compare.c
@@ -1,7 +1,13 @@
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wno-tautological-constant-compare -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtautological-constant-in-range-compare -DTEST -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtautological-constant-in-range-compare -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtautological-type-limit-compare -DTEST -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wtautological-type-limit-compare -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -DTEST -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wextra -Wno-sign-compare -DTEST -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -Wall -verify -x c++ %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify %s
// RUN: %clang_cc1 -triple x86_64-linux-gnu -fsyntax-only -verify -x c++ %s

int value(void);

Expand Down Expand Up @@ -122,32 +128,6 @@ int main()
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;
Expand Down Expand Up @@ -498,7 +478,7 @@ int main()
return 0;

#if __SIZEOF_INT128__
__int128 i128;
__int128 i128 = value();
if (i128 == -1) // used to crash
return 0;
#endif
Expand All @@ -509,7 +489,7 @@ int main()
no,
maybe
};
enum E e;
enum E e = (enum E)value();

if (e == yes)
return 0;
Expand Down
4 changes: 2 additions & 2 deletions test/Sema/tautological-constant-enum-compare.c
@@ -1,5 +1,5 @@
// 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 -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

Expand Down
3 changes: 2 additions & 1 deletion test/Sema/tautological-unsigned-enum-zero-compare.c
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -triple=x86_64-pc-linux-gnu -fsyntax-only \
// RUN: -Wtautological-unsigned-enum-zero-compare \
// RUN: -verify=unsigned,unsigned-signed %s
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
// RUN: -Wtautological-unsigned-enum-zero-compare \
// RUN: -verify=unsigned-signed %s
// RUN: %clang_cc1 -triple=x86_64-pc-win32 -fsyntax-only \
// RUN: -Wno-tautological-unsigned-enum-zero-compare \
// RUN: -verify=silence %s

// Okay, this is where it gets complicated.
Expand Down
3 changes: 2 additions & 1 deletion test/Sema/tautological-unsigned-enum-zero-compare.cpp
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-linux-gnu -fsyntax-only \
// RUN: -Wtautological-unsigned-enum-zero-compare \
// RUN: -verify=unsigned,unsigned-signed %s
// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
// RUN: -Wtautological-unsigned-enum-zero-compare \
// RUN: -verify=unsigned-signed %s
// RUN: %clang_cc1 -std=c++11 -triple=x86_64-pc-win32 -fsyntax-only \
// RUN: -Wno-tautological-unsigned-enum-zero-compare \
// RUN: -verify=silence %s

// silence-no-diagnostics
Expand Down
43 changes: 39 additions & 4 deletions test/Sema/tautological-unsigned-zero-compare.c
@@ -1,7 +1,13 @@
// RUN: %clang_cc1 -fsyntax-only -verify %s
// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence %s
// RUN: %clang_cc1 -fsyntax-only -verify -x c++ %s
// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-zero-compare -verify=silence -x c++ %s
// RUN: %clang_cc1 -fsyntax-only \
// RUN: -Wtautological-unsigned-zero-compare \
// RUN: -verify %s
// RUN: %clang_cc1 -fsyntax-only \
// RUN: -verify=silence %s
// RUN: %clang_cc1 -fsyntax-only \
// RUN: -Wtautological-unsigned-zero-compare \
// RUN: -verify -x c++ %s
// RUN: %clang_cc1 -fsyntax-only \
// RUN: -verify=silence -x c++ %s

unsigned uvalue(void);
signed int svalue(void);
Expand Down Expand Up @@ -32,10 +38,39 @@ int main()
TFunc<unsigned short>();
#endif

short s = svalue();

unsigned un = uvalue();

// silence-no-diagnostics

// Note: both sides are promoted to unsigned long prior to the comparison.
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;

if (un == 0)
return 0;
if (un != 0)
Expand Down
2 changes: 1 addition & 1 deletion test/SemaCXX/compare.cpp
@@ -1,7 +1,7 @@
// Force x86-64 because some of our heuristics are actually based
// on integer sizes.

// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -std=c++11 %s
// RUN: %clang_cc1 -triple x86_64-apple-darwin -fsyntax-only -pedantic -verify -Wsign-compare -Wtautological-constant-in-range-compare -std=c++11 %s

int test0(long a, unsigned long b) {
enum EnumA {A};
Expand Down

0 comments on commit b5b3d43

Please sign in to comment.