Skip to content

Commit 0050503

Browse files
authored
[clang][bytecode] Allow right-shift of negative values (#108987)
We used to incorrectly diagnose this as a "left shift of negative value".
1 parent 3d87e21 commit 0050503

File tree

2 files changed

+20
-16
lines changed

2 files changed

+20
-16
lines changed

clang/lib/AST/ByteCode/Interp.h

Lines changed: 19 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ bool CallBI(InterpState &S, CodePtr OpPC, const Function *Func,
159159
bool CallPtr(InterpState &S, CodePtr OpPC, uint32_t ArgSize,
160160
const CallExpr *CE);
161161

162+
enum class ShiftDir { Left, Right };
163+
162164
/// Checks if the shift operation is legal.
163-
template <typename LT, typename RT>
165+
template <ShiftDir Dir, typename LT, typename RT>
164166
bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
165167
unsigned Bits) {
166168
if (RHS.isNegative()) {
@@ -181,19 +183,21 @@ bool CheckShift(InterpState &S, CodePtr OpPC, const LT &LHS, const RT &RHS,
181183
return false;
182184
}
183185

184-
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
185-
const Expr *E = S.Current->getExpr(OpPC);
186-
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
187-
// operand, and must not overflow the corresponding unsigned type.
188-
if (LHS.isNegative()) {
189-
S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
190-
if (!S.noteUndefinedBehavior())
191-
return false;
192-
} else if (LHS.toUnsigned().countLeadingZeros() <
193-
static_cast<unsigned>(RHS)) {
194-
S.CCEDiag(E, diag::note_constexpr_lshift_discards);
195-
if (!S.noteUndefinedBehavior())
196-
return false;
186+
if constexpr (Dir == ShiftDir::Left) {
187+
if (LHS.isSigned() && !S.getLangOpts().CPlusPlus20) {
188+
const Expr *E = S.Current->getExpr(OpPC);
189+
// C++11 [expr.shift]p2: A signed left shift must have a non-negative
190+
// operand, and must not overflow the corresponding unsigned type.
191+
if (LHS.isNegative()) {
192+
S.CCEDiag(E, diag::note_constexpr_lshift_of_negative) << LHS.toAPSInt();
193+
if (!S.noteUndefinedBehavior())
194+
return false;
195+
} else if (LHS.toUnsigned().countLeadingZeros() <
196+
static_cast<unsigned>(RHS)) {
197+
S.CCEDiag(E, diag::note_constexpr_lshift_discards);
198+
if (!S.noteUndefinedBehavior())
199+
return false;
200+
}
197201
}
198202
}
199203

@@ -2394,7 +2398,6 @@ inline bool RVOPtr(InterpState &S, CodePtr OpPC) {
23942398
//===----------------------------------------------------------------------===//
23952399
// Shr, Shl
23962400
//===----------------------------------------------------------------------===//
2397-
enum class ShiftDir { Left, Right };
23982401

23992402
template <class LT, class RT, ShiftDir Dir>
24002403
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) {
24312434
}
24322435
}
24332436

2434-
if (!CheckShift(S, OpPC, LHS, RHS, Bits))
2437+
if (!CheckShift<Dir>(S, OpPC, LHS, RHS, Bits))
24352438
return false;
24362439

24372440
// Limit the shift amount to Bits - 1. If this happened,

clang/test/AST/ByteCode/shifts.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55

66
#define INT_MIN (~__INT_MAX__)
77

8+
constexpr int a = -1 >> 3;
89

910
namespace shifts {
1011
constexpr void test() { // ref-error {{constexpr function never produces a constant expression}} \

0 commit comments

Comments
 (0)