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 @@ -132,19 +134,65 @@ 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)*8) { return false; + } + + unsigned CorrectedSrcWidth = AC.getIntWidth(SubType); + if (SubType->isSignedIntegerType()) { + CorrectedSrcWidth--; + } - unsigned W = C.getASTContext().getIntWidth(DestType); - if (W == 1 || W >= 64U) + 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, 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.. @@ -181,3 +187,28 @@ } } + +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; +} +