[clang] [clang][bytecode] Allow right-shift of negative values (PR #108987)
Timm Baeder via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 17 08:03:26 PDT 2024
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?= <tbaeder at 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}} \
More information about the cfe-commits
mailing list