]> granicus.if.org Git - clang/commitdiff
Teach -Wconversion, -Wsign-compare etc. about division and remainder.
authorJohn McCall <rjmccall@apple.com>
Thu, 14 Jul 2011 22:39:48 +0000 (22:39 +0000)
committerJohn McCall <rjmccall@apple.com>
Thu, 14 Jul 2011 22:39:48 +0000 (22:39 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@135208 91177308-0d34-0410-b5e6-96231b3b80d8

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

index 267cda8f4016ca935873eac6d22bb82906201051..3b48201eddf2a2de442a3a47e43963ad2846954e 100644 (file)
@@ -2659,14 +2659,54 @@ IntRange GetExprRange(ASTContext &C, Expr *E, unsigned MaxWidth) {
     case BO_Sub:
       if (BO->getLHS()->getType()->isPointerType())
         return IntRange::forValueOfType(C, E->getType());
-      // fallthrough
+      break;
 
-    default:
+    // The width of a division result is mostly determined by the size
+    // of the LHS.
+    case BO_Div: {
+      // Don't 'pre-truncate' the operands.
+      unsigned opWidth = C.getIntWidth(E->getType());
+      IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+
+      // If the divisor is constant, use that.
+      llvm::APSInt divisor;
+      if (BO->getRHS()->isIntegerConstantExpr(divisor, C)) {
+        unsigned log2 = divisor.logBase2(); // floor(log_2(divisor))
+        if (log2 >= L.Width)
+          L.Width = (L.NonNegative ? 0 : 1);
+        else
+          L.Width = std::min(L.Width - log2, MaxWidth);
+        return L;
+      }
+
+      // Otherwise, just use the LHS's width.
+      IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+      return IntRange(L.Width, L.NonNegative && R.NonNegative);
+    }
+
+    // The result of a remainder can't be larger than the result of
+    // either side.
+    case BO_Rem: {
+      // Don't 'pre-truncate' the operands.
+      unsigned opWidth = C.getIntWidth(E->getType());
+      IntRange L = GetExprRange(C, BO->getLHS(), opWidth);
+      IntRange R = GetExprRange(C, BO->getRHS(), opWidth);
+
+      IntRange meet = IntRange::meet(L, R);
+      meet.Width = std::min(meet.Width, MaxWidth);
+      return meet;
+    }
+
+    // The default behavior is okay for these.
+    case BO_Mul:
+    case BO_Add:
+    case BO_Xor:
+    case BO_Or:
       break;
     }
 
-    // Treat every other operator as if it were closed on the
-    // narrowest type that encompasses both operands.
+    // The default case is to treat the operation as if it were closed
+    // on the narrowest type that encompasses both operands.
     IntRange L = GetExprRange(C, BO->getLHS(), MaxWidth);
     IntRange R = GetExprRange(C, BO->getRHS(), MaxWidth);
     return IntRange::join(L, R);
index 1eaf7082d67e75797e237a3499b16bd3b54b79f9..03204c63e9651edd3d897cb96aa3f338b4ecbac4 100644 (file)
@@ -335,3 +335,11 @@ void test_8559831(enum E8559831b value_a, E8559831c value_c) {
    enum E8559831a a3 = value_d;
    a3 = value_d;
 }
+
+void test26(int si, long sl) {
+  si = sl % sl; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
+  si = sl % si;
+  si = si % sl;
+  si = si / sl;
+  si = sl / si; // expected-warning {{implicit conversion loses integer precision: 'long' to 'int'}}
+}