diff options
author | John McCall <rjmccall@apple.com> | 2009-11-06 08:49:08 +0000 |
---|---|---|
committer | John McCall <rjmccall@apple.com> | 2009-11-06 08:49:08 +0000 |
commit | 5dbad3d46c43e8051dac0c3775bcbaf8f1a6b8fe (patch) | |
tree | 1db2e008ab573ba1f0bc372e8e868b1abd922c9f /lib/Sema/SemaExpr.cpp | |
parent | 4c2620705b87ab6899fb2756bf191bb89d1995c8 (diff) |
Improve the -Wsign-compare heuristics:
* If the unsigned type is smaller than the signed type, never warn, because
its value will not change when zero-extended to the larger type.
* If we're testing for (in)equality, and the unsigned value is an integer
constant whose sign bit is not set, never warn, because even though the
signed value might change, it can't affect the result of the equality.
Also make the comparison test cases much more rigorous, and have them expose
the subtle differences between C and C++ here.
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@86242 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema/SemaExpr.cpp')
-rw-r--r-- | lib/Sema/SemaExpr.cpp | 39 |
1 files changed, 35 insertions, 4 deletions
diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 031bbe77ac..d92f4b99ff 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -4445,9 +4445,15 @@ QualType Sema::CheckShiftOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, return LHSTy; } -/// Implements -Wsign-compare. +/// \brief Implements -Wsign-compare. +/// +/// \param lex the left-hand expression +/// \param rex the right-hand expression +/// \param OpLoc the location of the joining operator +/// \param Equality whether this is an "equality-like" join; +/// this suppresses the warning in some cases void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, - const PartialDiagnostic &PD) { + const PartialDiagnostic &PD, bool Equality) { QualType lt = lex->getType(), rt = rex->getType(); // Only warn if both operands are integral. @@ -4461,15 +4467,25 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, // The rule is that the signed operand becomes unsigned, so isolate the // signed operand. - Expr *signedOperand; + Expr *signedOperand, *unsignedOperand; if (lt->isSignedIntegerType()) { if (rt->isSignedIntegerType()) return; signedOperand = lex; + unsignedOperand = rex; } else { if (!rt->isSignedIntegerType()) return; signedOperand = rex; + unsignedOperand = lex; } + // If the unsigned type is strictly smaller than the signed type, + // then (1) the result type will be signed and (2) the unsigned type + // will fight losslessly within the signed type, and so the result + // of the comparison will be exact. + if (Context.getIntWidth(signedOperand->getType()) > + Context.getIntWidth(unsignedOperand->getType())) + return; + // If the value is a non-negative integer constant, then the // signed->unsigned conversion won't change it. llvm::APSInt value; @@ -4480,6 +4496,20 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc, return; } + if (Equality) { + // For (in)equality comparisons, if the unsigned operand is a + // constant no greater than the maximum signed operand, then + // reinterpreting the signed operand as unsigned will not change + // the result of the comparison. + if (unsignedOperand->isIntegerConstantExpr(value, Context)) { + assert(!value.isSigned() && "result of unsigned expression is signed"); + + // 2's complement: test the top bit. + if (value.isNonNegative()) + return; + } + } + Diag(OpLoc, PD) << lex->getType() << rex->getType() << lex->getSourceRange() << rex->getSourceRange(); @@ -4493,7 +4523,8 @@ QualType Sema::CheckCompareOperands(Expr *&lex, Expr *&rex, SourceLocation Loc, if (lex->getType()->isVectorType() || rex->getType()->isVectorType()) return CheckVectorCompareOperands(lex, rex, Loc, isRelational); - CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison); + CheckSignCompare(lex, rex, Loc, diag::warn_mixed_sign_comparison, + (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE)); // C99 6.5.8p3 / C99 6.5.9p4 if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType()) |