forked from OSchip/llvm-project
[Sema] Move some stuff into -Wtautological-unsigned-enum-zero-compare
Summary: As requested by Sam McCall: > Enums (not new I guess). Typical case: if (enum < 0 || enum > MAX) > The warning strongly suggests that the enum < 0 check has no effect > (for enums with nonnegative ranges). > Clang doesn't seem to optimize such checks out though, and they seem > likely to catch bugs in some cases. Yes, only if there's UB elsewhere, > but I assume not optimizing out these checks indicates a deliberate > decision to stay somewhat compatible with a technically-incorrect > mental model. > If this is the case, should we move these to a > -Wtautological-compare-enum subcategory? Reviewers: rjmccall, rsmith, aaron.ballman, sammccall, bkramer, djasper Reviewed By: aaron.ballman Subscribers: jroelofs, cfe-commits Tags: #clang Differential Revision: https://reviews.llvm.org/D37629 llvm-svn: 313677
This commit is contained in:
parent
8cc8b63b06
commit
c9c9748d99
|
@ -429,12 +429,14 @@ def StringPlusInt : DiagGroup<"string-plus-int">;
|
||||||
def StringPlusChar : DiagGroup<"string-plus-char">;
|
def StringPlusChar : DiagGroup<"string-plus-char">;
|
||||||
def StrncatSize : DiagGroup<"strncat-size">;
|
def StrncatSize : DiagGroup<"strncat-size">;
|
||||||
def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
|
def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">;
|
||||||
|
def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">;
|
||||||
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
|
def TautologicalOutOfRangeCompare : DiagGroup<"tautological-constant-out-of-range-compare">;
|
||||||
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
|
def TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
|
||||||
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
|
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
|
||||||
def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">;
|
def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">;
|
||||||
def TautologicalCompare : DiagGroup<"tautological-compare",
|
def TautologicalCompare : DiagGroup<"tautological-compare",
|
||||||
[TautologicalUnsignedZeroCompare,
|
[TautologicalUnsignedZeroCompare,
|
||||||
|
TautologicalUnsignedEnumZeroCompare,
|
||||||
TautologicalOutOfRangeCompare,
|
TautologicalOutOfRangeCompare,
|
||||||
TautologicalPointerCompare,
|
TautologicalPointerCompare,
|
||||||
TautologicalOverlapCompare,
|
TautologicalOverlapCompare,
|
||||||
|
|
|
@ -5906,19 +5906,26 @@ def note_typecheck_assign_const : Note<
|
||||||
"member function %q1 is declared const here|"
|
"member function %q1 is declared const here|"
|
||||||
"%select{|nested }1data member %2 declared const here}0">;
|
"%select{|nested }1data member %2 declared const here}0">;
|
||||||
|
|
||||||
|
def warn_lunsigned_always_true_comparison : Warning<
|
||||||
|
"comparison of unsigned expression %0 is always %select{false|true}1">,
|
||||||
|
InGroup<TautologicalUnsignedZeroCompare>;
|
||||||
|
def warn_runsigned_always_true_comparison : Warning<
|
||||||
|
"comparison of %0 unsigned expression is always %select{false|true}1">,
|
||||||
|
InGroup<TautologicalUnsignedZeroCompare>;
|
||||||
|
def warn_lunsigned_enum_always_true_comparison : Warning<
|
||||||
|
"comparison of unsigned enum expression %0 is always %select{false|true}1">,
|
||||||
|
InGroup<TautologicalUnsignedEnumZeroCompare>;
|
||||||
|
def warn_runsigned_enum_always_true_comparison : Warning<
|
||||||
|
"comparison of %0 unsigned enum expression is always %select{false|true}1">,
|
||||||
|
InGroup<TautologicalUnsignedEnumZeroCompare>;
|
||||||
|
|
||||||
def warn_mixed_sign_comparison : Warning<
|
def warn_mixed_sign_comparison : Warning<
|
||||||
"comparison of integers of different signs: %0 and %1">,
|
"comparison of integers of different signs: %0 and %1">,
|
||||||
InGroup<SignCompare>, DefaultIgnore;
|
InGroup<SignCompare>, DefaultIgnore;
|
||||||
def warn_lunsigned_always_true_comparison : Warning<
|
|
||||||
"comparison of unsigned%select{| enum}2 expression %0 is always %1">,
|
|
||||||
InGroup<TautologicalUnsignedZeroCompare>;
|
|
||||||
def warn_out_of_range_compare : Warning<
|
def warn_out_of_range_compare : Warning<
|
||||||
"comparison of %select{constant %0|true|false}1 with "
|
"comparison of %select{constant %0|true|false}1 with "
|
||||||
"%select{expression of type %2|boolean expression}3 is always "
|
"%select{expression of type %2|boolean expression}3 is always "
|
||||||
"%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>;
|
"%select{false|true}4">, InGroup<TautologicalOutOfRangeCompare>;
|
||||||
def warn_runsigned_always_true_comparison : Warning<
|
|
||||||
"comparison of %0 unsigned%select{| enum}2 expression is always %1">,
|
|
||||||
InGroup<TautologicalUnsignedZeroCompare>;
|
|
||||||
def warn_comparison_of_mixed_enum_types : Warning<
|
def warn_comparison_of_mixed_enum_types : Warning<
|
||||||
"comparison of two values with different enumeration types"
|
"comparison of two values with different enumeration types"
|
||||||
"%diff{ ($ and $)|}0,1">,
|
"%diff{ ($ and $)|}0,1">,
|
||||||
|
|
|
@ -8583,7 +8583,7 @@ bool CheckTautologicalComparisonWithZero(Sema &S, BinaryOperator *E) {
|
||||||
|
|
||||||
// bool values are handled by DiagnoseOutOfRangeComparison().
|
// bool values are handled by DiagnoseOutOfRangeComparison().
|
||||||
|
|
||||||
BinaryOperatorKind op = E->getOpcode();
|
BinaryOperatorKind Op = E->getOpcode();
|
||||||
if (E->isValueDependent())
|
if (E->isValueDependent())
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -8592,22 +8592,30 @@ bool CheckTautologicalComparisonWithZero(Sema &S, BinaryOperator *E) {
|
||||||
|
|
||||||
bool Match = true;
|
bool Match = true;
|
||||||
|
|
||||||
if (op == BO_LT && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
|
if (Op == BO_LT && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
|
||||||
S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
|
S.Diag(E->getOperatorLoc(),
|
||||||
<< "< 0" << "false" << HasEnumType(LHS)
|
HasEnumType(LHS) ? diag::warn_lunsigned_enum_always_true_comparison
|
||||||
<< LHS->getSourceRange() << RHS->getSourceRange();
|
: diag::warn_lunsigned_always_true_comparison)
|
||||||
} else if (op == BO_GE && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
|
<< "< 0"
|
||||||
S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
|
<< "false" << LHS->getSourceRange() << RHS->getSourceRange();
|
||||||
<< ">= 0" << "true" << HasEnumType(LHS)
|
} else if (Op == BO_GE && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
|
||||||
<< LHS->getSourceRange() << RHS->getSourceRange();
|
S.Diag(E->getOperatorLoc(),
|
||||||
} else if (op == BO_GT && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
|
HasEnumType(LHS) ? diag::warn_lunsigned_enum_always_true_comparison
|
||||||
S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
|
: diag::warn_lunsigned_always_true_comparison)
|
||||||
<< "0 >" << "false" << HasEnumType(RHS)
|
<< ">= 0"
|
||||||
<< LHS->getSourceRange() << RHS->getSourceRange();
|
<< "true" << LHS->getSourceRange() << RHS->getSourceRange();
|
||||||
} else if (op == BO_LE && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
|
} else if (Op == BO_GT && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
|
||||||
S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
|
S.Diag(E->getOperatorLoc(),
|
||||||
<< "0 <=" << "true" << HasEnumType(RHS)
|
HasEnumType(RHS) ? diag::warn_runsigned_enum_always_true_comparison
|
||||||
<< LHS->getSourceRange() << RHS->getSourceRange();
|
: diag::warn_runsigned_always_true_comparison)
|
||||||
|
<< "0 >"
|
||||||
|
<< "false" << LHS->getSourceRange() << RHS->getSourceRange();
|
||||||
|
} else if (Op == BO_LE && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
|
||||||
|
S.Diag(E->getOperatorLoc(),
|
||||||
|
HasEnumType(RHS) ? diag::warn_runsigned_enum_always_true_comparison
|
||||||
|
: diag::warn_runsigned_always_true_comparison)
|
||||||
|
<< "0 <="
|
||||||
|
<< "true" << LHS->getSourceRange() << RHS->getSourceRange();
|
||||||
} else
|
} else
|
||||||
Match = false;
|
Match = false;
|
||||||
|
|
||||||
|
|
|
@ -308,8 +308,59 @@ int rdar8414119_bar(unsigned x) {
|
||||||
int rdar8511238() {
|
int rdar8511238() {
|
||||||
enum A { A_foo, A_bar };
|
enum A { A_foo, A_bar };
|
||||||
enum A a;
|
enum A a;
|
||||||
|
|
||||||
|
if (a == 0)
|
||||||
|
return 0;
|
||||||
|
if (a != 0)
|
||||||
|
return 0;
|
||||||
if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
|
if (a < 0) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
|
||||||
return 0;
|
return 0;
|
||||||
|
if (a <= 0)
|
||||||
|
return 0;
|
||||||
|
if (a > 0)
|
||||||
|
return 0;
|
||||||
|
if (a >= 0) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (0 == a)
|
||||||
|
return 0;
|
||||||
|
if (0 != a)
|
||||||
|
return 0;
|
||||||
|
if (0 < a)
|
||||||
|
return 0;
|
||||||
|
if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
|
||||||
|
return 0;
|
||||||
|
if (0 > a) // expected-warning {{comparison of 0 > unsigned enum expression is always false}}
|
||||||
|
return 0;
|
||||||
|
if (0 >= a)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (a == 0U)
|
||||||
|
return 0;
|
||||||
|
if (a != 0U)
|
||||||
|
return 0;
|
||||||
|
if (a < 0U) // expected-warning {{comparison of unsigned enum expression < 0 is always false}}
|
||||||
|
return 0;
|
||||||
|
if (a <= 0U)
|
||||||
|
return 0;
|
||||||
|
if (a > 0U)
|
||||||
|
return 0;
|
||||||
|
if (a >= 0U) // expected-warning {{comparison of unsigned enum expression >= 0 is always true}}
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (0U == a)
|
||||||
|
return 0;
|
||||||
|
if (0U != a)
|
||||||
|
return 0;
|
||||||
|
if (0U < a)
|
||||||
|
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 (0U >= a)
|
||||||
|
return 0;
|
||||||
|
|
||||||
return 20;
|
return 20;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -DTEST -verify %s
|
||||||
|
// RUN: %clang_cc1 -fsyntax-only -Wno-tautological-unsigned-enum-zero-compare -verify %s
|
||||||
|
|
||||||
|
int main() {
|
||||||
|
enum A { A_foo, A_bar };
|
||||||
|
enum A a;
|
||||||
|
|
||||||
|
#ifdef TEST
|
||||||
|
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}}
|
||||||
|
return 0;
|
||||||
|
if (0 <= a) // expected-warning {{comparison of 0 <= unsigned enum expression is always true}}
|
||||||
|
return 0;
|
||||||
|
if (0 > 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 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;
|
||||||
|
#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;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
Loading…
Reference in New Issue