@@ -2511,52 +2511,50 @@ 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+
25142527 if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
25152528 return false ;
25162529
25172530 // Limit the shift amount to Bits - 1. If this happened,
25182531 // it has already been diagnosed by CheckShift() above,
25192532 // 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.
25232533 typename LT::AsUnsigned R;
2524- unsigned MaxShiftAmount = LHS.bitWidth () - 1 ;
25252534 if constexpr (Dir == ShiftDir::Left) {
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.
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
25472539 LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
25482540 LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2549- }
25502541 } else {
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);
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);
25602558 }
25612559 }
25622560
0 commit comments