summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td2
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td19
-rw-r--r--clang/lib/Sema/SemaChecking.cpp42
-rw-r--r--clang/test/Sema/compare.c53
-rw-r--r--clang/test/Sema/tautological-unsigned-enum-zero-compare.c46
5 files changed, 138 insertions, 24 deletions
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 4ebcf256ebf..a7115fdd60a 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -429,12 +429,14 @@ def StringPlusInt : DiagGroup<"string-plus-int">;
def StringPlusChar : DiagGroup<"string-plus-char">;
def StrncatSize : DiagGroup<"strncat-size">;
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 TautologicalPointerCompare : DiagGroup<"tautological-pointer-compare">;
def TautologicalOverlapCompare : DiagGroup<"tautological-overlap-compare">;
def TautologicalUndefinedCompare : DiagGroup<"tautological-undefined-compare">;
def TautologicalCompare : DiagGroup<"tautological-compare",
[TautologicalUnsignedZeroCompare,
+ TautologicalUnsignedEnumZeroCompare,
TautologicalOutOfRangeCompare,
TautologicalPointerCompare,
TautologicalOverlapCompare,
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index f851e29431d..7b0ca3b9aeb 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -5906,19 +5906,26 @@ def note_typecheck_assign_const : Note<
"member function %q1 is declared const here|"
"%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<
"comparison of integers of different signs: %0 and %1">,
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<
"comparison of %select{constant %0|true|false}1 with "
"%select{expression of type %2|boolean expression}3 is always "
"%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<
"comparison of two values with different enumeration types"
"%diff{ ($ and $)|}0,1">,
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 212fe65c76f..6544cb923b1 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -8583,7 +8583,7 @@ bool CheckTautologicalComparisonWithZero(Sema &S, BinaryOperator *E) {
// bool values are handled by DiagnoseOutOfRangeComparison().
- BinaryOperatorKind op = E->getOpcode();
+ BinaryOperatorKind Op = E->getOpcode();
if (E->isValueDependent())
return false;
@@ -8592,22 +8592,30 @@ bool CheckTautologicalComparisonWithZero(Sema &S, BinaryOperator *E) {
bool Match = true;
- if (op == BO_LT && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false" << HasEnumType(LHS)
- << LHS->getSourceRange() << RHS->getSourceRange();
- } else if (op == BO_GE && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
- S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << ">= 0" << "true" << HasEnumType(LHS)
- << LHS->getSourceRange() << RHS->getSourceRange();
- } else if (op == BO_GT && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 >" << "false" << HasEnumType(RHS)
- << LHS->getSourceRange() << RHS->getSourceRange();
- } else if (op == BO_LE && isNonBooleanUnsignedValue(RHS) && IsZero(S, LHS)) {
- S.Diag(E->getOperatorLoc(), diag::warn_runsigned_always_true_comparison)
- << "0 <=" << "true" << HasEnumType(RHS)
- << LHS->getSourceRange() << RHS->getSourceRange();
+ if (Op == BO_LT && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
+ S.Diag(E->getOperatorLoc(),
+ HasEnumType(LHS) ? diag::warn_lunsigned_enum_always_true_comparison
+ : diag::warn_lunsigned_always_true_comparison)
+ << "< 0"
+ << "false" << LHS->getSourceRange() << RHS->getSourceRange();
+ } else if (Op == BO_GE && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
+ S.Diag(E->getOperatorLoc(),
+ HasEnumType(LHS) ? diag::warn_lunsigned_enum_always_true_comparison
+ : diag::warn_lunsigned_always_true_comparison)
+ << ">= 0"
+ << "true" << LHS->getSourceRange() << RHS->getSourceRange();
+ } else if (Op == BO_GT && 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 >"
+ << "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
Match = false;
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index ae261432dcd..97586a7cc05 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -308,8 +308,59 @@ int rdar8414119_bar(unsigned x) {
int rdar8511238() {
enum A { A_foo, A_bar };
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}}
- 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;
}
diff --git a/clang/test/Sema/tautological-unsigned-enum-zero-compare.c b/clang/test/Sema/tautological-unsigned-enum-zero-compare.c
new file mode 100644
index 00000000000..a0c2a30055c
--- /dev/null
+++ b/clang/test/Sema/tautological-unsigned-enum-zero-compare.c
@@ -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;
+}
OpenPOWER on IntegriCloud