https://github.com/akash-manna-sky created 
https://github.com/llvm/llvm-project/pull/223295

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.

>From d0137837a04bbc95249d50bd2a8e8ac1ccf36859 Mon Sep 17 00:00:00 2001
From: Akash Manna <[email protected]>
Date: Mon, 14 Sep 2026 09:02:55 +0530
Subject: [PATCH] [Clang] Fix -Wsign-compare assertion when negating a vector
 of unsigned integers

TryGetExprRange decided whether unary - and ~ keep an unsigned range by
calling isUnsignedIntegerType(), which is false for vector types. A
negated vector of unsigned therefore took the signed-negation path and
came back as a possibly-negative range, tripping the "unsigned range
includes negative?" assertion in AnalyzeComparison. Use
hasUnsignedIntegerRepresentation(), which looks through vector and
matrix element types like the rest of the range analysis does, and
apply the same predicate to the binary-operator result. This restores
the pre-Clang-21 behaviour of warning about the mixed-sign comparison.

Fixes #203575
---
 clang/docs/ReleaseNotes.md      |  1 +
 clang/lib/Sema/SemaChecking.cpp |  6 +++---
 clang/test/Sema/compare.c       | 19 +++++++++++++++++++
 3 files changed, 23 insertions(+), 3 deletions(-)

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
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to