]> granicus.if.org Git - clang/commitdiff
Derive tighter ranges for & and >> in the conversion-checking code.
authorJohn McCall <rjmccall@apple.com>
Wed, 6 Jan 2010 22:07:33 +0000 (22:07 +0000)
committerJohn McCall <rjmccall@apple.com>
Wed, 6 Jan 2010 22:07:33 +0000 (22:07 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@92862 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Sema/SemaChecking.cpp
test/Sema/conversion.c

index 00e7242808a769302bd983924033481938bcd47c..463a03801a4ee4ffd1406e05860f42ea010ffd1e 100644 (file)
@@ -1607,7 +1607,13 @@ struct IntRange {
   // Returns the supremum of two ranges: i.e. their conservative merge.
   static IntRange join(const IntRange &L, const IntRange &R) {
     return IntRange(std::max(L.Width, R.Width),
-                        L.NonNegative && R.NonNegative);
+                    L.NonNegative && R.NonNegative);
+  }
+
+  // Returns the infinum of two ranges: i.e. their aggressive merge.
+  static IntRange meet(const IntRange &L, const IntRange &R) {
+    return IntRange(std::min(L.Width, R.Width),
+                    L.NonNegative || R.NonNegative);
   }
 };
 
@@ -1668,8 +1674,12 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
 
     IntRange OutputTypeRange = IntRange::forType(C, CE->getType());
 
+    bool isIntegerCast = (CE->getCastKind() == CastExpr::CK_IntegralCast);
+    if (!isIntegerCast && CE->getCastKind() == CastExpr::CK_Unknown)
+      isIntegerCast = CE->getSubExpr()->getType()->isIntegerType();
+
     // Assume that non-integer casts can span the full range of the type.
-    if (CE->getCastKind() != CastExpr::CK_IntegralCast)
+    if (!isIntegerCast)
       return OutputTypeRange;
 
     IntRange SubRange
@@ -1719,17 +1729,39 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
     case BinaryOperator::PtrMemI:
       return IntRange::forType(C, E->getType());
 
+    // Bitwise-and uses the *infinum* of the two source ranges.
+    case BinaryOperator::And:
+      return IntRange::meet(GetExprRange(C, BO->getLHS(), MaxWidth),
+                            GetExprRange(C, BO->getRHS(), MaxWidth));
+
     // Left shift gets black-listed based on a judgement call.
     case BinaryOperator::Shl:
       return IntRange::forType(C, E->getType());
 
-    // Various special cases.
-    case BinaryOperator::Shr:
-      // TODO: if the RHS is constant, change the width as appropriate.
-      return GetExprRange(C, BO->getLHS(), MaxWidth);
+    // Right shift by a constant can narrow its left argument.
+    case BinaryOperator::Shr: {
+      IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
+
+      // If the shift amount is a positive constant, drop the width by
+      // that much.
+      llvm::APSInt shift;
+      if (BO->getRHS()->isIntegerConstantExpr(shift, C) &&
+          shift.isNonNegative()) {
+        unsigned zext = shift.getZExtValue();
+        if (zext >= L.Width)
+          L.Width = (L.NonNegative ? 0 : 1);
+        else
+          L.Width -= zext;
+      }
+
+      return L;
+    }
+
+    // Comma acts as its right operand.
     case BinaryOperator::Comma:
       return GetExprRange(C, BO->getRHS(), MaxWidth);
 
+    // Black-list pointer subtractions.
     case BinaryOperator::Sub:
       if (BO->getLHS()->getType()->isPointerType())
         return IntRange::forType(C, E->getType());
index 44b1224b52a8ed1236c6c7c063e46e94dbd6346b..298bf7564219cbbd77adeddd4ea6ba143e118a60 100644 (file)
@@ -261,3 +261,13 @@ void test18() {
   x = (U.a ? 0 : 1);
   x = (U.b ? 0 : 1);
 }
+
+// None of these should warn.
+unsigned char test19(unsigned long u64) {
+  unsigned char x1 = u64 & 0xff;
+  unsigned char x2 = u64 >> 56;
+
+  unsigned char mask = 0xee;
+  unsigned char x3 = u64 & mask;
+  return x1 + x2 + x3;
+}