Index: clang/lib/AST/Interp/Integral.h =================================================================== --- clang/lib/AST/Interp/Integral.h +++ clang/lib/AST/Interp/Integral.h @@ -127,7 +127,11 @@ return Compare(V, RHS.V); } - unsigned countLeadingZeros() const { return llvm::countl_zero(V); } + unsigned countLeadingZeros() const { + if constexpr (!Signed) + return llvm::countl_zero(V); + llvm_unreachable("Don't call countLeadingZeros() on signed types."); + } Integral truncate(unsigned TruncBits) const { if (TruncBits >= Bits) Index: clang/lib/AST/Interp/Interp.h =================================================================== --- clang/lib/AST/Interp/Interp.h +++ clang/lib/AST/Interp/Interp.h @@ -109,8 +109,9 @@ bool CheckCtorCall(InterpState &S, CodePtr OpPC, const Pointer &This); /// Checks if the shift operation is legal. -template -bool CheckShift(InterpState &S, CodePtr OpPC, const RT &RHS, unsigned Bits) { +template +bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, + unsigned Bits) { if (RHS.isNegative()) { const SourceInfo &Loc = S.Current->getSource(OpPC); S.CCEDiag(Loc, diag::note_constexpr_negative_shift) << RHS.toAPSInt(); @@ -125,6 +126,16 @@ QualType Ty = E->getType(); S.CCEDiag(E, diag::note_constexpr_large_shift) << Val << Ty << Bits; return false; + } else if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) { + const Expr *E = S.Current->getExpr(OpPC); + // C++11 [expr.shift]p2: A signed left shift must have a non-negative + // operand, and must not overflow the corresponding unsigned type. + // C++2a [expr.shift]p2: E1 << E2 is the unique value congruent to + // E1 x 2^E2 module 2^N. + if (LHS.isNegative()) + S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << 12; + else if (LHS.toUnsigned().countLeadingZeros() < static_cast(RHS)) + S.CCEDiag(E, diag::note_constexpr_lshift_discards); } return true; } @@ -1612,7 +1623,7 @@ const auto &LHS = S.Stk.pop(); const unsigned Bits = LHS.bitWidth(); - if (!CheckShift(S, OpPC, RHS, Bits)) + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; Integral R; @@ -1629,7 +1640,7 @@ const auto &LHS = S.Stk.pop(); const unsigned Bits = LHS.bitWidth(); - if (!CheckShift(S, OpPC, RHS, Bits)) + if (!CheckShift(S, OpPC, LHS, RHS, Bits)) return false; Integral R; Index: clang/test/AST/Interp/shifts.cpp =================================================================== --- clang/test/AST/Interp/shifts.cpp +++ clang/test/AST/Interp/shifts.cpp @@ -152,4 +152,14 @@ constexpr signed int R = (sizeof(unsigned) * 8) + 1; constexpr decltype(L) M = (R > 32 && R < 64) ? L << R : 0; constexpr decltype(L) M2 = (R > 32 && R < 64) ? L >> R : 0; + + + constexpr int signedShift() { // cxx17-error {{never produces a constant expression}} \ + // ref-cxx17-error {{never produces a constant expression}} + return 1024 << 31; // cxx17-warning {{signed shift result}} \ + // ref-cxx17-warning {{signed shift result}} \ + // cxx17-note {{signed left shift discards bits}} \ + // ref-cxx17-note {{signed left shift discards bits}} + } + };