[clang] [llvm] [Clang] Fix assertion failure when passing wide string literal to __builtin_nanf (PR #205452)
via cfe-commits
cfe-commits at lists.llvm.org
Thu Jun 25 11:50:16 PDT 2026
https://github.com/divyansh-1009 updated https://github.com/llvm/llvm-project/pull/205452
>From 30ef9df38f27f6511fea3aa378f42e5eccf8f489 Mon Sep 17 00:00:00 2001
From: Divyansh <anshmcs at gmail.com>
Date: Wed, 24 Jun 2026 04:28:01 +0530
Subject: [PATCH 1/4] [Clang] Fix assertion failure when passing wide string
literal to __builtin_nanf
Fixes #205306.
---
clang/lib/AST/ExprConstant.cpp | 2 ++
clang/test/Sema/builtin-nan-wide-string.c | 3 +++
2 files changed, 5 insertions(+)
create mode 100644 clang/test/Sema/builtin-nan-wide-string.c
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 8efceff7e8c31..02afad4096655 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19999,6 +19999,8 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
if (!S) return false;
+ if (!S->isOrdinary() && !S->isUTF8()) return false;
+
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
llvm::APInt fill;
diff --git a/clang/test/Sema/builtin-nan-wide-string.c b/clang/test/Sema/builtin-nan-wide-string.c
new file mode 100644
index 0000000000000..52e1b4a17db94
--- /dev/null
+++ b/clang/test/Sema/builtin-nan-wide-string.c
@@ -0,0 +1,3 @@
+// RUN: %clang_cc1 -fsyntax-only -verify %s
+
+char hello = __builtin_nanf(L""); // expected-error {{incompatible pointer types passing 'int[1]' to parameter of type 'const char *'}}
>From 2c461a63e4fcefb14ebebb416b89212dd5603906 Mon Sep 17 00:00:00 2001
From: Divyansh <anshmcs at gmail.com>
Date: Wed, 24 Jun 2026 21:53:06 +0530
Subject: [PATCH 2/4] update release notes, add comprehensive test coverages,
restrict support to ordinary string literals, add run directives for C and
C++
---
clang/docs/ReleaseNotes.rst | 1 +
clang/lib/AST/ExprConstant.cpp | 2 +-
clang/test/Sema/builtin-nan-wide-string.c | 47 ++++++++++++++++++++++-
clang/test/Sema/constant-builtins-2.c | 4 ++
test_nan_u8.c | 1 +
test_nan_u8.cpp | 1 +
test_nan_wide.c | 1 +
test_nan_wide2.c | 1 +
8 files changed, 55 insertions(+), 3 deletions(-)
create mode 100644 test_nan_u8.c
create mode 100644 test_nan_u8.cpp
create mode 100644 test_nan_wide.c
create mode 100644 test_nan_wide2.c
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 0ff8e8f5afd3c..829f919f892af 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -744,6 +744,7 @@ Bug Fixes to Compiler Builtins
crash when using it with ``-fms-extensions`` on other platforms. (#GH184318)
- Fixed a compiler crash due to an unresolved overloaded function type when
calling ``__builtin_bit_cast``. (#GH200112)
+- Fixed an assertion failure when passing a wide string literal to ``__builtin_nan`` and related builtins. (#GH205306)
Bug Fixes to Attribute Support
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index 02afad4096655..fa34c4ff3a9a2 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19999,7 +19999,7 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
if (!S) return false;
- if (!S->isOrdinary() && !S->isUTF8()) return false;
+ if (!S->isOrdinary()) return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
diff --git a/clang/test/Sema/builtin-nan-wide-string.c b/clang/test/Sema/builtin-nan-wide-string.c
index 52e1b4a17db94..d97af1c7ad898 100644
--- a/clang/test/Sema/builtin-nan-wide-string.c
+++ b/clang/test/Sema/builtin-nan-wide-string.c
@@ -1,3 +1,46 @@
-// RUN: %clang_cc1 -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c -x c %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ %s
+// RUN: %clang_cc1 -fsyntax-only -verify=c -x c -fexperimental-new-constant-interpreter %s
+// RUN: %clang_cc1 -fsyntax-only -verify=cxx -x c++ -fexperimental-new-constant-interpreter %s
-char hello = __builtin_nanf(L""); // expected-error {{incompatible pointer types passing 'int[1]' to parameter of type 'const char *'}}
+#ifdef __cplusplus
+#define CONSTEXPR constexpr
+#else
+#define CONSTEXPR
+#endif
+
+CONSTEXPR float f1 = __builtin_nanf(L"");
+// c-warning at -1 {{incompatible pointer types passing 'int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const wchar_t[1]'}}
+
+CONSTEXPR double d1 = __builtin_nan(L"");
+// c-warning at -1 {{incompatible pointer types passing 'int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const wchar_t[1]'}}
+
+CONSTEXPR long double ld1 = __builtin_nanl(L"");
+// c-warning at -1 {{incompatible pointer types passing 'int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const wchar_t[1]'}}
+
+CONSTEXPR float f2 = __builtin_nanf(u"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned short[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char16_t[1]'}}
+
+CONSTEXPR double d2 = __builtin_nan(u"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned short[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char16_t[1]'}}
+
+CONSTEXPR long double ld2 = __builtin_nanl(u"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned short[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char16_t[1]'}}
+
+CONSTEXPR float f3 = __builtin_nanf(U"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char32_t[1]'}}
+
+CONSTEXPR double d3 = __builtin_nan(U"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char32_t[1]'}}
+
+CONSTEXPR long double ld3 = __builtin_nanl(U"");
+// c-warning at -1 {{incompatible pointer types passing 'unsigned int[1]' to parameter of type 'const char *'}}
+// cxx-error at -2 {{cannot initialize a parameter of type 'const char *' with an lvalue of type 'const char32_t[1]'}}
diff --git a/clang/test/Sema/constant-builtins-2.c b/clang/test/Sema/constant-builtins-2.c
index fd3643bbdb7c8..4890ff0ecc1cc 100644
--- a/clang/test/Sema/constant-builtins-2.c
+++ b/clang/test/Sema/constant-builtins-2.c
@@ -19,6 +19,10 @@ __float128 g5_2 = __builtin_inff128();
double g6 = __builtin_nan("");
float g7 = __builtin_nanf("");
long double g8 = __builtin_nanl("");
+
+double g6_u8 = __builtin_nan(u8"");
+float g7_u8 = __builtin_nanf(u8"");
+long double g8_u8 = __builtin_nanl(u8"");
#if defined(__FLOAT128__) || defined(__SIZEOF_FLOAT128__)
__float128 g8_2 = __builtin_nanf128("");
#endif
diff --git a/test_nan_u8.c b/test_nan_u8.c
new file mode 100644
index 0000000000000..6859499504725
--- /dev/null
+++ b/test_nan_u8.c
@@ -0,0 +1 @@
+float g8 = __builtin_nanf(u8"");
diff --git a/test_nan_u8.cpp b/test_nan_u8.cpp
new file mode 100644
index 0000000000000..1016b5b948ef3
--- /dev/null
+++ b/test_nan_u8.cpp
@@ -0,0 +1 @@
+constexpr float g8 = __builtin_nanf(u8"");
diff --git a/test_nan_wide.c b/test_nan_wide.c
new file mode 100644
index 0000000000000..6c8abecf78d31
--- /dev/null
+++ b/test_nan_wide.c
@@ -0,0 +1 @@
+float g8 = __builtin_nanf(L"");
diff --git a/test_nan_wide2.c b/test_nan_wide2.c
new file mode 100644
index 0000000000000..657ef0ac7ad19
--- /dev/null
+++ b/test_nan_wide2.c
@@ -0,0 +1 @@
+char hello = __builtin_nanf(L"");
>From 8b0428b3c34ed8f95b57f50ab8216164d72b4e1b Mon Sep 17 00:00:00 2001
From: Divyansh <anshmcs at gmail.com>
Date: Thu, 25 Jun 2026 00:02:05 +0530
Subject: [PATCH 3/4] fix: validate that arguments to __builtin_nan functions
are ordinary string literals
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 ++
clang/lib/Sema/SemaChecking.cpp | 23 +++++++++++++++++++
test_cxx17_u8.cpp | 1 +
test_nan_all.c | 5 ++++
test_nan_u8_c.c | 1 +
5 files changed, 32 insertions(+)
create mode 100644 test_cxx17_u8.cpp
create mode 100644 test_nan_all.c
create mode 100644 test_nan_u8_c.c
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index cde99dfb16ec5..062d0c5384dfd 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -171,6 +171,8 @@ def err_ice_too_large : Error<
"integer constant expression evaluates to value %0 that cannot be "
"represented in a %1-bit %select{signed|unsigned}2 integer type">;
def err_expr_not_string_literal : Error<"expression is not a string literal">;
+def err_expected_ordinary_string_literal : Error<
+ "argument to %0 must be an ordinary string literal">;
def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index fa0ec55a63bb7..4343af146b147 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3001,6 +3001,29 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
FPOptions FPO;
switch (BuiltinID) {
+ case Builtin::BI__builtin_nan:
+ case Builtin::BI__builtin_nanf:
+ case Builtin::BI__builtin_nanl:
+ case Builtin::BI__builtin_nanf16:
+ case Builtin::BI__builtin_nanf128:
+ case Builtin::BI__builtin_nans:
+ case Builtin::BI__builtin_nansf:
+ case Builtin::BI__builtin_nansl:
+ case Builtin::BI__builtin_nansf16:
+ case Builtin::BI__builtin_nansf128: {
+ if (TheCall->getNumArgs() > 0) {
+ Expr *Arg = TheCall->getArg(0)->IgnoreParenCasts();
+ if (StringLiteral *S = dyn_cast<StringLiteral>(Arg)) {
+ if (!S->isOrdinary()) {
+ Diag(Arg->getBeginLoc(), diag::err_expected_ordinary_string_literal)
+ << Context.BuiltinInfo.getQuotedName(BuiltinID)
+ << Arg->getSourceRange();
+ return ExprError();
+ }
+ }
+ }
+ break;
+ }
case Builtin::BI__builtin___get_unsafe_stack_start:
case Builtin::BI__builtin___get_unsafe_stack_bottom:
Diag(TheCall->getBeginLoc(), diag::warn_deprecated_builtin)
diff --git a/test_cxx17_u8.cpp b/test_cxx17_u8.cpp
new file mode 100644
index 0000000000000..1016b5b948ef3
--- /dev/null
+++ b/test_cxx17_u8.cpp
@@ -0,0 +1 @@
+constexpr float g8 = __builtin_nanf(u8"");
diff --git a/test_nan_all.c b/test_nan_all.c
new file mode 100644
index 0000000000000..3c9dddda8597a
--- /dev/null
+++ b/test_nan_all.c
@@ -0,0 +1,5 @@
+float f1 = __builtin_nanf(u8"");
+float f2 = __builtin_nanf(L"");
+float f3 = __builtin_nanf(u"");
+float f4 = __builtin_nanf(U"");
+float f5 = __builtin_nanf("");
diff --git a/test_nan_u8_c.c b/test_nan_u8_c.c
new file mode 100644
index 0000000000000..6859499504725
--- /dev/null
+++ b/test_nan_u8_c.c
@@ -0,0 +1 @@
+float g8 = __builtin_nanf(u8"");
>From 40fe99030be11023f800ef1750bd934951eea4b2 Mon Sep 17 00:00:00 2001
From: Divyansh <anshmcs at gmail.com>
Date: Fri, 26 Jun 2026 00:16:14 +0530
Subject: [PATCH 4/4] Revert changes related to disallowing u8 string literals
This focuses the PR exclusively on fixing the failed assertion for wide strings,
keeping the changes for u8 literals for a separate PR. Also updates the new
constant evaluator to properly handle unsigned 8-bit character arrays.
---
.../clang/Basic/DiagnosticSemaKinds.td | 2 --
clang/lib/AST/ByteCode/InterpBuiltin.cpp | 12 ++++++++--
clang/lib/AST/ExprConstant.cpp | 2 +-
clang/lib/Sema/SemaChecking.cpp | 23 -------------------
test_cxx17_u8.cpp | 1 -
test_nan_all.c | 5 ----
test_nan_u8_c.c | 1 -
7 files changed, 11 insertions(+), 35 deletions(-)
delete mode 100644 test_cxx17_u8.cpp
delete mode 100644 test_nan_all.c
delete mode 100644 test_nan_u8_c.c
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 062d0c5384dfd..cde99dfb16ec5 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -171,8 +171,6 @@ def err_ice_too_large : Error<
"integer constant expression evaluates to value %0 that cannot be "
"represented in a %1-bit %select{signed|unsigned}2 integer type">;
def err_expr_not_string_literal : Error<"expression is not a string literal">;
-def err_expected_ordinary_string_literal : Error<
- "argument to %0 must be an ordinary string literal">;
def note_constexpr_assert_failed : Note<
"assertion failed during evaluation of constant expression">;
diff --git a/clang/lib/AST/ByteCode/InterpBuiltin.cpp b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
index e59d14db896a2..bf0be2a817701 100644
--- a/clang/lib/AST/ByteCode/InterpBuiltin.cpp
+++ b/clang/lib/AST/ByteCode/InterpBuiltin.cpp
@@ -441,11 +441,19 @@ static bool interp__builtin_nan(InterpState &S, CodePtr OpPC,
if (!Arg.isElementInitialized(I))
return false;
- if (Arg.elem<int8_t>(I) == 0) {
+ char C;
+ if (Arg.getFieldDesc()->getPrimType() == PT_Sint8)
+ C = Arg.elem<int8_t>(I);
+ else if (Arg.getFieldDesc()->getPrimType() == PT_Uint8)
+ C = Arg.elem<uint8_t>(I);
+ else
+ return false;
+
+ if (C == 0) {
FoundZero = true;
break;
}
- Str += Arg.elem<char>(I);
+ Str += C;
}
// If we didn't find a NUL byte, diagnose as a one-past-the-end read.
diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp
index d6de806722661..5368de32f4316 100644
--- a/clang/lib/AST/ExprConstant.cpp
+++ b/clang/lib/AST/ExprConstant.cpp
@@ -19999,7 +19999,7 @@ static bool TryEvaluateBuiltinNaN(const ASTContext &Context,
const StringLiteral *S = dyn_cast<StringLiteral>(Arg->IgnoreParenCasts());
if (!S) return false;
- if (!S->isOrdinary()) return false;
+ if (!S->isOrdinary() && !S->isUTF8()) return false;
const llvm::fltSemantics &Sem = Context.getFloatTypeSemantics(ResultTy);
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index 4343af146b147..fa0ec55a63bb7 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -3001,29 +3001,6 @@ Sema::CheckBuiltinFunctionCall(FunctionDecl *FDecl, unsigned BuiltinID,
FPOptions FPO;
switch (BuiltinID) {
- case Builtin::BI__builtin_nan:
- case Builtin::BI__builtin_nanf:
- case Builtin::BI__builtin_nanl:
- case Builtin::BI__builtin_nanf16:
- case Builtin::BI__builtin_nanf128:
- case Builtin::BI__builtin_nans:
- case Builtin::BI__builtin_nansf:
- case Builtin::BI__builtin_nansl:
- case Builtin::BI__builtin_nansf16:
- case Builtin::BI__builtin_nansf128: {
- if (TheCall->getNumArgs() > 0) {
- Expr *Arg = TheCall->getArg(0)->IgnoreParenCasts();
- if (StringLiteral *S = dyn_cast<StringLiteral>(Arg)) {
- if (!S->isOrdinary()) {
- Diag(Arg->getBeginLoc(), diag::err_expected_ordinary_string_literal)
- << Context.BuiltinInfo.getQuotedName(BuiltinID)
- << Arg->getSourceRange();
- return ExprError();
- }
- }
- }
- break;
- }
case Builtin::BI__builtin___get_unsafe_stack_start:
case Builtin::BI__builtin___get_unsafe_stack_bottom:
Diag(TheCall->getBeginLoc(), diag::warn_deprecated_builtin)
diff --git a/test_cxx17_u8.cpp b/test_cxx17_u8.cpp
deleted file mode 100644
index 1016b5b948ef3..0000000000000
--- a/test_cxx17_u8.cpp
+++ /dev/null
@@ -1 +0,0 @@
-constexpr float g8 = __builtin_nanf(u8"");
diff --git a/test_nan_all.c b/test_nan_all.c
deleted file mode 100644
index 3c9dddda8597a..0000000000000
--- a/test_nan_all.c
+++ /dev/null
@@ -1,5 +0,0 @@
-float f1 = __builtin_nanf(u8"");
-float f2 = __builtin_nanf(L"");
-float f3 = __builtin_nanf(u"");
-float f4 = __builtin_nanf(U"");
-float f5 = __builtin_nanf("");
diff --git a/test_nan_u8_c.c b/test_nan_u8_c.c
deleted file mode 100644
index 6859499504725..0000000000000
--- a/test_nan_u8_c.c
+++ /dev/null
@@ -1 +0,0 @@
-float g8 = __builtin_nanf(u8"");
More information about the cfe-commits
mailing list