[clang] 39fd3fc - [clang][Interp] Don't fail on shifts greater than type bitwidth

Timm Bäder via cfe-commits cfe-commits at lists.llvm.org
Tue Feb 20 02:33:07 PST 2024


Author: Timm Bäder
Date: 2024-02-20T11:32:37+01:00
New Revision: 39fd3fcd4527d627ee7f526a651aa47c27a9ad0d

URL: https://github.com/llvm/llvm-project/commit/39fd3fcd4527d627ee7f526a651aa47c27a9ad0d
DIFF: https://github.com/llvm/llvm-project/commit/39fd3fcd4527d627ee7f526a651aa47c27a9ad0d.diff

LOG: [clang][Interp] Don't fail on shifts greater than type bitwidth

We need to limit the shift width to the type bitwidth, then do the
shift and report success, but still diagnose what we limited the
shiftwidth.

Added: 
    

Modified: 
    clang/lib/AST/Interp/Interp.h
    clang/test/AST/Interp/shifts.cpp

Removed: 
    


################################################################################
diff  --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 5e9c07545ae1fb..23a2756a18f690 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -135,7 +135,7 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
     const APSInt Val = RHS.toAPSInt();
     QualType Ty = E->getType();
     S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits;
-    return false;
+    return true; // We will do the shift anyway but fix up the shift amount.
   }
 
   if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
@@ -1798,11 +1798,17 @@ inline bool Shr(InterpState &S, CodePtr OpPC) {
   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
     return false;
 
+  // Limit the shift amount to Bits - 1. If this happened,
+  // it has already been diagnosed by CheckShift() above,
+  // but we still need to handle it.
   typename LT::AsUnsigned R;
-  LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
-                             LT::AsUnsigned::from(RHS), Bits, &R);
+  if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
+    LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
+                               LT::AsUnsigned::from(Bits - 1), Bits, &R);
+  else
+    LT::AsUnsigned::shiftRight(LT::AsUnsigned::from(LHS),
+                               LT::AsUnsigned::from(RHS, Bits), Bits, &R);
   S.Stk.push<LT>(LT::from(R));
-
   return true;
 }
 
@@ -1817,9 +1823,17 @@ inline bool Shl(InterpState &S, CodePtr OpPC) {
   if (!CheckShift(S, OpPC, LHS, RHS, Bits))
     return false;
 
+  // Limit the shift amount to Bits - 1. If this happened,
+  // it has already been diagnosed by CheckShift() above,
+  // but we still need to handle it.
   typename LT::AsUnsigned R;
-  LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
-                            LT::AsUnsigned::from(RHS, Bits), Bits, &R);
+  if (RHS > RT::from(Bits - 1, RHS.bitWidth()))
+    LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
+                              LT::AsUnsigned::from(Bits - 1), Bits, &R);
+  else
+    LT::AsUnsigned::shiftLeft(LT::AsUnsigned::from(LHS),
+                              LT::AsUnsigned::from(RHS, Bits), Bits, &R);
+
   S.Stk.push<LT>(LT::from(R));
   return true;
 }

diff  --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp
index e5201b3f8bbef7..76047d0f752d54 100644
--- a/clang/test/AST/Interp/shifts.cpp
+++ b/clang/test/AST/Interp/shifts.cpp
@@ -34,12 +34,13 @@ namespace shifts {
                  // ref-warning {{shift count is negative}} \
                  // ref-cxx17-warning {{shift count is negative}}
     c = 1 << (unsigned)-1; // expected-warning {{shift count >= width of type}} \
-                           // FIXME: 'implicit conversion' warning missing in the new interpreter. \
+                           // expected-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
                            // cxx17-warning {{shift count >= width of type}} \
+                           // cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
                            // ref-warning {{shift count >= width of type}} \
-                           // ref-warning {{implicit conversion}} \
+                           // ref-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}} \
                            // ref-cxx17-warning {{shift count >= width of type}} \
-                           // ref-cxx17-warning {{implicit conversion}}
+                           // ref-cxx17-warning {{implicit conversion from 'int' to 'char' changes value from -2147483648 to 0}}
     c = 1 >> (unsigned)-1; // expected-warning {{shift count >= width of type}} \
                            // cxx17-warning {{shift count >= width of type}} \
                            // ref-warning {{shift count >= width of type}} \


        


More information about the cfe-commits mailing list