[clang] [clang][Interp] Fix value truncation when casting int128 to smaller size (PR #67961)

via cfe-commits cfe-commits at lists.llvm.org
Mon Oct 2 01:50:38 PDT 2023


Timm =?utf-8?q?Bäder?= <tbaeder at redhat.com>
Message-ID:
In-Reply-To: <llvm/llvm-project/pull/67961/clang at github.com>


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

<details>
<summary>Changes</summary>

Before this patch, we would run into an assertion in `APInt::get{S,Z}ExtValue()` because the `AllOnes` value had more than 64 active bits.

---
Full diff: https://github.com/llvm/llvm-project/pull/67961.diff


2 Files Affected:

- (modified) clang/lib/AST/Interp/IntegralAP.h (+13-9) 
- (modified) clang/test/AST/Interp/literals.cpp (+9) 


``````````diff
diff --git a/clang/lib/AST/Interp/IntegralAP.h b/clang/lib/AST/Interp/IntegralAP.h
index b2b367f30c238fe..f67b15dbc9b31ac 100644
--- a/clang/lib/AST/Interp/IntegralAP.h
+++ b/clang/lib/AST/Interp/IntegralAP.h
@@ -55,14 +55,14 @@ template <bool Signed> class IntegralAP final {
   bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
 
   explicit operator bool() const { return !V.isZero(); }
-  explicit operator int8_t() const { return V.getSExtValue(); }
-  explicit operator uint8_t() const { return V.getZExtValue(); }
-  explicit operator int16_t() const { return V.getSExtValue(); }
-  explicit operator uint16_t() const { return V.getZExtValue(); }
-  explicit operator int32_t() const { return V.getSExtValue(); }
-  explicit operator uint32_t() const { return V.getZExtValue(); }
-  explicit operator int64_t() const { return V.getSExtValue(); }
-  explicit operator uint64_t() const { return V.getZExtValue(); }
+  explicit operator int8_t() const { return truncateCast<int8_t>(V); }
+  explicit operator uint8_t() const { return truncateCast<uint8_t>(V); }
+  explicit operator int16_t() const { return truncateCast<int16_t>(V); }
+  explicit operator uint16_t() const { return truncateCast<uint16_t>(V); }
+  explicit operator int32_t() const { return truncateCast<int32_t>(V); }
+  explicit operator uint32_t() const { return truncateCast<uint32_t>(V); }
+  explicit operator int64_t() const { return truncateCast<int64_t>(V); }
+  explicit operator uint64_t() const { return truncateCast<uint64_t>(V); }
 
   template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
     assert(NumBits > 0);
@@ -210,7 +210,6 @@ template <bool Signed> class IntegralAP final {
   }
 
   static bool comp(IntegralAP A, IntegralAP *R) {
-    assert(false);
     *R = IntegralAP(~A.V);
     return false;
   }
@@ -249,6 +248,11 @@ template <bool Signed> class IntegralAP final {
     R->V = A.V - B.V;
     return false; // Success!
   }
+
+  template <typename T> static T truncateCast(const APSInt &V) {
+    return std::is_signed_v<T> ? V.trunc(sizeof(T) * 8).getSExtValue()
+                               : V.trunc(sizeof(T) * 8).getZExtValue();
+  }
 };
 
 template <bool Signed>
diff --git a/clang/test/AST/Interp/literals.cpp b/clang/test/AST/Interp/literals.cpp
index eca0e4c2cbd26f1..65d211422ddac92 100644
--- a/clang/test/AST/Interp/literals.cpp
+++ b/clang/test/AST/Interp/literals.cpp
@@ -52,6 +52,9 @@ namespace i128 {
   constexpr int128_t Two = (int128_t)1 << 1ul;
   static_assert(Two == 2, "");
 
+  constexpr uint128_t AllOnes = ~static_cast<uint128_t>(0);
+  static_assert(AllOnes == UINT128_MAX, "");
+
 #if __cplusplus >= 201402L
   template <typename T>
   constexpr T CastFrom(__int128_t A) {
@@ -67,6 +70,12 @@ namespace i128 {
   static_assert(CastFrom<double>(12) == 12, "");
   static_assert(CastFrom<long double>(12) == 12, "");
 
+  static_assert(CastFrom<char>(AllOnes) == -1, "");
+  static_assert(CastFrom<unsigned char>(AllOnes) == 0xFF, "");
+  static_assert(CastFrom<long>(AllOnes) == -1, "");
+  static_assert(CastFrom<unsigned short>(AllOnes) == 0xFFFF, "");
+  static_assert(CastFrom<int>(AllOnes) == -1, "");
+
   template <typename T>
   constexpr __int128 CastTo(T A) {
     int128_t B = (int128_t)A;

``````````

</details>


https://github.com/llvm/llvm-project/pull/67961


More information about the cfe-commits mailing list