Skip to content

Commit ef9666a

Browse files
authored
[clang][Interp] Fix value truncation when casting int128 to smaller size (#67961)
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.
1 parent 0502d83 commit ef9666a

File tree

2 files changed

+23
-9
lines changed

2 files changed

+23
-9
lines changed

clang/lib/AST/Interp/IntegralAP.h

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,12 @@ template <unsigned Bits, bool Signed> class Integral;
3232
class Boolean;
3333

3434
template <bool Signed> class IntegralAP final {
35+
private:
36+
template <typename T> static T truncateCast(const APSInt &V) {
37+
return std::is_signed_v<T> ? V.trunc(sizeof(T) * 8).getSExtValue()
38+
: V.trunc(sizeof(T) * 8).getZExtValue();
39+
}
40+
3541
public:
3642
APSInt V;
3743

@@ -55,14 +61,14 @@ template <bool Signed> class IntegralAP final {
5561
bool operator<=(IntegralAP RHS) const { return V <= RHS.V; }
5662

5763
explicit operator bool() const { return !V.isZero(); }
58-
explicit operator int8_t() const { return V.getSExtValue(); }
59-
explicit operator uint8_t() const { return V.getZExtValue(); }
60-
explicit operator int16_t() const { return V.getSExtValue(); }
61-
explicit operator uint16_t() const { return V.getZExtValue(); }
62-
explicit operator int32_t() const { return V.getSExtValue(); }
63-
explicit operator uint32_t() const { return V.getZExtValue(); }
64-
explicit operator int64_t() const { return V.getSExtValue(); }
65-
explicit operator uint64_t() const { return V.getZExtValue(); }
64+
explicit operator int8_t() const { return truncateCast<int8_t>(V); }
65+
explicit operator uint8_t() const { return truncateCast<uint8_t>(V); }
66+
explicit operator int16_t() const { return truncateCast<int16_t>(V); }
67+
explicit operator uint16_t() const { return truncateCast<uint16_t>(V); }
68+
explicit operator int32_t() const { return truncateCast<int32_t>(V); }
69+
explicit operator uint32_t() const { return truncateCast<uint32_t>(V); }
70+
explicit operator int64_t() const { return truncateCast<int64_t>(V); }
71+
explicit operator uint64_t() const { return truncateCast<uint64_t>(V); }
6672

6773
template <typename T> static IntegralAP from(T Value, unsigned NumBits = 0) {
6874
assert(NumBits > 0);

clang/test/AST/Interp/literals.cpp

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ namespace i128 {
5353
static_assert(Two == 2, "");
5454

5555
constexpr uint128_t AllOnes = ~static_cast<uint128_t>(0);
56-
static_assert(AllOnes == static_cast<uint128_t>(-1), "");
56+
static_assert(AllOnes == UINT128_MAX, "");
5757

5858
#if __cplusplus >= 201402L
5959
template <typename T>
@@ -70,6 +70,14 @@ namespace i128 {
7070
static_assert(CastFrom<double>(12) == 12, "");
7171
static_assert(CastFrom<long double>(12) == 12, "");
7272

73+
static_assert(CastFrom<char>(AllOnes) == -1, "");
74+
static_assert(CastFrom<unsigned char>(AllOnes) == 0xFF, "");
75+
static_assert(CastFrom<long>(AllOnes) == -1, "");
76+
static_assert(CastFrom<unsigned short>(AllOnes) == 0xFFFF, "");
77+
static_assert(CastFrom<int>(AllOnes) == -1, "");
78+
static_assert(CastFrom<int128_t>(AllOnes) == -1, "");
79+
static_assert(CastFrom<uint128_t>(AllOnes) == AllOnes, "");
80+
7381
template <typename T>
7482
constexpr __int128 CastTo(T A) {
7583
int128_t B = (int128_t)A;

0 commit comments

Comments
 (0)