[clang] [clang] Fix constant evaluation of strchr (PR #230869)
Vedant Singhal via cfe-commits
cfe-commits at lists.llvm.org
Wed Oct 21 13:59:19 PDT 2026
https://github.com/Ved235 updated https://github.com/llvm/llvm-project/pull/230869
>From 3ae1762f92c0dba16b54c337fe8341084858c34d Mon Sep 17 00:00:00 2001
From: Vedant <vedantsinghal07 at gmail.com>
Date: Sat, 10 Oct 2026 23:29:16 +0100
Subject: [PATCH] Fix type conversion in constant evaluation of strchr
---
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 16 ----------------
clang/lib/AST/ExprConstant.cpp | 7 -------
clang/test/AST/ByteCode/builtin-functions.cpp | 12 ++++++++----
clang/test/SemaCXX/constexpr-string.cpp | 12 ++++++++----
4 files changed, 16 insertions(+), 31 deletions(-)
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index 4a5c691d390a71..53d543928efa3e 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -2378,22 +2378,6 @@ static bool interp__builtin_memchr(InterpState &S, CodePtr OpPC,
if (!isReadable(Ptr))
return false;
- if (ID == Builtin::BIstrchr || ID == Builtin::BI__builtin_strchr) {
- int64_t DesiredTrunc;
- if (S.getASTContext().CharTy->isSignedIntegerType())
- DesiredTrunc =
- Desired.trunc(S.getASTContext().getCharWidth()).getSExtValue();
- else
- DesiredTrunc =
- Desired.trunc(S.getASTContext().getCharWidth()).getZExtValue();
- // strchr compares directly to the passed integer, and therefore
- // always fails if given an int that is not a char.
- if (Desired != DesiredTrunc) {
- S.Stk.push<Pointer>();
- return true;
- }
- }
-
uint64_t DesiredVal;
if (ID == Builtin::BIwmemchr || ID == Builtin::BI__builtin_wmemchr ||
ID == Builtin::BIwcschr || ID == Builtin::BI__builtin_wcschr) {
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8551f4c9ae279a..f5b562a4eab677 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -10877,13 +10877,6 @@ bool PointerExprEvaluator::VisitBuiltinCallExpr(const CallExpr *E,
switch (BuiltinOp) {
case Builtin::BIstrchr:
case Builtin::BI__builtin_strchr:
- // strchr compares directly to the passed integer, and therefore
- // always fails if given an int that is not a char.
- if (!APSInt::isSameValue(HandleIntToIntCast(Info, E, CharTy,
- E->getArg(1)->getType(),
- Desired),
- Desired))
- return ZeroInitialization(E);
StopAtNull = true;
[[fallthrough]];
case Builtin::BImemchr:
diff --git a/clang/test/AST/ByteCode/builtin-functions.cpp b/clang/test/AST/ByteCode/builtin-functions.cpp
index 211c3e98d161c4..ae07bae2779629 100644
--- a/clang/test/AST/ByteCode/builtin-functions.cpp
+++ b/clang/test/AST/ByteCode/builtin-functions.cpp
@@ -1825,11 +1825,15 @@ namespace Strchr {
static_assert(__builtin_strchr(kStr, 'd') == nullptr);
static_assert(__builtin_strchr(kStr, 'e') == nullptr);
static_assert(__builtin_strchr(kStr, '\0') == kStr + 5);
- static_assert(__builtin_strchr(kStr, 'a' + 256) == nullptr);
- static_assert(__builtin_strchr(kStr, 'a' - 256) == nullptr);
+ static_assert(__builtin_strchr(kStr, 256) == kStr + 5);
+ static_assert(__builtin_strchr(kStr, -256) == kStr + 5);
+ static_assert(__builtin_strchr(kStr, 'a' + 256) == kStr);
+ static_assert(__builtin_strchr(kStr, 'a' - 256) == kStr);
static_assert(__builtin_strchr(kStr, '\xff') == kStr + 4);
- static_assert(__builtin_strchr(kStr, '\xff' + 256) == nullptr);
- static_assert(__builtin_strchr(kStr, '\xff' - 256) == nullptr);
+ static_assert(__builtin_strchr(kStr, '\xff' + 256) == kStr + 4);
+ static_assert(__builtin_strchr(kStr, '\xff' - 256) == kStr + 4);
+ constexpr char kStr2[] = "\x80\x41";
+ static_assert(__builtin_strchr(kStr2, 128) == kStr2);
static_assert(__builtin_strchr(kFoo, 'o') == kFoo + 1);
static_assert(__builtin_strchr(kFoo, 'x') == nullptr); // both-error {{not an integral constant}} \
// both-note {{dereferenced one-past-the-end}}
diff --git a/clang/test/SemaCXX/constexpr-string.cpp b/clang/test/SemaCXX/constexpr-string.cpp
index b49979bbc8ca0e..b55118ffc9e2a5 100644
--- a/clang/test/SemaCXX/constexpr-string.cpp
+++ b/clang/test/SemaCXX/constexpr-string.cpp
@@ -369,11 +369,15 @@ namespace StrchrEtc {
static_assert(__builtin_strchr(kStr, 'd') == nullptr);
static_assert(__builtin_strchr(kStr, 'e') == nullptr);
static_assert(__builtin_strchr(kStr, '\0') == kStr + 5);
- static_assert(__builtin_strchr(kStr, 'a' + 256) == nullptr);
- static_assert(__builtin_strchr(kStr, 'a' - 256) == nullptr);
+ static_assert(__builtin_strchr(kStr, 256) == kStr + 5);
+ static_assert(__builtin_strchr(kStr, -256) == kStr + 5);
+ static_assert(__builtin_strchr(kStr, 'a' + 256) == kStr);
+ static_assert(__builtin_strchr(kStr, 'a' - 256) == kStr);
static_assert(__builtin_strchr(kStr, '\xff') == kStr + 4);
- static_assert(__builtin_strchr(kStr, '\xff' + 256) == nullptr);
- static_assert(__builtin_strchr(kStr, '\xff' - 256) == nullptr);
+ static_assert(__builtin_strchr(kStr, '\xff' + 256) == kStr + 4);
+ static_assert(__builtin_strchr(kStr, '\xff' - 256) == kStr + 4);
+ constexpr char kStr2[] = "\x80\x41";
+ static_assert(__builtin_strchr(kStr2, 128) == kStr2);
static_assert(__builtin_strchr(kFoo, 'o') == kFoo + 1);
static_assert(__builtin_strchr(kFoo, 'x') == nullptr); // expected-error {{not an integral constant}} expected-note {{dereferenced one-past-the-end}}
static_assert(__builtin_strchr(nullptr, 'x') == nullptr); // expected-error {{not an integral constant}} expected-note {{dereferenced null}}
More information about the cfe-commits
mailing list