diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h index 5e9c07545ae1f..23a2756a18f69 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::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::from(R)); return true; } diff --git a/clang/test/AST/Interp/shifts.cpp b/clang/test/AST/Interp/shifts.cpp index e5201b3f8bbef..76047d0f752d5 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}} \