ASDenysPetrov created this revision.
ASDenysPetrov added reviewers: NoQ, vsavchenko, steakhal, martong, dcoughlin, 
baloghadamsoftware.
ASDenysPetrov added a project: clang.
Herald added subscribers: manas, dkrupp, donat.nagy, Szelethus, 
mikhail.ramalho, a.sidorin, rnkovacs, szepet, xazax.hun.
ASDenysPetrov requested review of this revision.
Herald added a subscriber: cfe-commits.

Support integral cast for ranges of symbolic integers. Previously we only 
support integral cast for concrete integers.

Reason about the ranges of `SymbolCast` expressions. Apply truncations, 
promotions and conversions to get a correct range set using nested types of a 
`SymbolCast`. Replace `SValBuilder::evalIntegralCast` with 
`SValBuilder::evalCast`. Remove `SValBuilder::evalIntegralCast` as unnecessary 
one.

See tests in //symbol-integral-cast.cpp// for examples.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D103096

Files:
  clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
  clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
  clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
  clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
  clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
  clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
  clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
  clang/test/Analysis/bool-assignment.c
  clang/test/Analysis/constant-folding.c
  clang/test/Analysis/constraint_manager_negate_difference.c
  clang/test/Analysis/explain-svals.cpp
  clang/test/Analysis/expr-inspection.cpp
  clang/test/Analysis/malloc.c
  clang/test/Analysis/std-c-library-functions.c
  clang/test/Analysis/svalbuilder-rearrange-comparisons.c
  clang/test/Analysis/symbol-integral-cast.cpp

Index: clang/test/Analysis/symbol-integral-cast.cpp
===================================================================
--- /dev/null
+++ clang/test/Analysis/symbol-integral-cast.cpp
@@ -0,0 +1,353 @@
+// RUN: %clang_analyze_cc1 -analyzer-checker=debug.ExprInspection -analyzer-config eagerly-assume=false -verify %s
+
+template <typename T>
+void clang_analyzer_eval(T);
+void clang_analyzer_warnIfReached();
+
+typedef short int16_t;
+typedef int int32_t;
+typedef unsigned short uint16_t;
+typedef unsigned int uint32_t;
+
+void test1(int x) {
+  // Even if two lower bytes of `x` equal to zero, it doesn't mean that
+  // the entire `x` is zero. We are not able to know the exact value of x.
+  // It can be one of  65536 possible values like [0, 65536, 131072, ...]
+  // and so on. To avoid huge range sets we still assume `x` in the range
+  // [INT_MIN, INT_MAX].
+  if (!(short)x) {
+    if (!x)
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+    else
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test2(int x) {
+  // If two lower bytes of `x` equal to zero, and we know x to be 65537,
+  // which is not truncated to short as zero. Thus the branch is infisible.
+  short s = x;
+  if (!s) {
+    if (x == 65537)
+      clang_analyzer_warnIfReached(); // no-warning
+    else
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test3(int x, short s) {
+  s = x;
+  if ((short)x > -10 && s < 10) {
+    if (x > 0 && x < 10) {
+      // If the range of the whole variable was constrained then reason again
+      // about truncated bytes to make the ranges more precise.
+      clang_analyzer_eval((short)x <= 0); // expected-warning {{FALSE}}
+    }
+  }
+}
+
+void test4(unsigned x) {
+  if ((char)x > 8) {
+    // Constraint the range of the lowest byte of `x` to [9, CHAR_MAX].
+    // The original range of `x` still remains [0, UINT_MAX].
+    clang_analyzer_eval((char)x < 42); // expected-warning {{UNKNOWN}}
+    if (x < 42) {
+      // Constraint the original range to [0, 42] and update (re-constraint)
+      // the range of the lowest byte of 'x' to [9, 42].
+      clang_analyzer_eval((char)x < 42); // expected-warning {{TRUE}}
+    }
+  }
+}
+
+void test5(unsigned x) {
+  if ((char)x > -10 && (char)x < 10) {
+    if ((short)x == 8) {
+      // If the range of higher bytes(short) was constrained then reason again
+      // about smaller truncated ranges(char) to make it more precise.
+      clang_analyzer_eval((char)x == 8);  // expected-warning {{TRUE}}
+      clang_analyzer_eval((short)x == 8); // expected-warning {{TRUE}}
+      // We still assume full version of `x` in the range [INT_MIN, INT_MAX].
+      clang_analyzer_eval(x == 8); // expected-warning {{UNKNOWN}}
+    }
+  }
+}
+
+void test6(int x) {
+  // Even if two lower bytes of `x` less than zero, it doesn't mean that `x`
+  // can't be greater than zero. Thence we don't change the native range of
+  // `x` and this branch is feasible.
+  if (x > 0)
+    if ((short)x < 0)
+      clang_analyzer_eval(x > 0); // expected-warning {{TRUE}}
+}
+
+void test7(int x) {
+  // The range of two lower bytes of `x` [1, SHORT_MAX] is enough to cover
+  // all possible values of char [CHAR_MIN, CHAR_MAX]. So the lowest byte
+  // can be lower than zero.
+  if ((short)x > 0) {
+    if ((char)x < 0)
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+    else
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test8(int x) {
+  // Promotion from `signed int` to `signed long long` also reasoning about the
+  // original range, because we know the fact that even after promotion it
+  // remains in the range [INT_MIN, INT_MAX].
+  if ((long long)x < 0)
+    clang_analyzer_eval(x < 0); // expected-warning {{TRUE}}
+}
+
+void test9(signed int x) {
+  // Any cast `signed` to `unsigned` produces an unsigned range, which is
+  // [0, UNSIGNED_MAX] and can not be lower than zero.
+  if ((unsigned long long)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  if ((unsigned int)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  if ((unsigned short)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  if ((unsigned char)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test10(unsigned int x, signed char sc) {
+  // Promotion from `unsigned` to `signed` produces a signed range,
+  // which is able to cover all the values of the original,
+  // so that such cast is not lower than zero.
+  if ((signed long long)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  // Any other cast(conversion or truncation) from `unsigned` to `signed`
+  // produces a signed range, which is [SIGNED_MIN, SIGNED_MAX]
+  // and can be lower than zero.
+  if ((signed int)x < 0)            // explicit cast
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  signed short ss = x; // initialization
+  if (ss < 0)
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+  sc = x; // assignment
+  if (sc < 0)
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  else
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+}
+
+void test11(unsigned int x) {
+  // Promotion from 'unsigned' to 'signed' entirely covers the original range.
+  // Thence such cast is not lower than zero and the `true` branch is
+  // infiseable. But it doesn't affect the original range, which still remains
+  // as [0, UNSIGNED_MAX].
+  if ((signed long long)x < 0)
+    clang_analyzer_warnIfReached(); // no-warning
+  else
+    clang_analyzer_eval(x < 0); // expected-warning {{FALSE}}
+
+  // Any other cast(conversion or truncation) from `unsigned` to `signed`
+  // produces a signed range, which is [SIGNED_MIN, SIGNED_MAX]. But it doesn't
+  // affect the original range, which still remains as [0, UNSIGNED_MAX].
+  if ((signed int)x < 0)
+    clang_analyzer_eval(x < 0); // expected-warning {{FALSE}}
+
+  if ((signed short)x < 0)
+    clang_analyzer_eval(x < 0); // expected-warning {{FALSE}}
+
+  if ((signed char)x < 0)
+    clang_analyzer_eval(x < 0); // expected-warning {{FALSE}}
+}
+
+void test12(int x, char c) {
+  if (x >= 5308) {
+    if (x <= 5419) {
+      // Truncation on assignment: int[5308, 5419] -> char[-68, 43]
+      c = x;
+      clang_analyzer_eval(-68 <= c && c <= 43); // expected-warning {{TRUE}}
+
+      if (c < 50)
+        clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+      else
+        clang_analyzer_warnIfReached(); // no-warning
+
+      // Truncation on initializaion: int[5308, 5419] -> char[-68, 43]
+      char c1 = x;
+      clang_analyzer_eval(-68 <= c1 && c1 <= 43); // expected-warning {{TRUE}}
+    }
+  }
+}
+
+void test13(int x) {
+  if (x > 913440767 && x < 913440769) { // 0x36720000
+
+    if ((short)x)                     // Truncation: int[913440768] -> short[0]
+      clang_analyzer_warnIfReached(); // no-warning
+    else
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+
+    if ((short)x != 0)
+      clang_analyzer_warnIfReached(); // no-warning
+    else
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  }
+}
+
+void test14(int x) {
+  if (x >= -1569193983 && x <= 578290016) {
+    // The big range of `x` covers all possible values of short.
+    // Truncation: int[-1569193983, 578290016] -> short[-32768, 32767]
+    if ((short)x > 0) {
+      clang_analyzer_eval(-1569193983 <= x && x <= 578290016); // expected-warning {{TRUE}}
+      short s = x;
+      clang_analyzer_eval(-32768 <= s && s <= 32767); // expected-warning {{TRUE}}
+    }
+  }
+}
+
+void test15(int x) {
+  if (x >= -1569193983 && x <= -1569193871) { // [0xA2780001, 0xA2780071]
+    // The small range of `x` covers only several values of short.
+    // Truncation: int[-1569193983, -1569193871] -> short[1, 113]
+    if ((short)x)
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+    else
+      clang_analyzer_warnIfReached(); // no-warning
+
+    if ((short)x > 0)
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+    else
+      clang_analyzer_warnIfReached(); // no-warning
+
+    if ((short)x < 114)
+      clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+    else
+      clang_analyzer_warnIfReached(); // no-warning
+  }
+}
+
+void test16(char x) {
+  if (x < 0)
+    clang_analyzer_eval(-128 <= x && x < 0); // expected-warning {{TRUE}}
+  else
+    clang_analyzer_eval(0 <= x && x <= 127); // expected-warning {{TRUE}}
+}
+
+void test17(char x) {
+  if (-11 <= x && x <= -10) {
+    unsigned u = x;
+    // Conversion: char[-11, -10] -> unsigned int[4294967285, 4294967286]
+    clang_analyzer_eval(4294967285 <= u && u <= 4294967286); // expected-warning {{TRUE}}
+    unsigned short us = x;
+    // Conversion: char[-11, -10] -> unsigned short[65525, 65526]
+    clang_analyzer_eval(65525 <= us && us <= 65526); // expected-warning {{TRUE}}
+    unsigned char uc = x;
+    // Conversion: char[-11, -10] -> unsigned char[245, 246]
+    clang_analyzer_eval(245 <= uc && uc <= 246); // expected-warning {{TRUE}}
+  }
+}
+
+void test18(char c, short s, int i) {
+  // Any char value always is less then 1000.
+  int OneThousand = 1000;
+  c = i;
+  if (c < OneThousand)
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  else
+    clang_analyzer_warnIfReached(); // no-warning
+
+  // Any short value always is greater then 40000.
+  int MinusFourtyThousands = -40000;
+  s = i;
+  if (s > MinusFourtyThousands)
+    clang_analyzer_warnIfReached(); // expected-warning {{REACHABLE}}
+  else
+    clang_analyzer_warnIfReached(); // no-warning
+}
+
+void test19(char x, short y) {
+  if (-43 <= x && x <= -42) { // x[-42, -43]
+    y = 42;
+    clang_analyzer_eval(int16_t(x) < int16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int16_t(x) < int32_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < int16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < int32_t(y)); // expected-warning {{TRUE}}
+
+    clang_analyzer_eval(int16_t(x) < uint16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int16_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(int32_t(x) < uint16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+
+    clang_analyzer_eval(uint16_t(x) < int16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint16_t(x) < int32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < int16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < int32_t(y)); // expected-warning {{FALSE}}
+
+    clang_analyzer_eval(uint16_t(x) < uint16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint16_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < uint16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+  }
+}
+
+void test20(char x, short y) {
+  if (42 <= y && y <= 43) { // y[42, 43]
+    x = -42;
+    clang_analyzer_eval(int16_t(x) < int16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int16_t(x) < int32_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < int16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < int32_t(y)); // expected-warning {{TRUE}}
+
+    clang_analyzer_eval(int16_t(x) < uint16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int16_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(int32_t(x) < uint16_t(y)); // expected-warning {{TRUE}}
+    clang_analyzer_eval(int32_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+
+    clang_analyzer_eval(uint16_t(x) < int16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint16_t(x) < int32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < int16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < int32_t(y)); // expected-warning {{FALSE}}
+
+    clang_analyzer_eval(uint16_t(x) < uint16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint16_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < uint16_t(y)); // expected-warning {{FALSE}}
+    clang_analyzer_eval(uint32_t(x) < uint32_t(y)); // expected-warning {{FALSE}}
+  }
+}
+
+void test21(unsigned x) {
+  if (x > 42) {
+    // Unsigned range can generate two signed ranges.
+    // Conversion: unsigned[43, 4294967295] -> int[-2147483648, -1]U[43, 2147483647]
+    int i = x;                             // initialization
+    clang_analyzer_eval(-1 < i && i < 43); // expected-warning {{FALSE}}
+  }
+}
+
+void test22(int x, unsigned u) {
+  if (x > -42) {
+    // Signed range can generate two unsigned ranges.
+    // Conversion: int[-41, 2147483647] -> unsigned[0, 2147483647]U[4294967255, 4294967295]
+    u = x;                                                 // assignment
+    clang_analyzer_eval(2147483647 < u && u < 4294967255); // expected-warning {{FALSE}}
+  }
+}
Index: clang/test/Analysis/svalbuilder-rearrange-comparisons.c
===================================================================
--- clang/test/Analysis/svalbuilder-rearrange-comparisons.c
+++ clang/test/Analysis/svalbuilder-rearrange-comparisons.c
@@ -515,7 +515,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - $y == 0}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x == (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_left_int_equal_unsigned() {
@@ -524,7 +524,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x == y); // expected-warning {{$y - $x == 1}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x + 1 == (unsigned int)$y}}
 }
 
 void compare_different_symbol_minus_left_int_equal_unsigned() {
@@ -533,7 +533,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - $y == 1}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x - 1 == (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_right_int_equal_unsigned() {
@@ -541,7 +541,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y - 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y + 2}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - $y == 2}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x == (unsigned int)$y + 2}}
 }
 
 void compare_different_symbol_minus_right_int_equal_unsigned() {
@@ -549,7 +549,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y + 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y - 2}}
-  clang_analyzer_express(x == y); // expected-warning {{$y - $x == 2}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x == (unsigned int)$y - 2}}
 }
 
 void compare_different_symbol_plus_left_plus_right_int_equal_unsigned() {
@@ -558,7 +558,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$y - $x == 1}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x + 2 == (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_plus_left_minus_right_int_equal_unsigned() {
@@ -567,7 +567,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$y - $x == 3}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x + 2 == (unsigned int)$y - 1}}
 }
 
 void compare_different_symbol_minus_left_plus_right_int_equal_unsigned() {
@@ -576,7 +576,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - $y == 3}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x - 2 == (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_minus_left_minus_right_int_equal_unsigned() {
@@ -585,7 +585,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - $y == 1}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x - 2 == (unsigned int)$y - 1}}
 }
 
 void compare_same_symbol_equal_unsigned() {
@@ -601,7 +601,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x == y); // expected-warning {{$x + 1U == $x}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x + 1U == (unsigned int)$x}}
 }
 
 void compare_same_symbol_minus_left_int_equal_unsigned() {
@@ -610,21 +610,21 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - 1U == $x}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x - 1U == (unsigned int)$x}}
 }
 
 void compare_same_symbol_plus_right_int_equal_unsigned() {
   unsigned x = f(), y = x + 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x == $x + 1U}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x == (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_right_int_equal_unsigned() {
   unsigned x = f(), y = x - 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x == $x - 1U}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x == (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_plus_left_plus_right_int_equal_unsigned() {
@@ -642,7 +642,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x + 1U == $x - 1U}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x + 1U == (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_minus_left_plus_right_int_equal_unsigned() {
@@ -651,7 +651,7 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x == y); // expected-warning {{$x - 1U == $x + 1U}}
+  clang_analyzer_express(x == y); // expected-warning {{(unsigned int)$x - 1U == (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_left_minus_right_int_equal_unsigned() {
@@ -668,7 +668,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - $y <= 0}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x <= (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_left_int_less_or_equal_unsigned() {
@@ -677,7 +677,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x <= y); // expected-warning {{$y - $x >= 1}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x + 1 <= (unsigned int)$y}}
 }
 
 void compare_different_symbol_minus_left_int_less_or_equal_unsigned() {
@@ -686,7 +686,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - $y <= 1}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x - 1 <= (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_right_int_less_or_equal_unsigned() {
@@ -694,7 +694,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y - 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y + 2}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - $y <= 2}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x <= (unsigned int)$y + 2}}
 }
 
 void compare_different_symbol_minus_right_int_less_or_equal_unsigned() {
@@ -702,7 +702,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y + 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y - 2}}
-  clang_analyzer_express(x <= y); // expected-warning {{$y - $x >= 2}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x <= (unsigned int)$y - 2}}
 }
 
 void compare_different_symbol_plus_left_plus_right_int_less_or_equal_unsigned() {
@@ -711,7 +711,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$y - $x >= 1}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x + 2 <= (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_plus_left_minus_right_int_less_or_equal_unsigned() {
@@ -720,7 +720,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$y - $x >= 3}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x + 2 <= (unsigned int)$y - 1}}
 }
 
 void compare_different_symbol_minus_left_plus_right_int_less_or_equal_unsigned() {
@@ -729,7 +729,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - $y <= 3}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x - 2 <= (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_minus_left_minus_right_int_less_or_equal_unsigned() {
@@ -738,7 +738,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - $y <= 1}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x - 2 <= (unsigned int)$y - 1}}
 }
 
 void compare_same_symbol_less_or_equal_unsigned() {
@@ -754,7 +754,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x + 1U <= $x}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x + 1U <= (unsigned int)$x}}
 }
 
 void compare_same_symbol_minus_left_int_less_or_equal_unsigned() {
@@ -763,21 +763,21 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - 1U <= $x}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x - 1U <= (unsigned int)$x}}
 }
 
 void compare_same_symbol_plus_right_int_less_or_equal_unsigned() {
   unsigned x = f(), y = x + 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x <= $x + 1U}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x <= (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_right_int_less_or_equal_unsigned() {
   unsigned x = f(), y = x - 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x <= $x - 1U}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x <= (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_plus_left_plus_right_int_less_or_equal_unsigned() {
@@ -795,7 +795,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x + 1U <= $x - 1U}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x + 1U <= (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_minus_left_plus_right_int_less_or_equal_unsigned() {
@@ -804,7 +804,7 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x <= y); // expected-warning {{$x - 1U <= $x + 1U}}
+  clang_analyzer_express(x <= y); // expected-warning {{(unsigned int)$x - 1U <= (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_left_minus_right_int_less_or_equal_unsigned() {
@@ -821,7 +821,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - $y < 0}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x < (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_left_int_less_unsigned() {
@@ -830,7 +830,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x < y); // expected-warning {{$y - $x > 1}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x + 1 < (unsigned int)$y}}
 }
 
 void compare_different_symbol_minus_left_int_less_unsigned() {
@@ -839,7 +839,7 @@
   clang_analyzer_denote(y, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$y}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - $y < 1}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x - 1 < (unsigned int)$y}}
 }
 
 void compare_different_symbol_plus_right_int_less_unsigned() {
@@ -847,7 +847,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y - 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y + 2}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - $y < 2}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x < (unsigned int)$y + 2}}
 }
 
 void compare_different_symbol_minus_right_int_less_unsigned() {
@@ -855,7 +855,7 @@
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y + 2, "$y");
   clang_analyzer_express(y); // expected-warning {{$y - 2}}
-  clang_analyzer_express(x < y); // expected-warning {{$y - $x > 2}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x < (unsigned int)$y - 2}}
 }
 
 void compare_different_symbol_plus_left_plus_right_int_less_unsigned() {
@@ -864,7 +864,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$y - $x > 1}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x + 2 < (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_plus_left_minus_right_int_less_unsigned() {
@@ -873,7 +873,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x + 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$y - $x > 3}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x + 2 < (unsigned int)$y - 1}}
 }
 
 void compare_different_symbol_minus_left_plus_right_int_less_unsigned() {
@@ -882,7 +882,7 @@
   clang_analyzer_denote(y - 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y + 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - $y < 3}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x - 2 < (unsigned int)$y + 1}}
 }
 
 void compare_different_symbol_minus_left_minus_right_int_less_unsigned() {
@@ -891,7 +891,7 @@
   clang_analyzer_denote(y + 1, "$y");
   clang_analyzer_express(x); // expected-warning {{$x - 2}}
   clang_analyzer_express(y); // expected-warning {{$y - 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - $y < 1}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x - 2 < (unsigned int)$y - 1}}
 }
 
 void compare_same_symbol_less_unsigned() {
@@ -907,7 +907,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x < y); // expected-warning {{$x + 1U < $x}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x + 1U < (unsigned int)$x}}
 }
 
 void compare_same_symbol_minus_left_int_less_unsigned() {
@@ -916,21 +916,21 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - 1U < $x}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x - 1U < (unsigned int)$x}}
 }
 
 void compare_same_symbol_plus_right_int_less_unsigned() {
   unsigned x = f(), y = x + 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x < $x + 1U}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x < (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_right_int_less_unsigned() {
   unsigned x = f(), y = x - 1;
   clang_analyzer_denote(x, "$x");
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x < $x - 1U}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x < (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_plus_left_plus_right_int_less_unsigned() {
@@ -948,7 +948,7 @@
   ++x;
   clang_analyzer_express(x); // expected-warning {{$x + 1}}
   clang_analyzer_express(y); // expected-warning {{$x - 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x + 1U < $x - 1U}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x + 1U < (unsigned int)$x - 1U}}
 }
 
 void compare_same_symbol_minus_left_plus_right_int_less_unsigned() {
@@ -957,7 +957,7 @@
   --x;
   clang_analyzer_express(x); // expected-warning {{$x - 1}}
   clang_analyzer_express(y); // expected-warning {{$x + 1}}
-  clang_analyzer_express(x < y); // expected-warning {{$x - 1U < $x + 1U}}
+  clang_analyzer_express(x < y); // expected-warning {{(unsigned int)$x - 1U < (unsigned int)$x + 1U}}
 }
 
 void compare_same_symbol_minus_left_minus_right_int_less_unsigned() {
Index: clang/test/Analysis/std-c-library-functions.c
===================================================================
--- clang/test/Analysis/std-c-library-functions.c
+++ clang/test/Analysis/std-c-library-functions.c
@@ -214,8 +214,11 @@
 int isprint(int);
 void test_isgraph_isprint(int x) {
   char y = x;
-  if (isgraph(y))
+  if (isgraph(y)) {
+    // expected-warning@+1{{FALSE}}
     clang_analyzer_eval(isprint(x)); // expected-warning{{TRUE}}
+    clang_analyzer_eval(isprint((char)x)); // expected-warning{{TRUE}}
+  }
 }
 
 int isdigit(int);
@@ -234,7 +237,7 @@
 void test_isspace(int x) {
   if (!isascii(x))
     return;
-  char y = x;
+  int y = x;
   if (y == ' ')
     clang_analyzer_eval(isspace(x)); // expected-warning{{TRUE}}
 }
Index: clang/test/Analysis/malloc.c
===================================================================
--- clang/test/Analysis/malloc.c
+++ clang/test/Analysis/malloc.c
@@ -1893,6 +1893,6 @@
   // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}}
   int *p = (int *)malloc(x);
   clang_analyzer_dumpExtent(p);
-  // expected-warning-re@-1 {{{{^conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}}}}}}
+  // expected-warning-re@-1 {{{{^\(unsigned long long\) \(conj_\$[[:digit:]]+{int, LC1, S[[:digit:]]+, #1}\)}}}}}
   free(p);
 }
Index: clang/test/Analysis/expr-inspection.cpp
===================================================================
--- clang/test/Analysis/expr-inspection.cpp
+++ clang/test/Analysis/expr-inspection.cpp
@@ -2,7 +2,8 @@
 
 // Self-tests for the debug.ExprInspection checker.
 
-void clang_analyzer_denote(int x, const char *str);
+template <typename T>
+void clang_analyzer_denote(T x, const char *str);
 void clang_analyzer_express(int x);
 
 // Invalid declarations to test sanity checks.
@@ -19,7 +20,7 @@
 
   clang_analyzer_denote(x, "$x");
   clang_analyzer_denote(y, "$y");
-  clang_analyzer_express(x + y); // expected-warning{{$x + $y}}
+  clang_analyzer_express(x + y); // expected-warning{{(unsigned int)$x + $y}}
 
   clang_analyzer_denote(1, "$z");     // expected-warning{{Not a symbol}}
   clang_analyzer_express(1);     // expected-warning{{Not a symbol}}
Index: clang/test/Analysis/explain-svals.cpp
===================================================================
--- clang/test/Analysis/explain-svals.cpp
+++ clang/test/Analysis/explain-svals.cpp
@@ -46,15 +46,15 @@
 
 void test_2(char *ptr, int ext) {
   clang_analyzer_explain((void *) "asdf"); // expected-warning-re{{{{^pointer to element of type 'char' with index 0 of string literal "asdf"$}}}}
-  clang_analyzer_explain(strlen(ptr)); // expected-warning-re{{{{^metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}}
+  clang_analyzer_explain(strlen(ptr));     // expected-warning-re{{{{^\(int\)metadata of type 'unsigned long' tied to pointee of argument 'ptr'$}}}}
   clang_analyzer_explain(conjure()); // expected-warning-re{{{{^symbol of type 'int' conjured at statement 'conjure\(\)'$}}}}
   clang_analyzer_explain(glob); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob'$}}}}
   clang_analyzer_explain(glob_ptr); // expected-warning-re{{{{^value derived from \(symbol of type 'int' conjured at statement 'conjure\(\)'\) for global variable 'glob_ptr'$}}}}
-  clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^extent of pointee of argument 'ptr'$}}}}
+  clang_analyzer_explain(clang_analyzer_getExtent(ptr)); // expected-warning-re{{{{^\(int\)extent of pointee of argument 'ptr'$}}}}
   int *x = new int[ext];
   clang_analyzer_explain(x); // expected-warning-re{{{{^pointer to element of type 'int' with index 0 of heap segment that starts at symbol of type 'int \*' conjured at statement 'new int \[ext\]'$}}}}
   // Sic! What gets computed is the extent of the element-region.
-  clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(argument 'ext'\) \* 4$}}}}
+  clang_analyzer_explain(clang_analyzer_getExtent(x)); // expected-warning-re{{{{^\(int\)\(\(unsigned long\)argument 'ext'\) \* 4$}}}}
   delete[] x;
 }
 
@@ -91,7 +91,7 @@
 public:
   void test_5(int i) {
     clang_analyzer_explain(this); // expected-warning-re{{{{^pointer to 'this' object$}}}}
-    clang_analyzer_explain(&x[i]); // expected-warning-re{{{{^pointer to element of type 'int' with index 'argument 'i'' of field 'x' of 'this' object$}}}}
+    clang_analyzer_explain(&x[i]);               // expected-warning-re{{{{^pointer to element of type 'int' with index '\(long long\)argument 'i'' of field 'x' of 'this' object$}}}}
     clang_analyzer_explain(__builtin_alloca(i)); // expected-warning-re{{{{^pointer to region allocated by '__builtin_alloca\(i\)'$}}}}
   }
 };
Index: clang/test/Analysis/constraint_manager_negate_difference.c
===================================================================
--- clang/test/Analysis/constraint_manager_negate_difference.c
+++ clang/test/Analysis/constraint_manager_negate_difference.c
@@ -7,8 +7,8 @@
 #define UINT_MIN (0U)
 #define UINT_MAX (~UINT_MIN)
 #define UINT_MID (UINT_MAX / 2 + 1)
-#define INT_MAX (UINT_MAX & (UINT_MAX >> 1))
-#define INT_MIN (UINT_MAX & ~(UINT_MAX >> 1))
+#define INT_MAX (int)(UINT_MAX & (UINT_MAX >> 1))
+#define INT_MIN (int)(UINT_MAX & ~(UINT_MAX >> 1))
 
 extern void __assert_fail (__const char *__assertion, __const char *__file,
     unsigned int __line, __const char *__function)
Index: clang/test/Analysis/constant-folding.c
===================================================================
--- clang/test/Analysis/constant-folding.c
+++ clang/test/Analysis/constant-folding.c
@@ -238,9 +238,7 @@
 
     if (a <= 10) {
       // Result is unsigned.  This means that 'c' is casted to unsigned.
-      // We don't want to reason about ranges changing boundaries with
-      // conversions.
-      clang_analyzer_eval((a % c) < 30); // expected-warning{{UNKNOWN}}
+      clang_analyzer_eval((a % c) < 30); // expected-warning{{TRUE}}
     }
   }
 
Index: clang/test/Analysis/bool-assignment.c
===================================================================
--- clang/test/Analysis/bool-assignment.c
+++ clang/test/Analysis/bool-assignment.c
@@ -39,14 +39,14 @@
 void test_BOOL_initialization(int y) {
   BOOL constant = 2; // expected-warning {{Assignment of a non-Boolean value}}
   if (y < 0) {
-    BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    BOOL x = y; // no-warning
     return;
   }
   if (y > 200 && y < 250) {
 #ifdef ANALYZER_CM_Z3
     BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
 #else
-    BOOL x = y; // no-warning
+    BOOL x = y; // expected-warning {{Assignment of a non-Boolean value}}
 #endif
     return;
   }
@@ -64,11 +64,11 @@
 void test_BOOL_assignment(int y) {
   BOOL x = 0; // no-warning
   if (y < 0) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   if (y > 1) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   x = y; // no-warning
@@ -82,11 +82,11 @@
 void test_Boolean_initialization(int y) {
   Boolean constant = 2; // expected-warning {{Assignment of a non-Boolean value}}
   if (y < 0) {
-    Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    Boolean x = y; // no-warning
     return;
   }
   if (y > 1) {
-    Boolean x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    Boolean x = y; // no-warning
     return;
   }
   Boolean x = y; // no-warning
@@ -95,11 +95,11 @@
 void test_Boolean_assignment(int y) {
   Boolean x = 0; // no-warning
   if (y < 0) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   if (y > 1) {
-    x = y; // expected-warning {{Assignment of a non-Boolean value}}
+    x = y; // no-warning
     return;
   }
   x = y; // no-warning
Index: clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SimpleSValBuilder.cpp
@@ -536,8 +536,13 @@
       // We only handle LHS as simple symbols or SymIntExprs.
       SymbolRef Sym = lhs.castAs<nonloc::SymbolVal>().getSymbol();
 
+      // Unwrap SymbolCast trying to find SymIntExpr inside.
+      SymbolRef S = Sym;
+      while (isa<SymbolCast>(S))
+        S = cast<SymbolCast>(S)->getOperand();
+
       // LHS is a symbolic expression.
-      if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(Sym)) {
+      if (const SymIntExpr *symIntExpr = dyn_cast<SymIntExpr>(S)) {
 
         // Is this a logical not? (!x is represented as x == 0.)
         if (op == BO_EQ && rhs.isZeroConstant()) {
Index: clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
+++ clang/lib/StaticAnalyzer/Core/SValBuilder.cpp
@@ -500,44 +500,6 @@
   return true;
 }
 
-// Handles casts of type CK_IntegralCast.
-// At the moment, this function will redirect to evalCast, except when the range
-// of the original value is known to be greater than the max of the target type.
-SVal SValBuilder::evalIntegralCast(ProgramStateRef state, SVal val,
-                                   QualType castTy, QualType originalTy) {
-  // No truncations if target type is big enough.
-  if (getContext().getTypeSize(castTy) >= getContext().getTypeSize(originalTy))
-    return evalCast(val, castTy, originalTy);
-
-  SymbolRef se = val.getAsSymbol();
-  if (!se) // Let evalCast handle non symbolic expressions.
-    return evalCast(val, castTy, originalTy);
-
-  // Find the maximum value of the target type.
-  APSIntType ToType(getContext().getTypeSize(castTy),
-                    castTy->isUnsignedIntegerType());
-  llvm::APSInt ToTypeMax = ToType.getMaxValue();
-  NonLoc ToTypeMaxVal =
-      makeIntVal(ToTypeMax.isUnsigned() ? ToTypeMax.getZExtValue()
-                                        : ToTypeMax.getSExtValue(),
-                 castTy)
-          .castAs<NonLoc>();
-  // Check the range of the symbol being casted against the maximum value of the
-  // target type.
-  NonLoc FromVal = val.castAs<NonLoc>();
-  QualType CmpTy = getConditionType();
-  NonLoc CompVal =
-      evalBinOpNN(state, BO_LE, FromVal, ToTypeMaxVal, CmpTy).castAs<NonLoc>();
-  ProgramStateRef IsNotTruncated, IsTruncated;
-  std::tie(IsNotTruncated, IsTruncated) = state->assume(CompVal);
-  if (!IsNotTruncated && IsTruncated) {
-    // Symbol is truncated so we evaluate it as a cast.
-    NonLoc CastVal = makeNonLoc(se, originalTy, castTy);
-    return CastVal;
-  }
-  return evalCast(val, castTy, originalTy);
-}
-
 //===----------------------------------------------------------------------===//
 // Cast methods.
 // `evalCast` is the main method
@@ -939,15 +901,63 @@
   } else {
     // Symbol to integer, float.
     QualType T = Context.getCanonicalType(SE->getType());
-    // If types are the same or both are integers, ignore the cast.
-    // FIXME: Remove this hack when we support symbolic truncation/extension.
-    // HACK: If both castTy and T are integers, ignore the cast.  This is
-    // not a permanent solution.  Eventually we want to precisely handle
-    // extension/truncation of symbolic integers.  This prevents us from losing
-    // precision when we assign 'x = y' and 'y' is symbolic and x and y are
-    // different integer types.
-    if (haveSameType(T, CastTy))
-      return V;
+    // If castTy and T are different integers, return a cast of the given
+    // symbol. This helps RangeConstraintManager to recognize the cast and
+    // reason about new ranges. See symbolic truncation/extension/conversions
+    // handles in SymbolicRangeInferrer::VisitSymbolCast.
+    if (T->isIntegralOrEnumerationType() &&
+        CastTy->isIntegralOrEnumerationType()) {
+      // If types are the same, ignore the cast.
+      if (T == CastTy)
+        return V;
+      // Simplify SymbolCast if no truncation occurred. This reduce unnecessary
+      // nested types between the root operand and the outermost type.
+      // E.g. (short)(int)(long)(char x) equivalent to (short)(char x).
+      if (isa<SymbolCast>(SE)) {
+        ASTContext &Ctx = getContext();
+        SymbolRef OperandSym = cast<SymbolCast>(SE)->getOperand();
+        QualType OperandTy = OperandSym->getType();
+        uint32_t OperandBitWidth = Ctx.getIntWidth(OperandTy);
+        uint32_t SymBitWidth = Ctx.getIntWidth(T);
+        uint32_t CastBitWidth = Ctx.getIntWidth(CastTy);
+        const bool isTruncated = (OperandBitWidth > SymBitWidth);
+        if (isTruncated) {
+          const bool isMoreTruncated = (SymBitWidth >= CastBitWidth);
+          if (isMoreTruncated) {
+            // Cast type bit width is less than the current:
+            // - (char)(short)(int x) -> (char)int x.
+            SE = OperandSym;
+            T = CastTy;
+          }
+        } else {
+          // Original and cast types are equal:
+          // - (ushort)(int)(ushort x) -> ushort x;
+          // - (char)(uint)(char x) -> char x.
+          if (OperandTy == CastTy)
+            return nonloc::SymbolVal(OperandSym);
+          // Current and cast type bit widths or signs are equal:
+          // - (signed)(unsigned)(short x) -> (signed)short x;
+          // - (unsigned)(signed)(short x) -> (unsigned)short x;
+          // - (unsigned long long)(unsigned int)(short x) ->
+          // (unsigned long long)short x;
+          // - (long long)(int)(short x) -> (long long)short x;
+          if ((SymBitWidth == CastBitWidth) ||
+              (T->isSignedIntegerOrEnumerationType() ==
+               CastTy->isSignedIntegerOrEnumerationType())) {
+            SE = OperandSym;
+            T = OperandTy;
+          }
+          // Current and cast type signs are different:
+          // - (signed long long)(unsigned int)(short x) ->
+          // (signed long long)(unsigned int)short x;
+          // - (unsigned long long)(signed int)(short x) ->
+          // (unsigned long long)(signed int)short x;
+          // Do nothing extra.
+          // This prevent wrong `sext` and `zext` actions.
+        }
+      }
+      return makeNonLoc(SE, T, CastTy);
+    }
     if (!Loc::isLocType(CastTy))
       if (!IsUnknownOriginalType || !CastTy->isFloatingType() ||
           T->isFloatingType())
Index: clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
+++ clang/lib/StaticAnalyzer/Core/RangeConstraintManager.cpp
@@ -766,6 +766,7 @@
 
 namespace {
 class EquivalenceClass;
+class NominalTypeList;
 } // end anonymous namespace
 
 REGISTER_MAP_WITH_PROGRAMSTATE(ClassMap, SymbolRef, EquivalenceClass)
@@ -826,14 +827,16 @@
 
   LLVM_NODISCARD static inline ProgramStateRef
   markDisequal(BasicValueFactory &BV, RangeSet::Factory &F,
-               ProgramStateRef State, SymbolRef First, SymbolRef Second);
+               ProgramStateRef State, NominalTypeList &NTL, SymbolRef First,
+               SymbolRef Second);
   LLVM_NODISCARD static inline ProgramStateRef
   markDisequal(BasicValueFactory &BV, RangeSet::Factory &F,
-               ProgramStateRef State, EquivalenceClass First,
-               EquivalenceClass Second);
+               ProgramStateRef State, NominalTypeList &NTL,
+               EquivalenceClass First, EquivalenceClass Second);
   LLVM_NODISCARD inline ProgramStateRef
   markDisequal(BasicValueFactory &BV, RangeSet::Factory &F,
-               ProgramStateRef State, EquivalenceClass Other) const;
+               ProgramStateRef State, NominalTypeList &NTL,
+               EquivalenceClass Other) const;
   LLVM_NODISCARD static inline ClassSet
   getDisequalClasses(ProgramStateRef State, SymbolRef Sym);
   LLVM_NODISCARD inline ClassSet
@@ -893,8 +896,8 @@
   static inline bool
   addToDisequalityInfo(DisequalityMapTy &Info, ConstraintRangeTy &Constraints,
                        BasicValueFactory &BV, RangeSet::Factory &F,
-                       ProgramStateRef State, EquivalenceClass First,
-                       EquivalenceClass Second);
+                       ProgramStateRef State, NominalTypeList &NTL,
+                       EquivalenceClass First, EquivalenceClass Second);
 
   /// This is a unique identifier of the class.
   uintptr_t ID;
@@ -1081,6 +1084,35 @@
 //                           Symbolic reasoning logic
 //===----------------------------------------------------------------------===//
 
+class NominalTypeList {
+  CanQualType Types[4];
+
+public:
+  using Iterator = CanQualType *;
+
+  NominalTypeList(ASTContext &C)
+      : Types{C.Char8Ty, C.Char16Ty, C.Char32Ty, C.LongLongTy} {}
+  Iterator findByWidth(uint32_t Width) {
+    int index = 4;
+    switch (Width) {
+    case 8:
+      index = 0;
+      break;
+    case 16:
+      index = 1;
+      break;
+    case 32:
+      index = 2;
+      break;
+    case 64:
+      index = 3;
+    };
+    return Types + index;
+  }
+  Iterator begin() { return std::begin(Types); }
+  Iterator end() { return std::end(Types); }
+};
+
 /// A little component aggregating all of the reasoning we have about
 /// the ranges of symbolic expressions.
 ///
@@ -1091,11 +1123,60 @@
 public:
   template <class SourceType>
   static RangeSet inferRange(BasicValueFactory &BV, RangeSet::Factory &F,
-                             ProgramStateRef State, SourceType Origin) {
-    SymbolicRangeInferrer Inferrer(BV, F, State);
+                             ProgramStateRef State, NominalTypeList &NTL,
+                             SourceType Origin) {
+    SymbolicRangeInferrer Inferrer(BV, F, State, NTL);
     return Inferrer.infer(Origin);
   }
 
+  RangeSet VisitSymbolCast(const SymbolCast *Sym) {
+    // Unwrap symbol to get an underlying symbol.
+    // Store every next type except the inner(original) one.
+    SmallVector<QualType, 2> Types;
+    uint32_t MinBitWidth = UINT32_MAX;
+    SymbolRef RootSym = Sym;
+    ASTContext &C = ValueFactory.getContext();
+    do {
+      // We only handle integral cast, when all the types are integrals.
+      // Otherwise, pass the expression to VisitSymExpr.
+      QualType T = RootSym->getType();
+      if (!T->isIntegralOrEnumerationType())
+        return VisitSymExpr(Sym);
+
+      MinBitWidth = std::min(MinBitWidth, C.getIntWidth(T));
+      Types.push_back(T);
+      RootSym = cast<SymbolCast>(RootSym)->getOperand();
+    } while (isa<SymbolCast>(RootSym));
+    // Now RootSym is the root symbol.
+
+    QualType RootTy = RootSym->getType();
+    const uint32_t RootBitWidth = C.getIntWidth(RootTy);
+
+    // Check if we had any truncated ranges of the root symbol,
+    // which are more precise for reasoning about other bigger truncations.
+    const RangeSet *RS = nullptr;
+    auto It = NominalTypes.findByWidth(MinBitWidth);
+    auto E = NominalTypes.findByWidth(RootBitWidth);
+    for (; !RS && It < E; ++It) {
+      SymbolRef S =
+          State->getSymbolManager().getCastSymbol(RootSym, RootTy, *It);
+      RS = getConstraint(State, S);
+    }
+    // If we didn't find any truncated ranges, look for the original range.
+    if (!RS)
+      RS = getConstraint(State, RootSym);
+
+    // If there's no existing range, create it based on type.
+    RangeSet OriginalRS = RS ? *RS : infer(RootTy);
+
+    // Cast original range to the types from inner to outer one by one.
+    auto TypesReversedRange = llvm::make_range(Types.rbegin(), Types.rend());
+    for (const QualType T : TypesReversedRange)
+      OriginalRS = RangeFactory.castTo(OriginalRS, T);
+
+    return OriginalRS;
+  }
+
   RangeSet VisitSymExpr(SymbolRef Sym) {
     // If we got to this function, the actual type of the symbolic
     // expression is not supported for advanced inference.
@@ -1118,8 +1199,8 @@
 
 private:
   SymbolicRangeInferrer(BasicValueFactory &BV, RangeSet::Factory &F,
-                        ProgramStateRef S)
-      : ValueFactory(BV), RangeFactory(F), State(S) {}
+                        ProgramStateRef S, NominalTypeList &NTL)
+      : ValueFactory(BV), RangeFactory(F), State(S), NominalTypes(NTL) {}
 
   /// Infer range information from the given integer constant.
   ///
@@ -1464,6 +1545,7 @@
   BasicValueFactory &ValueFactory;
   RangeSet::Factory &RangeFactory;
   ProgramStateRef State;
+  NominalTypeList &NominalTypes;
 };
 
 //===----------------------------------------------------------------------===//
@@ -1637,7 +1719,8 @@
 class RangeConstraintManager : public RangedConstraintManager {
 public:
   RangeConstraintManager(ExprEngine *EE, SValBuilder &SVB)
-      : RangedConstraintManager(EE, SVB), F(getBasicVals()) {}
+      : RangedConstraintManager(EE, SVB), F(getBasicVals()),
+        NTL(SVB.getContext()) {}
 
   //===------------------------------------------------------------------===//
   // Implementation for interface from ConstraintManager.
@@ -1703,6 +1786,10 @@
 
 private:
   RangeSet::Factory F;
+  NominalTypeList NTL;
+
+  std::tuple<ProgramStateRef, SymbolRef, RangeSet>
+  handleSymbolCast(ProgramStateRef State, SymbolRef Sym, RangeSet R);
 
   RangeSet getRange(ProgramStateRef State, SymbolRef Sym);
   RangeSet getRange(ProgramStateRef State, EquivalenceClass Class);
@@ -1767,7 +1854,8 @@
 
   ProgramStateRef trackDisequality(ProgramStateRef State, SymbolRef LHS,
                                    SymbolRef RHS) {
-    return EquivalenceClass::markDisequal(getBasicVals(), F, State, LHS, RHS);
+    return EquivalenceClass::markDisequal(getBasicVals(), F, State, NTL, LHS,
+                                          RHS);
   }
 
   ProgramStateRef trackEquality(ProgramStateRef State, SymbolRef LHS,
@@ -2035,25 +2123,23 @@
   return isTrivial(State) && Reaper.isDead(getRepresentativeSymbol());
 }
 
-inline ProgramStateRef EquivalenceClass::markDisequal(BasicValueFactory &VF,
-                                                      RangeSet::Factory &RF,
-                                                      ProgramStateRef State,
-                                                      SymbolRef First,
-                                                      SymbolRef Second) {
-  return markDisequal(VF, RF, State, find(State, First), find(State, Second));
+inline ProgramStateRef
+EquivalenceClass::markDisequal(BasicValueFactory &VF, RangeSet::Factory &RF,
+                               ProgramStateRef State, NominalTypeList &NTL,
+                               SymbolRef First, SymbolRef Second) {
+  return markDisequal(VF, RF, State, NTL, find(State, First),
+                      find(State, Second));
 }
 
-inline ProgramStateRef EquivalenceClass::markDisequal(BasicValueFactory &VF,
-                                                      RangeSet::Factory &RF,
-                                                      ProgramStateRef State,
-                                                      EquivalenceClass First,
-                                                      EquivalenceClass Second) {
-  return First.markDisequal(VF, RF, State, Second);
+inline ProgramStateRef EquivalenceClass::markDisequal(
+    BasicValueFactory &VF, RangeSet::Factory &RF, ProgramStateRef State,
+    NominalTypeList &NTL, EquivalenceClass First, EquivalenceClass Second) {
+  return First.markDisequal(VF, RF, State, NTL, Second);
 }
 
 inline ProgramStateRef
 EquivalenceClass::markDisequal(BasicValueFactory &VF, RangeSet::Factory &RF,
-                               ProgramStateRef State,
+                               ProgramStateRef State, NominalTypeList &NTL,
                                EquivalenceClass Other) const {
   // If we know that two classes are equal, we can only produce an infeasible
   // state.
@@ -2066,10 +2152,10 @@
 
   // Disequality is a symmetric relation, so if we mark A as disequal to B,
   // we should also mark B as disequalt to A.
-  if (!addToDisequalityInfo(DisequalityInfo, Constraints, VF, RF, State, *this,
-                            Other) ||
-      !addToDisequalityInfo(DisequalityInfo, Constraints, VF, RF, State, Other,
-                            *this))
+  if (!addToDisequalityInfo(DisequalityInfo, Constraints, VF, RF, State, NTL,
+                            *this, Other) ||
+      !addToDisequalityInfo(DisequalityInfo, Constraints, VF, RF, State, NTL,
+                            Other, *this))
     return nullptr;
 
   assert(areFeasible(Constraints) && "Constraint manager shouldn't produce "
@@ -2084,7 +2170,7 @@
 inline bool EquivalenceClass::addToDisequalityInfo(
     DisequalityMapTy &Info, ConstraintRangeTy &Constraints,
     BasicValueFactory &VF, RangeSet::Factory &RF, ProgramStateRef State,
-    EquivalenceClass First, EquivalenceClass Second) {
+    NominalTypeList &NTL, EquivalenceClass First, EquivalenceClass Second) {
 
   // 1. Get all of the required factories.
   DisequalityMapTy::Factory &F = State->get_context<DisequalityMap>();
@@ -2107,7 +2193,7 @@
     if (const llvm::APSInt *Point = SecondConstraint->getConcreteValue()) {
 
       RangeSet FirstConstraint = SymbolicRangeInferrer::inferRange(
-          VF, RF, State, First.getRepresentativeSymbol());
+          VF, RF, State, NTL, First.getRepresentativeSymbol());
 
       FirstConstraint = RF.deletePoint(FirstConstraint, *Point);
 
@@ -2423,12 +2509,13 @@
 
 RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
                                           SymbolRef Sym) {
-  return SymbolicRangeInferrer::inferRange(getBasicVals(), F, State, Sym);
+  return SymbolicRangeInferrer::inferRange(getBasicVals(), F, State, NTL, Sym);
 }
 
 RangeSet RangeConstraintManager::getRange(ProgramStateRef State,
                                           EquivalenceClass Class) {
-  return SymbolicRangeInferrer::inferRange(getBasicVals(), F, State, Class);
+  return SymbolicRangeInferrer::inferRange(getBasicVals(), F, State, NTL,
+                                           Class);
 }
 
 //===------------------------------------------------------------------------===
@@ -2443,6 +2530,67 @@
 // As an example, the range [UINT_MAX-1, 3) contains five values: UINT_MAX-1,
 // UINT_MAX, 0, 1, and 2.
 
+std::tuple<ProgramStateRef, SymbolRef, RangeSet>
+RangeConstraintManager::handleSymbolCast(ProgramStateRef State, SymbolRef Sym,
+                                         RangeSet R) {
+  QualType T = Sym->getType();
+  if (!T->isIntegralOrEnumerationType() || R.isEmpty())
+    return {State, Sym, R};
+
+  BasicValueFactory &BVF = getBasicVals();
+  ASTContext &C = BVF.getContext();
+  SymbolRef RootSym = Sym;
+  if (isa<SymbolCast>(Sym)) {
+    uint32_t MinBitWidth = UINT32_MAX;
+    do {
+      // We only handle integral cast, when all the types are integrals.
+      T = RootSym->getType();
+      if (!T->isIntegralOrEnumerationType())
+        return {State, Sym, R};
+      MinBitWidth = std::min(MinBitWidth, C.getIntWidth(T));
+      RootSym = cast<SymbolCast>(RootSym)->getOperand();
+    } while (isa<SymbolCast>(RootSym));
+
+    QualType RootTy = RootSym->getType();
+    uint32_t RootBitWidth = C.getIntWidth(RootSym->getType());
+    const bool isTruncated = (MinBitWidth < RootBitWidth);
+    if (isTruncated) {
+      // Trancation occurred. High bits lost. We can't reason about ranges of
+      // the original(root) operand in this case. Just add a cast symbol to the
+      // constraint set.
+      // Create a new SymbolCast with a signed type and the least met size.
+      // E.g. (int)(uchar)x -> (char8)x
+      CanQualType Ty = *NTL.findByWidth(MinBitWidth);
+      R = F.castTo(R, Ty);
+      Sym = getSymbolManager().getCastSymbol(RootSym, RootTy, Ty);
+    } else {
+      // Promotion or conversion occurred. No bit lost.
+      // Get a range to the original(root) type and add to the constraint set.
+      R = F.castTo(R, RootTy);
+      Sym = RootSym;
+    }
+  }
+
+  T = Sym->getType();
+  for (auto It = NTL.findByWidth(C.getIntWidth(T)) - 1; It >= NTL.begin();
+       --It) {
+    SymbolRef S = State->getSymbolManager().getCastSymbol(
+        RootSym, RootSym->getType(), *It);
+    if (const RangeSet *RS = getConstraint(State, S)) {
+      RangeSet TruncR = F.castTo(R, *It);
+      TruncR = F.intersect(*RS, TruncR);
+      if (TruncR.isEmpty()) {
+        // This seems to be an infisible branch. Return an empty set.
+        R = TruncR;
+        break;
+      }
+      State = setConstraint(State, S, TruncR);
+    }
+  }
+
+  return {State, Sym, R};
+}
+
 ProgramStateRef
 RangeConstraintManager::assumeSymNE(ProgramStateRef St, SymbolRef Sym,
                                     const llvm::APSInt &Int,
@@ -2457,6 +2605,7 @@
   RangeSet New = getRange(St, Sym);
   New = F.deletePoint(New, Point);
 
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
   return trackNE(New, St, Sym, Int, Adjustment);
 }
 
@@ -2474,6 +2623,7 @@
   RangeSet New = getRange(St, Sym);
   New = F.intersect(New, AdjInt);
 
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
   return trackEQ(New, St, Sym, Int, Adjustment);
 }
 
@@ -2511,6 +2661,8 @@
                                     const llvm::APSInt &Int,
                                     const llvm::APSInt &Adjustment) {
   RangeSet New = getSymLTRange(St, Sym, Int, Adjustment);
+
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
   return trackNE(New, St, Sym, Int, Adjustment);
 }
 
@@ -2548,6 +2700,8 @@
                                     const llvm::APSInt &Int,
                                     const llvm::APSInt &Adjustment) {
   RangeSet New = getSymGTRange(St, Sym, Int, Adjustment);
+
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
   return trackNE(New, St, Sym, Int, Adjustment);
 }
 
@@ -2585,7 +2739,13 @@
                                     const llvm::APSInt &Int,
                                     const llvm::APSInt &Adjustment) {
   RangeSet New = getSymGERange(St, Sym, Int, Adjustment);
-  return New.isEmpty() ? nullptr : setConstraint(St, Sym, New);
+
+  if (New.isEmpty())
+    return nullptr;
+
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
+
+  return setConstraint(St, Sym, New);
 }
 
 RangeSet
@@ -2629,7 +2789,13 @@
                                     const llvm::APSInt &Int,
                                     const llvm::APSInt &Adjustment) {
   RangeSet New = getSymLERange(St, Sym, Int, Adjustment);
-  return New.isEmpty() ? nullptr : setConstraint(St, Sym, New);
+
+  if (New.isEmpty())
+    return nullptr;
+
+  std::tie(St, Sym, New) = handleSymbolCast(St, Sym, New);
+
+  return setConstraint(St, Sym, New);
 }
 
 ProgramStateRef RangeConstraintManager::assumeSymWithinInclusiveRange(
Index: clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
+++ clang/lib/StaticAnalyzer/Core/ExprEngineC.cpp
@@ -431,7 +431,7 @@
       case CK_IntegralCast: {
         // Delegate to SValBuilder to process.
         SVal V = state->getSVal(Ex, LCtx);
-        V = svalBuilder.evalIntegralCast(state, V, T, ExTy);
+        V = svalBuilder.evalCast(V, T, ExTy);
         state = state->BindExpr(CastE, LCtx, V);
         Bldr.generateNode(CastE, Pred, state);
         continue;
Index: clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
===================================================================
--- clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
+++ clang/lib/StaticAnalyzer/Checkers/ExprInspectionChecker.cpp
@@ -418,6 +418,13 @@
 
   ProgramStateRef State = C.getState();
 
+  // Unwrap symbolic expression to skip argument casts on function call.
+  // This is useful when there is no way for overloading function in C
+  // but we need to pass different types of arguments and
+  // implicit cast occures.
+  while (isa<SymbolCast>(Sym))
+    Sym = cast<SymbolCast>(Sym)->getOperand();
+
   C.addTransition(C.getState()->set<DenotedSymbols>(Sym, E));
 }
 
Index: clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
+++ clang/include/clang/StaticAnalyzer/Core/PathSensitive/SValBuilder.h
@@ -118,10 +118,6 @@
 
   SVal evalCast(SVal V, QualType CastTy, QualType OriginalTy);
 
-  // Handles casts of type CK_IntegralCast.
-  SVal evalIntegralCast(ProgramStateRef state, SVal val, QualType castTy,
-                        QualType originalType);
-
   virtual SVal evalMinus(NonLoc val) = 0;
 
   virtual SVal evalComplement(NonLoc val) = 0;
Index: clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
===================================================================
--- clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
+++ clang/include/clang/StaticAnalyzer/Checkers/SValExplainer.h
@@ -135,8 +135,9 @@
            " (" + Visit(S->getRHS()) + ")";
   }
 
-  // TODO: SymbolCast doesn't appear in practice.
-  // Add the relevant code once it does.
+  std::string VisitSymbolCast(const SymbolCast *S) {
+    return "(" + S->getType().getAsString() + ")" + Visit(S->getOperand());
+  }
 
   std::string VisitSymbolicRegion(const SymbolicRegion *R) {
     // Explain 'this' object here.
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to