https://github.com/tbaederr created https://github.com/llvm/llvm-project/pull/108987
We used to incorrectly diagnose this as a "left shift of negative value". >From 7836fe844ce9dc243d7a2b81daaaf462e02d772f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Timm=20B=C3=A4der?= <tbae...@redhat.com> Date: Tue, 17 Sep 2024 16:56:52 +0200 Subject: [PATCH] [clang][bytecode] Allow right-shift of negative values We used to incorrectly diagnose this as a "left shift of negative value". --- clang/lib/AST/ByteCode/Interp.h | 35 ++++++++++++++++-------------- clang/test/AST/ByteCode/shifts.cpp | 1 + 2 files changed, 20 insertions(+), 16 deletions(-) diff --git a/clang/lib/AST/ByteCode/Interp.h b/clang/lib/AST/ByteCode/Interp.h index 3d507e2e2ba764..52ccefee88642a 100644 --- a/clang/lib/AST/ByteCode/Interp.h +++ b/clang/lib/AST/ByteCode/Interp.h @@ -159,8 +159,10 @@ bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func, bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize, const CallExpr *CE); +enum class ShiftDir { Left, Right }; + /// Checks if the shift operation is legal. -template <typename LT, typename RT> +template <ShiftDir Dir, typename LT, typename RT> bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, unsigned Bits) { if (RHS.isNegative()) { @@ -181,19 +183,21 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS, return false; } - 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. - if (LHS.isNegative()) { - S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); - if (!S.noteUndefinedBehavior()) - return false; - } else if (LHS.toUnsigned().countLeadingZeros() < - static_cast<unsigned>(RHS)) { - S.CCEDiag(E, diag::note_constexpr_lshift_discards); - if (!S.noteUndefinedBehavior()) - return false; + if constexpr (Dir == ShiftDir::Left) { + 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. + if (LHS.isNegative()) { + S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt(); + if (!S.noteUndefinedBehavior()) + return false; + } else if (LHS.toUnsigned().countLeadingZeros() < + static_cast<unsigned>(RHS)) { + S.CCEDiag(E, diag::note_constexpr_lshift_discards); + if (!S.noteUndefinedBehavior()) + return false; + } } } @@ -2394,7 +2398,6 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) { //===----------------------------------------------------------------------===// // Shr, Shl //===----------------------------------------------------------------------===// -enum class ShiftDir { Left, Right }; template <class LT, class RT, ShiftDir Dir> inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { @@ -2431,7 +2434,7 @@ inline bool DoShift(InterpState &S, CodePtr OpPC, LT &LHS, RT &RHS) { } } - if (!CheckShift(S, OpPC, LHS, RHS, Bits)) + if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits)) return false; // Limit the shift amount to Bits - 1. If this happened, diff --git a/clang/test/AST/ByteCode/shifts.cpp b/clang/test/AST/ByteCode/shifts.cpp index 360b87b7ee04f8..0b3383731c6774 100644 --- a/clang/test/AST/ByteCode/shifts.cpp +++ b/clang/test/AST/ByteCode/shifts.cpp @@ -5,6 +5,7 @@ #define INT_MIN (~__INT_MAX__) +constexpr int a = -1 >> 3; namespace shifts { constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \ _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits