[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