@@ -2511,50 +2511,52 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
25112511 S, OpPC, LHS, RHS);
25122512 }
25132513
2514- if constexpr (Dir == ShiftDir::Left) {
2515- if (LHS.isNegative () && !S.getLangOpts ().CPlusPlus20 ) {
2516- // C++11 [expr.shift]p2: A signed left shift must have a non-negative
2517- // operand, and must not overflow the corresponding unsigned type.
2518- // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to
2519- // E1 x 2^E2 module 2^N.
2520- const SourceInfo &Loc = S.Current ->getSource (OpPC);
2521- S.CCEDiag (Loc, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt ();
2522- if (!S.noteUndefinedBehavior ())
2523- return false ;
2524- }
2525- }
2526-
25272514 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
25282515 return false ;
25292516
25302517 // Limit the shift amount to Bits - 1. If this happened,
25312518 // it has already been diagnosed by CheckShift() above,
25322519 // but we still need to handle it.
2520+ // Note that we have to be extra careful here since we're doing the shift in
2521+ // any case, but we need to adjust the shift amount or the way we do the shift
2522+ // for the potential error cases.
25332523 typename LT::AsUnsigned R;
2524+ unsigned MaxShiftAmount = LHS.bitWidth () - 1 ;
25342525 if constexpr (Dir == ShiftDir::Left) {
2535- if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2536- LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2537- LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2538- else
2526+ if (Compare (RHS, RT::from (MaxShiftAmount, RHS.bitWidth ())) ==
2527+ ComparisonCategoryResult::Greater) {
2528+ if (LHS.isNegative ())
2529+ R = LT::AsUnsigned::zero (LHS.bitWidth ());
2530+ else {
2531+ RHS = RT::from (LHS.countLeadingZeros (), RHS.bitWidth ());
2532+ LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2533+ LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2534+ }
2535+ } else if (LHS.isNegative ()) {
2536+ if (LHS.isMin ()) {
2537+ R = LT::AsUnsigned::zero (LHS.bitWidth ());
2538+ } else {
2539+ // If the LHS is negative, perform the cast and invert the result.
2540+ typename LT::AsUnsigned LHSU = LT::AsUnsigned::from (-LHS);
2541+ LT::AsUnsigned::shiftLeft (LHSU, LT::AsUnsigned::from (RHS, Bits), Bits,
2542+ &R);
2543+ R = -R;
2544+ }
2545+ } else {
2546+ // The good case, a simple left shift.
25392547 LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
25402548 LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2549+ }
25412550 } else {
2542- if (RHS > RT::from (Bits - 1 , RHS.bitWidth ()))
2543- LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2544- LT::AsUnsigned::from (Bits - 1 ), Bits, &R);
2545- else
2546- LT::AsUnsigned::shiftRight (LT::AsUnsigned::from (LHS),
2547- LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2548- }
2549-
2550- // We did the shift above as unsigned. Restore the sign bit if we need to.
2551- if constexpr (Dir == ShiftDir::Right) {
2552- if (LHS.isSigned () && LHS.isNegative ()) {
2553- typename LT::AsUnsigned SignBit;
2554- LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (1 , Bits),
2555- LT::AsUnsigned::from (Bits - 1 , Bits), Bits,
2556- &SignBit);
2557- LT::AsUnsigned::bitOr (R, SignBit, Bits, &R);
2551+ // Right shift.
2552+ if (Compare (RHS, RT::from (MaxShiftAmount, RHS.bitWidth ())) ==
2553+ ComparisonCategoryResult::Greater) {
2554+ R = LT::AsUnsigned::from (-1 );
2555+ } else {
2556+ // Do the shift on potentially signed LT, then convert to unsigned type.
2557+ LT A;
2558+ LT::shiftRight (LHS, LT::from (RHS, Bits), Bits, &A);
2559+ R = LT::AsUnsigned::from (A);
25582560 }
25592561 }
25602562
0 commit comments