diff --git a/clang/lib/AST/Interp/Integral.h b/clang/lib/AST/Interp/Integral.h --- a/clang/lib/AST/Interp/Integral.h +++ b/clang/lib/AST/Interp/Integral.h @@ -234,6 +234,18 @@ return false; } + template + static void shiftLeft(const Integral A, const Integral B, + unsigned OpBits, Integral *R) { + *R = Integral::from(A.V << B.V, OpBits); + } + + template + static void shiftRight(const Integral A, const Integral B, + unsigned OpBits, Integral *R) { + *R = Integral::from(A.V >> B.V, OpBits); + } + private: template static bool CheckAddUB(T A, T B, T &R) { if constexpr (std::is_signed_v) { diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h --- a/clang/lib/AST/Interp/Interp.h +++ b/clang/lib/AST/Interp/Interp.h @@ -1334,8 +1334,9 @@ if (!CheckShift(S, OpPC, RHS, Bits)) return false; - unsigned URHS = static_cast(RHS); - S.Stk.push(LT::from(static_cast(LHS) >> URHS, LHS.bitWidth())); + Integral R; + Integral::shiftRight(LHS.toUnsigned(), RHS, Bits, &R); + S.Stk.push(R); return true; } @@ -1350,9 +1351,9 @@ if (!CheckShift(S, OpPC, RHS, Bits)) return false; - unsigned URHS = static_cast(RHS); - S.Stk.push(LT::from(static_cast(LHS) << URHS, LHS.bitWidth())); - + Integral R; + Integral::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R); + S.Stk.push(R); return true; } diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp --- a/clang/test/AST/Interp/shifts.cpp +++ b/clang/test/AST/Interp/shifts.cpp @@ -143,4 +143,9 @@ constexpr char c2 = 1; constexpr int i3 = c2 << (__CHAR_BIT__ + 1); // Not ill-formed + + constexpr signed long int L = 1; + constexpr signed int R = 62; + constexpr decltype(L) M = L << R; + constexpr decltype(L) M2 = L >> R; };