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}} \ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits