donat.nagy updated this revision to Diff 167929.
donat.nagy added a comment.

Fix formatting in tests; add a comment.


Repository:
  rC Clang

https://reviews.llvm.org/D52730

Files:
  lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
  test/Analysis/conversion.c

Index: test/Analysis/conversion.c
===================================================================
--- test/Analysis/conversion.c
+++ test/Analysis/conversion.c
@@ -137,6 +137,12 @@
   U8 = S + 10;
 }
 
+char dontwarn6(long long x) {
+  long long y = 42;
+  y += x;
+  return y == 42;
+}
+
 
 // false positives..
 
@@ -155,7 +161,7 @@
 # define EOF (-1)
 char reply_string[8192];
 FILE *cin;
-extern int dostuff (void);
+extern int dostuff(void);
 int falsePositive2() {
   int c, n;
   int dig;
@@ -181,3 +187,26 @@
   }
 }
 
+double floating_point(long long a, int b) {
+  if (a > 1LL << 55) {
+    double r = a; // expected-warning {{Loss of precision}}
+    return r;
+  } else if (b > 1 << 25) {
+    float f = b; // expected-warning {{Loss of precision}}
+    return f;
+  }
+  return 137;
+}
+
+double floating_point2() {
+  int a = 1 << 24;
+  long long b = 1LL << 53;
+  double d = a; // no-warning
+  double f = b; // no-warning
+  return d - f;
+}
+
+int floating_point_3(unsigned long long a) {
+  double b = a; // no-warning
+  return 42;
+}
Index: lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
===================================================================
--- lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
+++ lib/StaticAnalyzer/Checkers/ConversionChecker.cpp
@@ -14,8 +14,10 @@
 // of expressions. A warning is reported when:
 // * a negative value is implicitly converted to an unsigned value in an
 //   assignment, comparison or multiplication.
-// * assignment / initialization when source value is greater than the max
-//   value of target
+// * assignment / initialization when the source value is greater than the max
+//   value of the target integer type
+// * assignment / initialization when the source integer is above the range
+//   where the target floating point type can represent all integers
 //
 // Many compilers and tools have similar checks that are based on semantic
 // analysis. Those checks are sound but have poor precision. ConversionChecker
@@ -29,6 +31,8 @@
 #include "clang/StaticAnalyzer/Core/CheckerManager.h"
 #include "clang/StaticAnalyzer/Core/PathSensitive/CheckerContext.h"
 
+#include <climits>
+
 using namespace clang;
 using namespace ento;
 
@@ -132,19 +136,66 @@
 
   QualType SubType = Cast->IgnoreParenImpCasts()->getType();
 
-  if (!DestType->isIntegerType() || !SubType->isIntegerType())
+  if (!DestType->isRealType() || !SubType->isIntegerType())
     return false;
 
-  if (C.getASTContext().getIntWidth(DestType) >=
-      C.getASTContext().getIntWidth(SubType))
+  const bool isInteger = DestType->isIntegerType();
+
+  const auto &AC = C.getASTContext();
+
+  // We will find the largest RepresentsUntilExp value such that the DestType
+  // can exactly represent all integers 0 <= n < 2^RepresentsUntilExp
+  unsigned RepresentsUntilExp;
+
+  if (isInteger) {
+    RepresentsUntilExp = AC.getIntWidth(DestType);
+    if (RepresentsUntilExp == 1) {
+      // This is just casting a number to bool, probably not a bug.
+      return false;
+    }
+    if (DestType->isSignedIntegerType()) {
+      RepresentsUntilExp--;
+    }
+  } else {
+    unsigned FloatingSize = AC.getTypeSize(DestType);
+    switch (FloatingSize) {
+      case 64:
+        // double and possibly long double on some systems
+        RepresentsUntilExp = 53; break;
+      case 32:
+        // float
+        RepresentsUntilExp = 24; break;
+      case 16:
+        // _Float16
+        RepresentsUntilExp = 12; break;
+      default:
+        // larger types, which can represent all integers below 2^64
+        return false;
+    }
+  }
+
+  if (RepresentsUntilExp >= sizeof(unsigned long long)*CHAR_BIT) {
+    // Avoid overflow in our later calculations
     return false;
+  }
 
-  unsigned W = C.getASTContext().getIntWidth(DestType);
-  if (W == 1 || W >= 64U)
+  unsigned CorrectedSrcWidth = AC.getIntWidth(SubType);
+  if (SubType->isSignedIntegerType()) {
+    CorrectedSrcWidth--;
+  }
+
+  if (RepresentsUntilExp >= CorrectedSrcWidth) {
+    // Simple case: the destination can store all values of the source type.
     return false;
+  }
 
-  unsigned long long MaxVal = 1ULL << W;
+  unsigned long long MaxVal = 1ULL << RepresentsUntilExp;
+  if (!isInteger) {
+    // if this is a floating point type, it can also represent MaxVal exactly
+    MaxVal++;
+  }
   return C.isGreaterOrEqual(Cast->getSubExpr(), MaxVal);
+  // TODO: maybe also check negative values with too large magnitude
 }
 
 bool ConversionChecker::isLossOfSign(const ImplicitCastExpr *Cast,
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to