[clang] [Clang] Fix `-Wsign-compare` assertion when negating a vector of unsigned integers (PR #223295)
via cfe-commits
cfe-commits at lists.llvm.org
Sun Sep 13 21:47:59 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Akash Manna (akash-manna-sky)
<details>
<summary>Changes</summary>
Fixes #<!-- -->203575
`-1 == -*c`, where `c` points to a vector of `unsigned`, hit the `unsigned range includes negative?` assertion in `AnalyzeComparison`. The range analysis for unary `-` and `~` (added in #<!-- -->126846) checks whether the result type is unsigned with `isUnsignedIntegerType()`, which never looks through vector types. So the negated unsigned vector was treated as a signed negation and came back with a possibly-negative range, even though the operand's own range was correctly unsigned. Same story for `~*c`.
The check now uses `hasUnsignedIntegerRepresentation()`, which looks through vector and matrix element types the same way `IntRange::forValueOfType` and the caller in `AnalyzeComparison` already do. The binary-operator result gets the same predicate for its non-negative fixup, since it had the identical blind spot. With that, a negated unsigned vector takes the same path as a negated `unsigned` scalar, and the comparison warns about mixed signs again as it did before Clang 21.
---
Full diff: https://github.com/llvm/llvm-project/pull/223295.diff
3 Files Affected:
- (modified) clang/docs/ReleaseNotes.md (+1)
- (modified) clang/lib/Sema/SemaChecking.cpp (+3-3)
- (modified) clang/test/Sema/compare.c (+19)
``````````diff
diff --git a/clang/docs/ReleaseNotes.md b/clang/docs/ReleaseNotes.md
index 3cca316a91d4d..e9d681eb89a00 100644
--- a/clang/docs/ReleaseNotes.md
+++ b/clang/docs/ReleaseNotes.md
@@ -521,6 +521,7 @@ features cannot lower the translation-unit ABI level;
- Fixed an assertion when `#pragma omp declare simd` or `#pragma omp declare variant` is followed by another OpenMP declarative directive containing a qualified identifier. (#GH217204)
- Fixed a crash when an `asm` label names the register for a global variable of incomplete type. (#GH219746)
- Fixed an ICE hat occurred when using `__imag int/float` as lvalue in assignment. (#GH119498)
+- Fixed an assertion failure in `-Wsign-compare` when a negated or complemented vector of unsigned integers was compared against a signed constant. (#GH203575)
#### Bug Fixes to Compiler Builtins
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 7374ce7404cbd..3b5523bf34d9b 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -12207,7 +12207,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
return std::nullopt;
IntRange C = Combine(*L, *R);
- C.NonNegative |= T->isUnsignedIntegerOrEnumerationType();
+ C.NonNegative |= T->hasUnsignedIntegerRepresentation();
C.Width = std::min(C.Width, MaxWidth);
return C;
}
@@ -12224,7 +12224,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
return IntRange::forValueOfType(C, GetExprType(E));
case UO_Minus: {
- if (E->getType()->isUnsignedIntegerType()) {
+ if (GetExprType(E)->hasUnsignedIntegerRepresentation()) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
@@ -12242,7 +12242,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
}
case UO_Not: {
- if (E->getType()->isUnsignedIntegerType()) {
+ if (GetExprType(E)->hasUnsignedIntegerRepresentation()) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index fdae3bc19841e..028d7bcfb3536 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -481,3 +481,22 @@ int test26(short n) {
return ~n == 32768; // expected-warning {{result of comparison of 16-bit signed value == 32768 is always false}}
}
#endif
+
+// GH203575
+typedef unsigned gh203575_uvec __attribute__((__vector_size__(sizeof 2)));
+
+int gh203575_1(gh203575_uvec *c) {
+ return -1 == -*c; // expected-warning {{comparison of integers of different signs: 'int' and 'gh203575_uvec' (vector of 1 'unsigned int' value)}}
+}
+
+int gh203575_2(gh203575_uvec *c) {
+ return - 8 == -*c; // expected-warning {{comparison of integers of different signs: 'int' and 'gh203575_uvec' (vector of 1 'unsigned int' value)}}
+}
+
+int gh203575_3(gh203575_uvec *c) {
+ return -1 == ~*c; // expected-warning {{comparison of integers of different signs: 'int' and 'gh203575_uvec' (vector of 1 'unsigned int' value)}}
+}
+
+int gh203575_4(gh203575_uvec a, gh203575_uvec b) {
+ return a == -b; // no-warning
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/223295
More information about the cfe-commits
mailing list