]> granicus.if.org Git - clang/commitdiff
Warn about comparing an unsigned expression with 0 in tautological ways.
authorJohn McCall <rjmccall@apple.com>
Thu, 11 Mar 2010 19:43:18 +0000 (19:43 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 11 Mar 2010 19:43:18 +0000 (19:43 +0000)
Patch by mikem!

git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@98279 91177308-0d34-0410-b5e6-96231b3b80d8

include/clang/Basic/DiagnosticSemaKinds.td
lib/Sema/Sema.h
lib/Sema/SemaChecking.cpp
lib/Sema/SemaExpr.cpp
lib/Sema/SemaExprCXX.cpp
test/Sema/compare.c

index 1e1c0aa3171482dba8d3dc070ecc03798c9df40b..175fbe9c0f89ab425345aa7f9a88e39005136610 100644 (file)
@@ -1857,6 +1857,12 @@ def warn_mixed_sign_comparison : Warning<
 def warn_mixed_sign_conditional : Warning<
   "operands of ? are integers of different signs: %0 and %1">,
   InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+def warn_lunsigned_always_true_comparison : Warning<
+  "comparison of unsigned expression %0 is always %1">,
+  InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
+def warn_runsigned_always_true_comparison : Warning<
+  "comparison of %0 unsigned expression is always %1">,
+  InGroup<DiagGroup<"sign-compare">>, DefaultIgnore;
 
 def err_invalid_this_use : Error<
   "invalid use of 'this' outside of a nonstatic member function">;
index c9f39e2b992f6404a2b843de4e0745b4b92e8089..0012435124cb0e1733dbb16ed09a95cd64c29955 100644 (file)
@@ -4245,8 +4245,7 @@ private:
                             SourceLocation ReturnLoc);
   void CheckFloatComparison(SourceLocation loc, Expr* lex, Expr* rex);
   void CheckSignCompare(Expr *LHS, Expr *RHS, SourceLocation Loc,
-                        const PartialDiagnostic &PD,
-                        bool Equality = false);
+                        const BinaryOperator::Opcode* BinOpc = 0);
   void CheckImplicitConversion(Expr *E, QualType Target);
 };
 
index 30a6ab4655388ae654dd218befa86020b2a15e03..544d66b503e81114aed13c3d2e4a9239d78482ea 100644 (file)
@@ -2011,10 +2011,9 @@ bool IsSameFloatAfterCast(const APValue &value,
 /// \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, which
-///   suppresses the warning in some cases
+/// \param BinOpc binary opcode or 0
 void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
-                            const PartialDiagnostic &PD, bool Equality) {
+                            const BinaryOperator::Opcode* BinOpc) {
   // Don't warn if we're in an unevaluated context.
   if (ExprEvalContexts.back().Context == Unevaluated)
     return;
@@ -2075,17 +2074,51 @@ void Sema::CheckSignCompare(Expr *lex, Expr *rex, SourceLocation OpLoc,
 
   // If the signed operand is non-negative, then the signed->unsigned
   // conversion won't change it.
-  if (signedRange.NonNegative)
+  if (signedRange.NonNegative) {
+    // Emit warnings for comparisons of unsigned to integer constant 0.
+    //   always false: x < 0  (or 0 > x)
+    //   always true:  x >= 0 (or 0 <= x)
+    llvm::APSInt X;
+    if (BinOpc && signedOperand->isIntegerConstantExpr(X, Context) && X == 0) {
+      if (signedOperand != lex) {
+        if (*BinOpc == BinaryOperator::LT) {
+          Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
+            << "< 0" << "false"
+            << lex->getSourceRange() << rex->getSourceRange();
+        }
+        else if (*BinOpc == BinaryOperator::GE) {
+          Diag(OpLoc, diag::warn_lunsigned_always_true_comparison)
+            << ">= 0" << "true"
+            << lex->getSourceRange() << rex->getSourceRange();
+        }
+      }
+      else {
+        if (*BinOpc == BinaryOperator::GT) {
+          Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
+            << "0 >" << "false" 
+            << lex->getSourceRange() << rex->getSourceRange();
+        } 
+        else if (*BinOpc == BinaryOperator::LE) {
+          Diag(OpLoc, diag::warn_runsigned_always_true_comparison)
+            << "0 <=" << "true" 
+            << lex->getSourceRange() << rex->getSourceRange();
+        }
+      }
+    }
     return;
+  }
 
   // For (in)equality comparisons, if the unsigned operand is a
   // constant which cannot collide with a overflowed signed operand,
   // then reinterpreting the signed operand as unsigned will not
   // change the result of the comparison.
-  if (Equality && unsignedRange.Width < unsignedWidth)
+  if (BinOpc &&
+      (*BinOpc == BinaryOperator::EQ || *BinOpc == BinaryOperator::NE) &&
+      unsignedRange.Width < unsignedWidth)
     return;
 
-  Diag(OpLoc, PD)
+  Diag(OpLoc, BinOpc ? diag::warn_mixed_sign_comparison
+                     : diag::warn_mixed_sign_conditional)
     << lt << rt << lex->getSourceRange() << rex->getSourceRange();
 }
 
index 2249579ba4e1aa99700a8bd43b8aa764b9d9d54e..5d352ceb04722cc2b29fb332039544ec6e6f4947 100644 (file)
@@ -4105,7 +4105,7 @@ QualType Sema::CheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   if (getLangOptions().CPlusPlus)
     return CXXCheckConditionalOperands(Cond, LHS, RHS, QuestionLoc);
 
-  CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional);
+  CheckSignCompare(LHS, RHS, QuestionLoc);
 
   UsualUnaryConversions(Cond);
   UsualUnaryConversions(LHS);
@@ -5282,8 +5282,7 @@ 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,
-                   (Opc == BinaryOperator::EQ || Opc == BinaryOperator::NE));
+  CheckSignCompare(lex, rex, Loc, &Opc);
 
   // C99 6.5.8p3 / C99 6.5.9p4
   if (lex->getType()->isArithmeticType() && rex->getType()->isArithmeticType())
index b9c8afa195fda2d3853d1b318053d7586896ea73..e1e5efa7d3a9396a32105fce1ac85e5561d3375c 100644 (file)
@@ -2085,7 +2085,7 @@ QualType Sema::CXXCheckConditionalOperands(Expr *&Cond, Expr *&LHS, Expr *&RHS,
   if (LHS->isTypeDependent() || RHS->isTypeDependent())
     return Context.DependentTy;
 
-  CheckSignCompare(LHS, RHS, QuestionLoc, diag::warn_mixed_sign_conditional);
+  CheckSignCompare(LHS, RHS, QuestionLoc);
 
   // C++0x 5.16p2
   //   If either the second or the third operand has type (cv) void, ...
index 2821a935c3c707df2aeeed3ed4229e78489b283e..7c8c36f0c145b44681f874884f1d41f33b79a865 100644 (file)
@@ -274,3 +274,11 @@ void test4() {
   if (value < (unsigned long) &ptr4) // expected-warning {{comparison of integers of different signs}}
     return;
 }
+
+// PR4807
+int test5(unsigned int x) {
+  return (x < 0) // expected-warning {{comparison of unsigned expression < 0 is always false}}
+    && (0 > x)   // expected-warning {{comparison of 0 > unsigned expression is always false}}
+    && (x >= 0)  // expected-warning {{comparison of unsigned expression >= 0 is always true}}
+    && (0 <= x); // expected-warning {{comparison of 0 <= unsigned expression is always true}}
+}