diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -591,11 +591,13 @@ def IntInBoolContext : DiagGroup<"int-in-bool-context">; def TautologicalTypeLimitCompare : DiagGroup<"tautological-type-limit-compare">; def TautologicalUnsignedZeroCompare : DiagGroup<"tautological-unsigned-zero-compare">; +def TautologicalUnsignedCharZeroCompare : DiagGroup<"tautological-unsigned-char-zero-compare">; def TautologicalUnsignedEnumZeroCompare : DiagGroup<"tautological-unsigned-enum-zero-compare">; // For compatibility with GCC. Tautological comparison warnings for constants // that are an extremal value of the type. def TypeLimits : DiagGroup<"type-limits", [TautologicalTypeLimitCompare, TautologicalUnsignedZeroCompare, + TautologicalUnsignedCharZeroCompare, TautologicalUnsignedEnumZeroCompare]>; // Additional tautological comparison warnings based on the expression, not // only on its type. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -6784,6 +6784,10 @@ "result of comparison of %select{%3|unsigned expression}0 %2 " "%select{unsigned expression|%3}0 is always %4">, InGroup, DefaultIgnore; +def warn_unsigned_char_always_true_comparison : Warning< + "result of comparison of %select{%3|char expression}0 %2 " + "%select{char expression|%3}0 is always %4, since char is interpreted as " + "unsigned">, InGroup, 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">, diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -11415,11 +11415,14 @@ << OtherIsBooleanDespiteType << *Result << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange()); } else { - unsigned Diag = (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) - ? (HasEnumType(OriginalOther) - ? diag::warn_unsigned_enum_always_true_comparison - : diag::warn_unsigned_always_true_comparison) - : diag::warn_tautological_constant_compare; + bool IsCharTy = OtherT.withoutLocalFastQualifiers() == S.Context.CharTy; + unsigned Diag = + (isKnownToHaveUnsignedValue(OriginalOther) && Value == 0) + ? (HasEnumType(OriginalOther) + ? diag::warn_unsigned_enum_always_true_comparison + : IsCharTy ? diag::warn_unsigned_char_always_true_comparison + : diag::warn_unsigned_always_true_comparison) + : diag::warn_tautological_constant_compare; S.Diag(E->getOperatorLoc(), Diag) << RhsConstant << OtherT << E->getOpcodeStr() << OS.str() << *Result diff --git a/clang/test/Sema/tautological-unsigned-char-zero-compare.cc b/clang/test/Sema/tautological-unsigned-char-zero-compare.cc new file mode 100644 --- /dev/null +++ b/clang/test/Sema/tautological-unsigned-char-zero-compare.cc @@ -0,0 +1,39 @@ +// RUN: %clang_cc1 -fsyntax-only \ +// RUN: -fno-signed-char \ +// RUN: -Wtautological-unsigned-zero-compare \ +// RUN: -Wtautological-unsigned-char-zero-compare \ +// RUN: -verify=unsigned %s +// RUN: %clang_cc1 -fsyntax-only \ +// RUN: -Wtautological-unsigned-zero-compare \ +// RUN: -Wtautological-unsigned-char-zero-compare \ +// RUN: -verify=signed %s + +void f(char c, unsigned char uc, signed char cc) { + if (c < 0) + return; + // unsigned-warning@-2 {{comparison of char expression < 0 is always false, since char is interpreted as unsigned}} + if (uc < 0) + return; + // unsigned-warning@-2 {{comparison of unsigned expression < 0 is always false}} + // signed-warning@-3 {{comparison of unsigned expression < 0 is always false}} + if (cc < 0) + return; + // Promoted to integer expressions should not warn. + if (c - 4 < 0) + return; +} + +void ref(char &c, unsigned char &uc, signed char &cc) { + if (c < 0) + return; + // unsigned-warning@-2 {{comparison of char expression < 0 is always false, since char is interpreted as unsigned}} + if (uc < 0) + return; + // unsigned-warning@-2 {{comparison of unsigned expression < 0 is always false}} + // signed-warning@-3 {{comparison of unsigned expression < 0 is always false}} + if (cc < 0) + return; + // Promoted to integer expressions should not warn. + if (c - 4 < 0) + return; +}