[clang] [Clang] Fix assertion "unsigned range includes negative?" in AnalyzeComparison during Sema of vector comparison with mismatched signed/unsigned types and __builtin_convertvector (PR #182627)
Yutong Zhu via cfe-commits
cfe-commits at lists.llvm.org
Tue Apr 28 17:04:22 PDT 2026
https://github.com/YutongZhuu updated https://github.com/llvm/llvm-project/pull/182627
>From 9a862f048bcb456aed54118d0b6a80753c1a3f92 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Fri, 20 Feb 2026 18:31:40 -0500
Subject: [PATCH 1/7] Change ``TryGetExprRange`` such that unsigned vectors get
non negative ranges
---
clang/lib/Sema/SemaChecking.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index ba4b25961d70d..052828107a867 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11500,6 +11500,15 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
Approximate);
}
+ QualType T = E->getType();
+ if (const auto *VT = T->getAs<VectorType>()) {
+ QualType ElemTy = VT->getElementType();
+ if (ElemTy->isUnsignedIntegerType()) {
+ return TryGetExprRange(C, UO->getSubExpr(), MaxWidth,
+ InConstantContext, Approximate);
+ }
+ }
+
std::optional<IntRange> SubRange = TryGetExprRange(
C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
@@ -11518,6 +11527,15 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
Approximate);
}
+ QualType T = E->getType();
+
+ if (const auto *VT = T->getAs<VectorType>()) {
+ QualType ElemTy = VT->getElementType();
+ if (ElemTy->isUnsignedIntegerType()) {
+ return TryGetExprRange(C, UO->getSubExpr(), MaxWidth,
+ InConstantContext, Approximate);
+ }
+ }
std::optional<IntRange> SubRange = TryGetExprRange(
C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
>From 667aa51d47895a223972b672971400b2a8d550a0 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Fri, 20 Feb 2026 19:02:27 -0500
Subject: [PATCH 2/7] Add tests and edit release notes
---
clang/docs/ReleaseNotes.rst | 2 ++
clang/test/Sema/compare.cpp | 14 ++++++++++++++
2 files changed, 16 insertions(+)
create mode 100644 clang/test/Sema/compare.cpp
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 77e2078a5ffbf..18c3667894172 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -498,6 +498,8 @@ Improvements to Clang's diagnostics
- Clang now generates a fix-it for C++20 designated initializers when the
initializers do not match the declaration order in the structure.
+- Clang now doesn't throw assertion errors when comparing unsigned vectors(#173614)
+
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/test/Sema/compare.cpp b/clang/test/Sema/compare.cpp
new file mode 100644
index 0000000000000..fb5d82847e2a0
--- /dev/null
+++ b/clang/test/Sema/compare.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -fsyntax-only
+// Expect no assertion failures in this file (#173614).
+typedef unsigned long __attribute__((__vector_size__(8))) W;
+
+int i;
+W g;
+
+void negation(void) {
+ W w = i == (-g);
+}
+
+void bitwiseNot(void) {
+ W w = i == (~g);
+}
>From c1ef4e51f751885035449ac399ad33ed838697be Mon Sep 17 00:00:00 2001
From: Yutong Zhu <115899167+YutongZhuu at users.noreply.github.com>
Date: Mon, 23 Feb 2026 15:57:47 -0500
Subject: [PATCH 3/7] Update clang/docs/ReleaseNotes.rst
Co-authored-by: Mariya Podchishchaeva <mariya.podchishchaeva at intel.com>
---
clang/docs/ReleaseNotes.rst | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 18c3667894172..74a75c1cd2fdf 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -498,7 +498,7 @@ Improvements to Clang's diagnostics
- Clang now generates a fix-it for C++20 designated initializers when the
initializers do not match the declaration order in the structure.
-- Clang now doesn't throw assertion errors when comparing unsigned vectors(#173614)
+- Clang now doesn't throw assertion errors when comparing unsigned vectors (#GH173614).
Improvements to Clang's time-trace
----------------------------------
>From 02f299633be2c056b28c53a59a33ecac5d22d4e6 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Mon, 23 Feb 2026 17:11:55 -0500
Subject: [PATCH 4/7] Merge compare.cpp into compare.c
---
clang/test/Sema/compare.c | 15 +++++++++++++++
clang/test/Sema/compare.cpp | 14 --------------
2 files changed, 15 insertions(+), 14 deletions(-)
delete mode 100644 clang/test/Sema/compare.cpp
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index fdae3bc19841e..1dc9d0d878929 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -481,3 +481,18 @@ int test26(short n) {
return ~n == 32768; // expected-warning {{result of comparison of 16-bit signed value == 32768 is always false}}
}
#endif
+
+typedef unsigned long __attribute__((__vector_size__(8))) W;
+void test27(void) {
+ int i;
+ W g;
+ // We expect no assertion failures here.
+ W w = i == (-g); // expected-warning {{}}
+}
+
+void test28(void) {
+ int i;
+ W g;
+ // We expect no assertion failures here.
+ W w = i == (~g); // expected-warning {{}}
+}
diff --git a/clang/test/Sema/compare.cpp b/clang/test/Sema/compare.cpp
deleted file mode 100644
index fb5d82847e2a0..0000000000000
--- a/clang/test/Sema/compare.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-// RUN: %clang_cc1 -fsyntax-only
-// Expect no assertion failures in this file (#173614).
-typedef unsigned long __attribute__((__vector_size__(8))) W;
-
-int i;
-W g;
-
-void negation(void) {
- W w = i == (-g);
-}
-
-void bitwiseNot(void) {
- W w = i == (~g);
-}
>From dcbfd859c42e8e174a42414277655048347549de Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Mon, 2 Mar 2026 13:50:06 -0500
Subject: [PATCH 5/7] Deduplicate the type checking logic and tests
---
clang/lib/Sema/SemaChecking.cpp | 28 ++++++++--------------------
clang/test/Sema/compare.c | 10 ++--------
2 files changed, 10 insertions(+), 28 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 052828107a867..d8c8884547f21 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11223,6 +11223,12 @@ static QualType GetExprType(const Expr *E) {
return Ty;
}
+static bool isUnsignedScalarType(QualType T) {
+ if (const auto *VT = T->getAs<VectorType>())
+ T = VT->getElementType();
+ return T->isUnsignedIntegerType();
+}
+
/// Attempts to estimate an approximate range for the given integer expression.
/// Returns a range if successful, otherwise it returns \c std::nullopt if a
/// reliable estimation cannot be determined.
@@ -11495,20 +11501,11 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
return IntRange::forValueOfType(C, GetExprType(E));
case UO_Minus: {
- if (E->getType()->isUnsignedIntegerType()) {
+ if (isUnsignedScalarType(E->getType())) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
- QualType T = E->getType();
- if (const auto *VT = T->getAs<VectorType>()) {
- QualType ElemTy = VT->getElementType();
- if (ElemTy->isUnsignedIntegerType()) {
- return TryGetExprRange(C, UO->getSubExpr(), MaxWidth,
- InConstantContext, Approximate);
- }
- }
-
std::optional<IntRange> SubRange = TryGetExprRange(
C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
@@ -11522,20 +11519,11 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
}
case UO_Not: {
- if (E->getType()->isUnsignedIntegerType()) {
+ if (isUnsignedScalarType(E->getType())) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
- QualType T = E->getType();
-
- if (const auto *VT = T->getAs<VectorType>()) {
- QualType ElemTy = VT->getElementType();
- if (ElemTy->isUnsignedIntegerType()) {
- return TryGetExprRange(C, UO->getSubExpr(), MaxWidth,
- InConstantContext, Approximate);
- }
- }
std::optional<IntRange> SubRange = TryGetExprRange(
C, UO->getSubExpr(), MaxWidth, InConstantContext, Approximate);
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index 1dc9d0d878929..e9e4f17f825ef 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -487,12 +487,6 @@ void test27(void) {
int i;
W g;
// We expect no assertion failures here.
- W w = i == (-g); // expected-warning {{}}
-}
-
-void test28(void) {
- int i;
- W g;
- // We expect no assertion failures here.
- W w = i == (~g); // expected-warning {{}}
+ W w1 = i == (-g); // expected-warning {{}}
+ W w2 = i == (~g); // expected-warning {{}}
}
>From b98756801f7e5b3f65bfac09772cebf07077afa6 Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Mon, 2 Mar 2026 14:49:56 -0500
Subject: [PATCH 6/7] Change function name to be clearer
---
clang/lib/Sema/SemaChecking.cpp | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index d8c8884547f21..58a0c30fd6825 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11223,7 +11223,7 @@ static QualType GetExprType(const Expr *E) {
return Ty;
}
-static bool isUnsignedScalarType(QualType T) {
+static bool isUnsignedIntegerOrVectorElementType(QualType T) {
if (const auto *VT = T->getAs<VectorType>())
T = VT->getElementType();
return T->isUnsignedIntegerType();
@@ -11501,7 +11501,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
return IntRange::forValueOfType(C, GetExprType(E));
case UO_Minus: {
- if (isUnsignedScalarType(E->getType())) {
+ if (isUnsignedIntegerOrVectorElementType(E->getType())) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
@@ -11519,7 +11519,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
}
case UO_Not: {
- if (isUnsignedScalarType(E->getType())) {
+ if (isUnsignedIntegerOrVectorElementType(E->getType())) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
>From fb2aacbaf8b74cf01212efd24f719ec7186a4d0c Mon Sep 17 00:00:00 2001
From: Yutong Zhu <y25zhu at uwaterloo.ca>
Date: Tue, 28 Apr 2026 20:03:42 -0400
Subject: [PATCH 7/7] Address comments 1. Refactor the type check helper
function into Type.cpp 2. Edit release notes
---
clang/docs/ReleaseNotes.rst | 2 +-
clang/include/clang/AST/TypeBase.h | 6 +++++-
clang/lib/AST/Type.cpp | 6 ++++++
clang/lib/Sema/SemaChecking.cpp | 10 ++--------
clang/test/Sema/compare.c | 31 +++++++++++++++++++++++++++---
5 files changed, 42 insertions(+), 13 deletions(-)
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 74a75c1cd2fdf..e06f466c86965 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -498,7 +498,7 @@ Improvements to Clang's diagnostics
- Clang now generates a fix-it for C++20 designated initializers when the
initializers do not match the declaration order in the structure.
-- Clang now doesn't throw assertion errors when comparing unsigned vectors (#GH173614).
+- Clang now doesn't throw assertion errors when comparing unsigned vector types (#GH173614).
Improvements to Clang's time-trace
----------------------------------
diff --git a/clang/include/clang/AST/TypeBase.h b/clang/include/clang/AST/TypeBase.h
index b0fdf178ab3cc..ecf189f5f2ad0 100644
--- a/clang/include/clang/AST/TypeBase.h
+++ b/clang/include/clang/AST/TypeBase.h
@@ -3020,10 +3020,14 @@ class alignas(TypeAlignment) Type : public ExtQualsTypeCommonBase {
/// enumeration types whose underlying type is a signed integer type.
bool isSignedIntegerOrEnumerationType() const;
- /// Determines whether this is an integer type that is unsigned or an
+ /// Return true if this is an integer type that is unsigned or an
/// enumeration types whose underlying type is a unsigned integer type.
bool isUnsignedIntegerOrEnumerationType() const;
+ // Determine whether this is an unsigned integer type or an unsigned integer
+ // vector type.
+ bool isUnsignedIntegerOrVectorType() const;
+
/// Return true if this is a fixed point type according to
/// ISO/IEC JTC1 SC22 WG14 N1169.
bool isFixedPointType() const;
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 53082bcf78f6a..0ba359c30395b 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -2289,6 +2289,12 @@ bool Type::isUnsignedIntegerOrEnumerationType() const {
return false;
}
+bool Type::isUnsignedIntegerOrVectorType() const {
+ if (const auto *VT = getAs<VectorType>())
+ return VT->getElementType()->isUnsignedIntegerType();
+ return isUnsignedIntegerType();
+}
+
bool Type::hasUnsignedIntegerRepresentation() const {
if (const auto *VT = dyn_cast<VectorType>(CanonicalType))
return VT->getElementType()->isUnsignedIntegerOrEnumerationType();
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 58a0c30fd6825..040d8aa67a7d4 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -11223,12 +11223,6 @@ static QualType GetExprType(const Expr *E) {
return Ty;
}
-static bool isUnsignedIntegerOrVectorElementType(QualType T) {
- if (const auto *VT = T->getAs<VectorType>())
- T = VT->getElementType();
- return T->isUnsignedIntegerType();
-}
-
/// Attempts to estimate an approximate range for the given integer expression.
/// Returns a range if successful, otherwise it returns \c std::nullopt if a
/// reliable estimation cannot be determined.
@@ -11501,7 +11495,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
return IntRange::forValueOfType(C, GetExprType(E));
case UO_Minus: {
- if (isUnsignedIntegerOrVectorElementType(E->getType())) {
+ if (E->getType()->isUnsignedIntegerOrVectorType()) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
@@ -11519,7 +11513,7 @@ static std::optional<IntRange> TryGetExprRange(ASTContext &C, const Expr *E,
}
case UO_Not: {
- if (isUnsignedIntegerOrVectorElementType(E->getType())) {
+ if (E->getType()->isUnsignedIntegerOrVectorType()) {
return TryGetExprRange(C, UO->getSubExpr(), MaxWidth, InConstantContext,
Approximate);
}
diff --git a/clang/test/Sema/compare.c b/clang/test/Sema/compare.c
index e9e4f17f825ef..953237d3c7419 100644
--- a/clang/test/Sema/compare.c
+++ b/clang/test/Sema/compare.c
@@ -483,10 +483,35 @@ int test26(short n) {
#endif
typedef unsigned long __attribute__((__vector_size__(8))) W;
+
void test27(void) {
int i;
W g;
- // We expect no assertion failures here.
- W w1 = i == (-g); // expected-warning {{}}
- W w2 = i == (~g); // expected-warning {{}}
+
+ W w1 = i == (-g);
+ // expected-warning at -1 {{}}
+
+ W w3 = i == (+g);
+ // expected-warning at -1 {{}}
+
+ W w2 = i == (~g);
+ // expected-warning at -1 {{}}
+
+ W w4 = i == (!g);
+ // expected-error at -1 {{}}
+
+ W w5 = i == (++g);
+ // expected-error at -1 {{}}
+
+ W w6 = i == (g++);
+ // expected-error at -1 {{}}
+
+ W w7 = i == (--g);
+ // expected-error at -1 {{}}
+
+ W w8 = i == (g--);
+ // expected-error at -1 {{}}
+
+ W w9 = i == (*g);
+ // expected-error at -1 {{}}
}
More information about the cfe-commits
mailing list