c: warn when an integer value comparison with an
integral expression have the obvious result.
Patch reviewed by John McCall off line.
// rdar://12202422
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164143 91177308-0d34-0410-b5e6-96231b3b80d8
diff --git a/lib/Sema/SemaChecking.cpp b/lib/Sema/SemaChecking.cpp
index 4c8418a..ed5517d 100644
--- a/lib/Sema/SemaChecking.cpp
+++ b/lib/Sema/SemaChecking.cpp
@@ -4301,6 +4301,45 @@
}
}
+static void DiagnoseOutOfRangeComparison(Sema &S, BinaryOperator *E,
+ Expr *lit, Expr *other,
+ llvm::APSInt Value,
+ bool rhsLiteral) {
+ BinaryOperatorKind op = E->getOpcode();
+ QualType OtherT = other->getType();
+ const Type *OtherPtrT = S.Context.getCanonicalType(OtherT).getTypePtr();
+ const Type *LitPtrT = S.Context.getCanonicalType(lit->getType()).getTypePtr();
+ if (OtherPtrT == LitPtrT)
+ return;
+ assert((OtherT->isIntegerType() && LitPtrT->isIntegerType())
+ && "comparison with non-integer type");
+ IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
+ IntRange LitRange = GetExprRange(S.Context, lit);
+ if (OtherRange.Width >= LitRange.Width)
+ return;
+ std::string PrettySourceValue = Value.toString(10);
+ bool IsTrue = true;
+ if (op == BO_EQ)
+ IsTrue = false;
+ else if (op == BO_NE)
+ IsTrue = true;
+ else if (rhsLiteral) {
+ if (op == BO_GT || op == BO_GE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_LT || op == BO_LE
+ IsTrue = LitRange.NonNegative;
+ }
+ else {
+ if (op == BO_LT || op == BO_LE)
+ IsTrue = !LitRange.NonNegative;
+ else // op == BO_GT || op == BO_GE
+ IsTrue = LitRange.NonNegative;
+ }
+ S.Diag(E->getOperatorLoc(), diag::warn_outof_range_compare)
+ << PrettySourceValue << other->getType() << IsTrue
+ << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+}
+
/// Analyze the operands of the given comparison. Implements the
/// fallback case from AnalyzeComparison.
static void AnalyzeImpConvsInComparison(Sema &S, BinaryOperator *E) {
@@ -4317,19 +4356,42 @@
assert(S.Context.hasSameUnqualifiedType(T, E->getRHS()->getType())
&& "comparison with mismatched types");
+ Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
+ Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
+ if (E->isValueDependent())
+ return AnalyzeImpConvsInComparison(S, E);
+
+ bool IsComparisonConstant = false;
+
+ // Check that an integer constant comparison results in a value
+ // of 'true' or 'false'.
+ if (T->isIntegralType(S.Context)) {
+ llvm::APSInt RHSValue;
+ bool IsRHSIntegralLiteral =
+ RHS->isIntegerConstantExpr(RHSValue, S.Context);
+ llvm::APSInt LHSValue;
+ bool IsLHSIntegralLiteral =
+ LHS->isIntegerConstantExpr(LHSValue, S.Context);
+ if (IsRHSIntegralLiteral && !IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, RHS, LHS, RHSValue, true);
+ else if (!IsRHSIntegralLiteral && IsLHSIntegralLiteral)
+ DiagnoseOutOfRangeComparison(S, E, LHS, RHS, LHSValue, false);
+ else
+ IsComparisonConstant =
+ (IsRHSIntegralLiteral && IsLHSIntegralLiteral);
+ }
+ else if (!T->hasUnsignedIntegerRepresentation())
+ IsComparisonConstant = E->isIntegerConstantExpr(S.Context);
+
// 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()
- || E->isValueDependent() || E->isIntegerConstantExpr(S.Context))
+ if (!T->hasUnsignedIntegerRepresentation() || IsComparisonConstant)
return AnalyzeImpConvsInComparison(S, E);
-
- Expr *LHS = E->getLHS()->IgnoreParenImpCasts();
- Expr *RHS = E->getRHS()->IgnoreParenImpCasts();
-
+
// Check to see if one of the (unmodified) operands is of different
// signedness.
Expr *signedOperand, *unsignedOperand;