Add missing test case as pointed out by Eli.

http://llvm-reviews.chandlerc.com/D113

CHANGE SINCE LAST DIFF
  http://llvm-reviews.chandlerc.com/D113?vs=320&id=327#toc

Files:
  test/Analysis/additive-folding.cpp
  test/SemaCXX/compare.cpp
  lib/Sema/SemaChecking.cpp
Index: test/Analysis/additive-folding.cpp
===================================================================
--- test/Analysis/additive-folding.cpp
+++ test/Analysis/additive-folding.cpp
@@ -1,4 +1,4 @@
-// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare -Wtautological-constant-out-of-range-compare %s
+// RUN: %clang_cc1 -analyze -analyzer-checker=core,debug.ExprInspection -verify -analyzer-constraints=range -Wno-tautological-compare %s
 
 void clang_analyzer_eval(bool);
 
@@ -128,10 +128,10 @@
 
 // Tautologies from outside the range of the symbol
 void tautologiesOutside(unsigned char a) {
-  clang_analyzer_eval(a <= 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
-  clang_analyzer_eval(a < 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
+  clang_analyzer_eval(a <= 0x100); // expected-warning{{TRUE}}
+  clang_analyzer_eval(a < 0x100); // expected-warning{{TRUE}}
 
-  clang_analyzer_eval(a != 0x100); // expected-warning{{comparison of constant 256 with expression of type 'unsigned char' is always true}} expected-warning{{TRUE}}
+  clang_analyzer_eval(a != 0x100); // expected-warning{{TRUE}}
   clang_analyzer_eval(a != -1); // expected-warning{{TRUE}}
 
   clang_analyzer_eval(a > -1); // expected-warning{{TRUE}}
Index: test/SemaCXX/compare.cpp
===================================================================
--- test/SemaCXX/compare.cpp
+++ test/SemaCXX/compare.cpp
@@ -223,3 +223,118 @@
   (void) (true ? b : a);
   (void) (true ? (unsigned char)b : (signed char)a);
 }
+
+// Test comparison of short to unsigned.  If tautological compare does not
+// trigger, then the signed comparision warning will.
+void test4(short s) {
+  // A is max short plus 1.  All zero and positive shorts are smaller than it.
+  // All negative shorts are cast towards the max unsigned range.  Relation
+  // comparisons are possible, but equality comparisons are tautological.
+  const unsigned A = 32768;
+  void (s < A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s > A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s <= A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s >= A); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+
+  void (s == A); // expected-warning{{comparison of constant 32768 with expression of type 'short' is always false}}
+  void (s != A); // expected-warning{{comparison of constant 32768 with expression of type 'short' is always true}}
+
+  // When negative one is converted to an unsigned value, it becomes the max
+  // unsigned.  Likewise, a negative one short can also be converted to max
+  // unsigned.
+  const unsigned B = -1;
+  void (s < B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s > B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s <= B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s >= B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s == B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+  void (s != B); // expected-warning{{comparison of integers of different signs: 'short' and 'const unsigned int'}}
+
+}
+
+void test5(bool b) {
+  (void) (b < -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+  (void) (b > -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+  (void) (b == -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+  (void) (b != -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+  (void) (b <= -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always false}}
+  (void) (b >= -1); // expected-warning{{comparison of constant -1 with expression of type 'bool' is always true}}
+
+  (void) (b < -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+  (void) (b > -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+  (void) (b == -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+  (void) (b != -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+  (void) (b <= -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always false}}
+  (void) (b >= -10); // expected-warning{{comparison of constant -10 with expression of type 'bool' is always true}}
+
+  (void) (b < 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+  (void) (b > 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+  (void) (b == 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+  (void) (b != 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+  (void) (b <= 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always true}}
+  (void) (b >= 2); // expected-warning{{comparison of constant 2 with expression of type 'bool' is always false}}
+
+  (void) (b < 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+  (void) (b > 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+  (void) (b == 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+  (void) (b != 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+  (void) (b <= 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always true}}
+  (void) (b >= 10); // expected-warning{{comparison of constant 10 with expression of type 'bool' is always false}}
+}
+
+void test6(signed char sc) {
+  (void)(sc < 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+  (void)(sc > 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(sc <= 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+  (void)(sc >= 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(sc == 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(sc != 200); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+
+  (void)(200 < sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(200 > sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+  (void)(200 <= sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(200 >= sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+  (void)(200 == sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always false}}
+  (void)(200 != sc); // expected-warning{{comparison of constant 200 with expression of type 'signed char' is always true}}
+}
+
+// Test many signedness combinations.
+void test7(unsigned long other) {
+  // Common unsigned, other unsigned, constant unsigned
+  (void)((unsigned)other != (unsigned long)(0x1ffffffff)); // expected-warning{{true}}
+  (void)((unsigned)other != (unsigned long)(0xffffffff));
+  (void)((unsigned long)other != (unsigned)(0x1ffffffff));
+  (void)((unsigned long)other != (unsigned)(0xffffffff));
+
+  // Common unsigned, other signed, constant unsigned
+  (void)((int)other != (unsigned long)(0xffffffffffffffff)); // expected-warning{{different signs}}
+  (void)((int)other != (unsigned long)(0x00000000ffffffff)); // expected-warning{{true}}
+  (void)((int)other != (unsigned long)(0x000000000fffffff));
+
+  // Common unsigned, other unsigned, constant signed
+  (void)((unsigned long)other != (int)(0xffffffff));  // expected-warning{{different signs}}
+  (void)((int)other != (unsigned long)(0xffffffff));  // expected-warning{{true}}
+  (void)((int)other != (unsigned long)(0xffffffffffffff00));  // expected-warning{{different signs}}
+
+  // Common unsigned, other signed, constant signed
+  // Should not be possible as the common type should also be signed.
+
+  // Common signed, other signed, constant signed
+  (void)((int)other != (long)(0xffffffff));  // expected-warning{{true}}
+  (void)((int)other != (long)(0xffffffff00000000));  // expected-warning{{true}}
+  (void)((int)other != (long)(0xfffffff));
+  (void)((int)other != (long)(0xfffffffff0000000));
+
+  // Common signed, other signed, constant unsigned
+  (void)((int)other != (unsigned char)(0xffff));
+  (void)((int)other != (unsigned char)(0xff));
+
+  // Common signed, other unsigned, constant signed
+  (void)((unsigned char)other != (int)(0xff));
+  (void)((unsigned char)other != (int)(0xffff));  // expected-warning{{true}}
+
+  // Common signed, other unsigned, constant unsigned
+  (void)((unsigned char)other != (unsigned short)(0xff));
+  (void)((unsigned char)other != (unsigned short)(0x100)); // expected-warning{{true}}
+  (void)((unsigned short)other != (unsigned char)(0xff));
+}
Index: lib/Sema/SemaChecking.cpp
===================================================================
--- lib/Sema/SemaChecking.cpp
+++ lib/Sema/SemaChecking.cpp
@@ -4328,38 +4328,97 @@
                                          Expr *Constant, Expr *Other,
                                          llvm::APSInt Value,
                                          bool RhsConstant) {
+  // 0 values are handled later by CheckTrivialUnsignedComparison().
+  if (Value == 0)
+    return;
+
   BinaryOperatorKind op = E->getOpcode();
   QualType OtherT = Other->getType();
   QualType ConstantT = Constant->getType();
+  QualType CommonT = E->getLHS()->getType();
   if (S.Context.hasSameUnqualifiedType(OtherT, ConstantT))
     return;
   assert((OtherT->isIntegerType() && ConstantT->isIntegerType())
          && "comparison with non-integer type");
-  // FIXME. handle cases for signedness to catch (signed char)N == 200
+
+  bool ConstantSigned = ConstantT->isSignedIntegerType();
+  bool OtherSigned = OtherT->isSignedIntegerType();
+  bool CommonSigned = CommonT->isSignedIntegerType();
+
+  bool EqualityOnly = false;
+
+  // TODO: Investigate using GetExprRange() to get tighter bounds on
+  // on the bit ranges.
   IntRange OtherRange = IntRange::forValueOfType(S.Context, OtherT);
-  IntRange LitRange = GetValueRange(S.Context, Value, Value.getBitWidth());
-  if (OtherRange.Width >= LitRange.Width)
+  unsigned OtherWidth = OtherRange.Width;
+  
+  if (CommonSigned) {
+    // The common type is signed, therefore no signed to unsigned conversion.
+    if (OtherSigned) {
+      // Check that the constant is representable in type OtherT.
+      if (ConstantSigned) {
+        if (OtherWidth >= Value.getMinSignedBits())
+          return;
+      } else { // !ConstantSigned
+        if (OtherWidth >= Value.getActiveBits() + 1)
+          return;
+      }
+    } else { // !OtherSigned
+      // Check that the constant is representable in type OtherT.
+      // Negative values are out of range.
+      if (ConstantSigned) {
+        if (Value.isNonNegative() && OtherWidth >= Value.getActiveBits())
+          return;
+      } else { // !ConstantSigned
+        if (OtherWidth >= Value.getActiveBits())
+          return;
+      }
+    }
+  } else {  // !CommonSigned
+    if (!OtherSigned) {
+      if (OtherWidth >= Value.getActiveBits())
+        return;
+    } else if (OtherSigned && !ConstantSigned) {
+      // Check to see if the constant is representable in OtherT.
+      if (OtherWidth > Value.getActiveBits())
+        return;
+      // Check to see if the constant is equivalent to a negative value
+      // cast to CommonT.
+      if (S.Context.getIntWidth(ConstantT) == S.Context.getIntWidth(CommonT) &&
+          Value.isNegative() && Value.getMinSignedBits() < OtherWidth)
+        return;
+      // The constant value rests between values that OtherT can represent after
+      // conversion.  Relational comparison still works, but equality
+      // comparisons will be tautological.
+      if (OtherWidth <= Value.getActiveBits())
+        EqualityOnly = true;
+    } else { // OtherSigned && ConstantSigned
+      assert(0 && "Two signed types converted to unsigned types.");
+    }
+  }
+
+  bool PositiveConstant = !ConstantSigned || Value.isNonNegative();
+
+  bool IsTrue = true;
+  if (op == BO_EQ || op == BO_NE) {
+    IsTrue = op == BO_NE;
+  } else if (EqualityOnly) {
     return;
-  bool IsTrue = true;
-  if (op == BO_EQ)
-    IsTrue = false;
-  else if (op == BO_NE)
-    IsTrue = true;
-  else if (RhsConstant) {
+  } else if (RhsConstant) {
     if (op == BO_GT || op == BO_GE)
-      IsTrue = !LitRange.NonNegative;
+      IsTrue = !PositiveConstant;
     else // op == BO_LT || op == BO_LE
-      IsTrue = LitRange.NonNegative;
+      IsTrue = PositiveConstant;
   } else {
     if (op == BO_LT || op == BO_LE)
-      IsTrue = !LitRange.NonNegative;
+      IsTrue = !PositiveConstant;
     else // op == BO_GT || op == BO_GE
-      IsTrue = LitRange.NonNegative;
+      IsTrue = PositiveConstant;
   }
   SmallString<16> PrettySourceValue(Value.toString(10));
   S.Diag(E->getOperatorLoc(), diag::warn_out_of_range_compare)
-  << PrettySourceValue << OtherT << IsTrue
-  << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
+      << PrettySourceValue << OtherT << IsTrue
+      << E->getLHS()->getSourceRange() << E->getRHS()->getSourceRange();
 }
 
 /// Analyze the operands of the given comparison.  Implements the
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits

Reply via email to