@@ -2511,50 +2511,52 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) {
2511
2511
S, OpPC, LHS, RHS);
2512
2512
}
2513
2513
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
-
2527
2514
if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
2528
2515
return false ;
2529
2516
2530
2517
// Limit the shift amount to Bits - 1. If this happened,
2531
2518
// it has already been diagnosed by CheckShift() above,
2532
2519
// 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.
2533
2523
typename LT::AsUnsigned R;
2524
+ unsigned MaxShiftAmount = LHS.bitWidth () - 1 ;
2534
2525
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.
2539
2547
LT::AsUnsigned::shiftLeft (LT::AsUnsigned::from (LHS),
2540
2548
LT::AsUnsigned::from (RHS, Bits), Bits, &R);
2549
+ }
2541
2550
} 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);
2558
2560
}
2559
2561
}
2560
2562
0 commit comments