errors/warnings, as the system frameworks might add a method with the same
selector which could make the message send to ``id`` ambiguous.
+- ``-Wtautological-compare`` now warns when comparing an unsigned integer and 0
+ regardless of whether the constant is signed or unsigned."
+
+- ``-Wtautological-compare`` now warns about comparing a signed integer and 0
+ when the signed integer is coerced to an unsigned type for the comparison.
+ ``-Wsign-compare`` was adjusted not to warn in this case.
+
Non-comprehensive list of changes in this release
-------------------------------------------------
return E->getType()->isEnumeralType();
}
-void CheckTrivialUnsignedComparison(Sema &S, BinaryOperator *E) {
+bool isNonBooleanUnsignedValue(Expr *E) {
+ // We are checking that the expression is not known to have boolean value,
+ // is an integer type; and is either unsigned after implicit casts,
+ // or was unsigned before implicit casts.
+ return !E->isKnownToHaveBooleanValue() && E->getType()->isIntegerType() &&
+ (!E->getType()->isSignedIntegerType() ||
+ !E->IgnoreParenImpCasts()->getType()->isSignedIntegerType());
+}
+
+bool CheckTautologicalComparisonWithZero(Sema &S, BinaryOperator *E) {
// Disable warning in template instantiations.
if (S.inTemplateInstantiation())
- return;
+ return false;
+
+ // bool values are handled by DiagnoseOutOfRangeComparison().
BinaryOperatorKind op = E->getOpcode();
if (E->isValueDependent())
- return;
+ return false;
+
+ Expr *LHS = E->getLHS();
+ Expr *RHS = E->getRHS();
+
+ bool Match = true;
- if (op == BO_LT && IsZero(S, E->getRHS())) {
+ if (op == BO_LT && isNonBooleanUnsignedValue(LHS) && IsZero(S, RHS)) {
S.Diag(E->getOperatorLoc(), diag::warn_lunsigned_always_true_comparison)
- << "< 0" << "false" << HasEnumType(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GE && IsZero(S, E->getRHS())) {
+ << "< 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(E->getLHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_GT && IsZero(S, E->getLHS())) {
+ << ">= 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(E->getRHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- } else if (op == BO_LE && IsZero(S, E->getLHS())) {
+ << "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(E->getRHS())
- << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
- }
+ << "0 <=" << "true" << HasEnumType(RHS)
+ << LHS->getSourceRange() << RHS->getSourceRange();
+ } else
+ Match = false;
+
+ return Match;
}
void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E, Expr *Constant,
bool OtherIsBooleanType = Other->isKnownToHaveBooleanValue();
- // 0 values are handled later by CheckTrivialUnsignedComparison().
+ // 0 values are handled later by CheckTautologicalComparisonWithZero().
if ((Value == 0) && (!OtherIsBooleanType))
return;
(IsRHSIntegralLiteral && IsLHSIntegralLiteral);
} else if (!T->hasUnsignedIntegerRepresentation())
IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
-
+
+ // We don't care about value-dependent expressions or expressions
+ // whose result is a constant.
+ if (IsComparisonConstant)
+ return AnalyzeImpConvsInComparison(S, E);
+
+ // If this is a tautological comparison, suppress -Wsign-compare.
+ if (CheckTautologicalComparisonWithZero(S, E))
+ return AnalyzeImpConvsInComparison(S, E);
+
// We don't do anything special if this isn't an unsigned integral
// comparison: we're only interested in integral comparisons, and
// signed comparisons only happen in cases we don't care to warn about.
- //
- // We also don't care about value-dependent expressions or expressions
- // whose result is a constant.
- if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
+ if (!T->hasUnsignedIntegerRepresentation())
return AnalyzeImpConvsInComparison(S, E);
-
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;
signedOperand = RHS;
unsignedOperand = LHS;
} else {
- CheckTrivialUnsignedComparison(S, E);
return AnalyzeImpConvsInComparison(S, E);
}
AnalyzeImplicitConversions(S, LHS, E->getOperatorLoc());
AnalyzeImplicitConversions(S, RHS, E->getOperatorLoc());
- // If the signed range is non-negative, -Wsign-compare won't fire,
- // but we should still check for comparisons which are always true
- // or false.
+ // If the signed range is non-negative, -Wsign-compare won't fire.
if (signedRange.NonNegative)
- return CheckTrivialUnsignedComparison(S, E);
+ return;
// For (in)equality comparisons, if the unsigned operand is a
// constant which cannot collide with a overflowed signed operand,
((int) a == (unsigned int) B) +
((short) a == (unsigned short) B) +
((signed char) a == (unsigned char) B) +
- (a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
+ (a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
(a < (unsigned int) B) +
(a < (unsigned short) B) +
(a < (unsigned char) B) +
((int) a < B) +
((short) a < B) +
((signed char) a < B) +
- ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
- ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
+ ((long) a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ ((int) a < (unsigned int) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
((short) a < (unsigned short) B) +
((signed char) a < (unsigned char) B) +
int main()
{
int a = value();
+
+ if (a == 0x0000000000000000L)
+ return 0;
+ if (a != 0x0000000000000000L)
+ return 0;
+ if (a < 0x0000000000000000L)
+ return 0;
+ if (a <= 0x0000000000000000L)
+ return 0;
+ if (a > 0x0000000000000000L)
+ return 0;
+ if (a >= 0x0000000000000000L)
+ return 0;
+
+ if (0x0000000000000000L == a)
+ return 0;
+ if (0x0000000000000000L != a)
+ return 0;
+ if (0x0000000000000000L < a)
+ return 0;
+ if (0x0000000000000000L <= a)
+ return 0;
+ if (0x0000000000000000L > a)
+ return 0;
+ if (0x0000000000000000L >= a)
+ return 0;
+
+ if (a == 0x0000000000000000UL)
+ return 0;
+ if (a != 0x0000000000000000UL)
+ return 0;
+ if (a < 0x0000000000000000UL) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return 0;
+ if (a <= 0x0000000000000000UL)
+ return 0;
+ if (a > 0x0000000000000000UL)
+ return 0;
+ if (a >= 0x0000000000000000UL) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ return 0;
+
+ if (0x0000000000000000UL == a)
+ return 0;
+ if (0x0000000000000000UL != a)
+ return 0;
+ if (0x0000000000000000UL < a)
+ return 0;
+ if (0x0000000000000000UL <= a) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+ return 0;
+ if (0x0000000000000000UL > a) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ return 0;
+ if (0x0000000000000000UL >= a)
+ return 0;
+
if (a == 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always false}}
return 0;
if (a != 0x1234567812345678L) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'int' is always true}}
return 0;
if (0x1234567812345678L >= s) // expected-warning {{comparison of constant 1311768465173141112 with expression of type 'short' is always true}}
return 0;
+
long l = value();
if (l == 0x1234567812345678L)
return 0;
return 0;
if (un != 0x0000000000000000L)
return 0;
- if (un < 0x0000000000000000L)
+ if (un < 0x0000000000000000L) // expected-warning {{comparison of unsigned expression < 0 is always false}}
return 0;
if (un <= 0x0000000000000000L)
return 0;
if (un > 0x0000000000000000L)
return 0;
- if (un >= 0x0000000000000000L)
+ if (un >= 0x0000000000000000L) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
return 0;
if (0x0000000000000000L == un)
return 0;
if (0x0000000000000000L < un)
return 0;
- if (0x0000000000000000L <= un)
+ if (0x0000000000000000L <= un) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
return 0;
- if (0x0000000000000000L > un)
+ if (0x0000000000000000L > un) // expected-warning {{comparison of 0 > unsigned expression is always false}}
return 0;
if (0x0000000000000000L >= un)
return 0;
+
+ if (un == 0x0000000000000000UL)
+ return 0;
+ if (un != 0x0000000000000000UL)
+ return 0;
+ if (un < 0x0000000000000000UL) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ return 0;
+ if (un <= 0x0000000000000000UL)
+ return 0;
+ if (un > 0x0000000000000000UL)
+ return 0;
+ if (un >= 0x0000000000000000UL) // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+ return 0;
+
+ if (0x0000000000000000UL == un)
+ return 0;
+ if (0x0000000000000000UL != un)
+ return 0;
+ if (0x0000000000000000UL < un)
+ return 0;
+ if (0x0000000000000000UL <= un) // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+ return 0;
+ if (0x0000000000000000UL > un) // expected-warning {{comparison of 0 > unsigned expression is always false}}
+ return 0;
+ if (0x0000000000000000UL >= un)
+ return 0;
+
float fl = 0;
- if (fl == 0x0000000000000000L) // no warning
- return 0;
+ if (fl == 0x0000000000000000L)
+ return 0;
+ if (fl != 0x0000000000000000L)
+ return 0;
+ if (fl < 0x0000000000000000L)
+ return 0;
+ if (fl <= 0x0000000000000000L)
+ return 0;
+ if (fl > 0x0000000000000000L)
+ return 0;
+ if (fl >= 0x0000000000000000L)
+ return 0;
- float dl = 0;
- if (dl == 0x0000000000000000L) // no warning
- return 0;
+ if (0x0000000000000000L == fl)
+ return 0;
+ if (0x0000000000000000L != fl)
+ return 0;
+ if (0x0000000000000000L < fl)
+ return 0;
+ if (0x0000000000000000L <= fl)
+ return 0;
+ if (0x0000000000000000L > fl)
+ return 0;
+ if (0x0000000000000000L >= fl)
+ return 0;
+
+ double dl = 0;
+ if (dl == 0x0000000000000000L)
+ return 0;
+ if (dl != 0x0000000000000000L)
+ return 0;
+ if (dl < 0x0000000000000000L)
+ return 0;
+ if (dl <= 0x0000000000000000L)
+ return 0;
+ if (dl > 0x0000000000000000L)
+ return 0;
+ if (dl >= 0x0000000000000000L)
+ return 0;
+
+ if (0x0000000000000000L == dl)
+ return 0;
+ if (0x0000000000000000L != dl)
+ return 0;
+ if (0x0000000000000000L < dl)
+ return 0;
+ if (0x0000000000000000L <= dl)
+ return 0;
+ if (0x0000000000000000L > dl)
+ return 0;
+ if (0x0000000000000000L >= dl)
+ return 0;
enum E {
yes,
((int) a == (unsigned int) B) +
((short) a == (unsigned short) B) +
((signed char) a == (unsigned char) B) +
- (a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
+ (a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
(a < (unsigned int) B) +
(a < (unsigned short) B) +
(a < (unsigned char) B) +
((int) a < B) +
((short) a < B) +
((signed char) a < B) +
- ((long) a < (unsigned long) B) + // expected-warning {{comparison of integers of different signs}}
- ((int) a < (unsigned int) B) + // expected-warning {{comparison of integers of different signs}}
+ ((long) a < (unsigned long) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
+ ((int) a < (unsigned int) B) + // expected-warning {{comparison of unsigned expression < 0 is always false}}
((short) a < (unsigned short) B) +
((signed char) a < (unsigned char) B) +