[clang] [clang] Fix shift-count diagnostics for compound assignments (PR #234830)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Oct 22 20:48:09 PDT 2026
https://github.com/ShivaGanesh265 created https://github.com/llvm/llvm-project/pull/234830
Fix shift-count warnings for compound shift assignments when the left operand gets promoted to a wider integer type.
Now, `DiagnoseBadShiftValues` checks the shift count against the promoted type of the left operand. For ex: with `unsigned char x; x >>= 8;`, the shift uses the promoted type rather than the original type of `x`.
Added tests for C and C++ covering valid and invalid shift counts, along with constant-evaluation cases.
Fixes #234217.
## Testing
- `clang/test/Sema/shift.c`
- `clang/test/SemaCXX/shift.cpp`
- `clang/test/AST/ByteCode/shifts.cpp`
- Related shift-count regression tests
- Sema and SemaCXX test suites
Sema and SemaCXX tests passed with no unexpected failures.
GenAI(Chatgpt) was used for understanding of the source code and learning the concepts
>From 50ff5c6d4d6f2deeb3e3a85ad7148b907f6195ce Mon Sep 17 00:00:00 2001
From: ShivaGanesh265 <cs24btech11003 at iith.ac.in>
Date: Fri, 23 Oct 2026 03:38:13 +0000
Subject: [PATCH] [clang] Fix shift-count diagnostics for compound assignments
---
clang/lib/Sema/SemaExpr.cpp | 4 ++-
clang/test/AST/ByteCode/shifts.cpp | 22 ++++----------
clang/test/Sema/shift.c | 46 +++++++++++++++++++++++++++---
clang/test/SemaCXX/shift.cpp | 46 +++++++++++++++++++++++++++---
4 files changed, 93 insertions(+), 25 deletions(-)
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 563b9297a6f288..6d0d81834f789f 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12174,7 +12174,9 @@ static void DiagnoseBadShiftValues(Sema& S, ExprResult &LHS, ExprResult &RHS,
return;
}
- QualType LHSExprType = LHS.get()->getType();
+ // Check the shift count against the width of the promoted left operand.
+ // For compound assignments, use the promoted type, not the original LHS type.
+ QualType LHSExprType = LHSType;
uint64_t LeftSize = S.Context.getTypeSize(LHSExprType);
if (LHSExprType->isBitIntType())
LeftSize = S.Context.getIntWidth(LHSExprType);
diff --git a/clang/test/AST/ByteCode/shifts.cpp b/clang/test/AST/ByteCode/shifts.cpp
index 58118bbea79413..119b00bd06931d 100644
--- a/clang/test/AST/ByteCode/shifts.cpp
+++ b/clang/test/AST/ByteCode/shifts.cpp
@@ -57,22 +57,12 @@ namespace shifts {
// cxx17-warning {{shift count >= width of type}} \
// ref-warning {{shift count >= width of type}} \
// ref-cxx17-warning {{shift count >= width of type}}
- c <<= __CHAR_BIT__; // expected-warning {{shift count >= width of type}} \
- // cxx17-warning {{shift count >= width of type}} \
- // ref-warning {{shift count >= width of type}} \
- // ref-cxx17-warning {{shift count >= width of type}}
- c >>= __CHAR_BIT__; // expected-warning {{shift count >= width of type}} \
- // cxx17-warning {{shift count >= width of type}} \
- // ref-warning {{shift count >= width of type}} \
- // ref-cxx17-warning {{shift count >= width of type}}
- c <<= __CHAR_BIT__+1; // expected-warning {{shift count >= width of type}} \
- // cxx17-warning {{shift count >= width of type}} \
- // ref-warning {{shift count >= width of type}} \
- // ref-cxx17-warning {{shift count >= width of type}}
- c >>= __CHAR_BIT__+1; // expected-warning {{shift count >= width of type}} \
- // cxx17-warning {{shift count >= width of type}} \
- // ref-warning {{shift count >= width of type}} \
- // ref-cxx17-warning {{shift count >= width of type}}
+ // These don't warn because the shift count is checked against the promoted
+ // left operand's width. The compound and regular shifts act in the same way.
+ c <<= __CHAR_BIT__;
+ c >>= __CHAR_BIT__;
+ c <<= __CHAR_BIT__+1;
+ c >>= __CHAR_BIT__+1;
(void)((long)c << __CHAR_BIT__);
c = 1 << (int)INT_MIN; // all-warning {{shift count is negative}}
diff --git a/clang/test/Sema/shift.c b/clang/test/Sema/shift.c
index 1ebccb1d0b3acc..abe030ebf5719c 100644
--- a/clang/test/Sema/shift.c
+++ b/clang/test/Sema/shift.c
@@ -32,10 +32,13 @@ void test(void) {
c >>= -1; // expected-warning {{shift count is negative}}
c <<= 999999; // expected-warning {{shift count >= width of type}}
c >>= 999999; // expected-warning {{shift count >= width of type}}
- c <<= CHAR_BIT; // expected-warning {{shift count >= width of type}}
- c >>= CHAR_BIT; // expected-warning {{shift count >= width of type}}
- c <<= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
- c >>= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
+ // These do not warn: the shift count is checked against the promoted left
+ // operand's width, not the LHS's storage width, so the compound forms are
+ // diagnosed just like their non-compound equivalents.
+ c <<= CHAR_BIT;
+ c >>= CHAR_BIT;
+ c <<= CHAR_BIT+1;
+ c >>= CHAR_BIT+1;
(void)((long)c << CHAR_BIT);
int i;
@@ -71,6 +74,41 @@ void test_shift_too_much(char x) {
(void) (x >> 80); // expected-warning {{shift count >= width of type}}
}
+// For compound shift assignments, check the shift count against the width of
+// the promoted LHS, just like regular shift assignments.
+// https://github.com/llvm/llvm-project/issues/234217
+unsigned char char_compound(unsigned char x) {
+ x >>= 8;
+ return x;
+}
+
+unsigned char char_ordinary(unsigned char x) {
+ x = x >> 8;
+ return x;
+}
+
+unsigned short short_compound(unsigned short x) {
+ x >>= 16;
+ return x;
+}
+
+unsigned short short_ordinary(unsigned short x) {
+ x = x >> 16;
+ return x;
+}
+
+unsigned char count_32(unsigned char x) {
+ x >>= 32; // expected-warning {{shift count >= width of type}}
+ x = x >> 32; // expected-warning {{shift count >= width of type}}
+ return x;
+}
+
+unsigned char count_negative(unsigned char x) {
+ x >>= -1; // expected-warning {{shift count is negative}}
+ x = x >> -1; // expected-warning {{shift count is negative}}
+ return x;
+}
+
typedef unsigned vec16 __attribute__((vector_size(16)));
typedef unsigned vec8 __attribute__((vector_size(8)));
diff --git a/clang/test/SemaCXX/shift.cpp b/clang/test/SemaCXX/shift.cpp
index 6367e6d2f250bb..717871e1c42966 100644
--- a/clang/test/SemaCXX/shift.cpp
+++ b/clang/test/SemaCXX/shift.cpp
@@ -33,10 +33,13 @@ void test() {
c >>= -1; // expected-warning {{shift count is negative}}
c <<= 999999; // expected-warning {{shift count >= width of type}}
c >>= 999999; // expected-warning {{shift count >= width of type}}
- c <<= CHAR_BIT; // expected-warning {{shift count >= width of type}}
- c >>= CHAR_BIT; // expected-warning {{shift count >= width of type}}
- c <<= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
- c >>= CHAR_BIT+1; // expected-warning {{shift count >= width of type}}
+ // These do not warn: the shift count is checked against the promoted left
+ // operand's width, not the LHS's storage width, so the compound forms are
+ // diagnosed just like their non-compound equivalents.
+ c <<= CHAR_BIT;
+ c >>= CHAR_BIT;
+ c <<= CHAR_BIT+1;
+ c >>= CHAR_BIT+1;
(void)((long)c << CHAR_BIT);
int i;
@@ -72,6 +75,41 @@ void test_shift_too_much(char x) {
(void) (x >> 80); // expected-warning {{shift count >= width of type}}
}
+// For compound shift assignments, check the shift count against the width of
+// the promoted LHS, just like regular shift assignments.
+// https://github.com/llvm/llvm-project/issues/234217
+unsigned char char_compound(unsigned char x) {
+ x >>= 8;
+ return x;
+}
+
+unsigned char char_ordinary(unsigned char x) {
+ x = x >> 8;
+ return x;
+}
+
+unsigned short short_compound(unsigned short x) {
+ x >>= 16;
+ return x;
+}
+
+unsigned short short_ordinary(unsigned short x) {
+ x = x >> 16;
+ return x;
+}
+
+unsigned char count_32(unsigned char x) {
+ x >>= 32; // expected-warning {{shift count >= width of type}}
+ x = x >> 32; // expected-warning {{shift count >= width of type}}
+ return x;
+}
+
+unsigned char count_negative(unsigned char x) {
+ x >>= -1; // expected-warning {{shift count is negative}}
+ x = x >> -1; // expected-warning {{shift count is negative}}
+ return x;
+}
+
typedef unsigned vec16 __attribute__((vector_size(16)));
typedef unsigned vec8 __attribute__((vector_size(8)));
More information about the cfe-commits
mailing list