[PATCH] D140845: [clang][Interp] Fix left-/right-shifting more than sizeof(unsigned)

Timm Bäder via Phabricator via cfe-commits cfe-commits at lists.llvm.org
Mon Jan 2 07:38:49 PST 2023


tbaeder created this revision.
tbaeder added reviewers: aaron.ballman, erichkeane, tahonermann, shafik.
Herald added a project: All.
tbaeder requested review of this revision.
Herald added a project: clang.
Herald added a subscriber: cfe-commits.

  We were just casting to `unsigned` before, so that caused problems when
  shifting more bits than `unsigned` has.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D140845

Files:
  clang/lib/AST/Interp/Integral.h
  clang/lib/AST/Interp/Interp.h
  clang/test/AST/Interp/shifts.cpp


Index: clang/test/AST/Interp/shifts.cpp
===================================================================
--- clang/test/AST/Interp/shifts.cpp
+++ clang/test/AST/Interp/shifts.cpp
@@ -143,4 +143,8 @@
 
   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;
 };
Index: clang/lib/AST/Interp/Interp.h
===================================================================
--- clang/lib/AST/Interp/Interp.h
+++ clang/lib/AST/Interp/Interp.h
@@ -1321,8 +1321,9 @@
   if (!CheckShift<RT>(S, OpPC, RHS, Bits))
     return false;
 
-  unsigned URHS = static_cast<unsigned>(RHS);
-  S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) >> URHS, LHS.bitWidth()));
+  Integral<LT::bitWidth(), false> R;
+  Integral<LT::bitWidth(), false>::shiftRight(LHS.toUnsigned(), RHS, Bits, &R);
+  S.Stk.push<LT>(R);
   return true;
 }
 
@@ -1337,9 +1338,9 @@
   if (!CheckShift<RT>(S, OpPC, RHS, Bits))
     return false;
 
-  unsigned URHS = static_cast<unsigned>(RHS);
-  S.Stk.push<LT>(LT::from(static_cast<unsigned>(LHS) << URHS, LHS.bitWidth()));
-
+  Integral<LT::bitWidth(), false> R;
+  Integral<LT::bitWidth(), false>::shiftLeft(LHS.toUnsigned(), RHS, Bits, &R);
+  S.Stk.push<LT>(R);
   return true;
 }
 
Index: clang/lib/AST/Interp/Integral.h
===================================================================
--- clang/lib/AST/Interp/Integral.h
+++ clang/lib/AST/Interp/Integral.h
@@ -241,6 +241,18 @@
     return false;
   }
 
+  template <unsigned RHSBits, bool RHSSign>
+  static void shiftLeft(const Integral A, const Integral<RHSBits, RHSSign> B,
+                        unsigned OpBits, Integral *R) {
+    *R = Integral::from(A.V << B.V, OpBits);
+  }
+
+  template <unsigned RHSBits, bool RHSSign>
+  static void shiftRight(const Integral A, const Integral<RHSBits, RHSSign> B,
+                         unsigned OpBits, Integral *R) {
+    *R = Integral::from(A.V >> B.V, OpBits);
+  }
+
 private:
   template <typename T> static bool CheckAddUB(T A, T B, T &R) {
     if constexpr (std::is_signed_v<T>) {


-------------- next part --------------
A non-text attachment was scrubbed...
Name: D140845.485864.patch
Type: text/x-patch
Size: 2149 bytes
Desc: not available
URL: <http://lists.llvm.org/pipermail/cfe-commits/attachments/20230102/bfb461dc/attachment.bin>


More information about the cfe-commits mailing list