[libcxx-commits] [libcxx] [libc++][format] Decay character arrays in formatting (PR #116571)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Nov 18 01:09:54 PST 2024
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/116571
>From 44242836fcfdf071cb3deb26c07a57bf3739715b Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 18 Nov 2024 10:04:33 +0800
Subject: [PATCH] [libc++][format] Decay character arrays in formatting
Currently, built-in `char`/`wchar_t` arrays are assumed to be
null-terminated sequence with the terminator being the last element in
formatting. This doesn't conform to [format.arg]/6.9.
> otherwise, if `decay_t<TD>` is `char_type*` or `const char_type*`,
> initializes value with `static_cast<const char_type*>(v)`;
The standard wording specifies that character arrays are decayed to
pointers. When the null terminator is not the last element or there's no
null terminator (the latter case is UB), libc++ currently produces
different results.
---
libcxx/include/__format/format_arg_store.h | 23 ++++---------------
.../format/format.functions/format_tests.h | 4 ++++
2 files changed, 9 insertions(+), 18 deletions(-)
diff --git a/libcxx/include/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h
index 8b2c95c657c9bd..78b142ebcdb743 100644
--- a/libcxx/include/__format/format_arg_store.h
+++ b/libcxx/include/__format/format_arg_store.h
@@ -101,20 +101,14 @@ consteval __arg_t __determine_arg_t() {
return __arg_t::__long_double;
}
-// Char pointer
+// Char pointer or array
template <class _Context, class _Tp>
- requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)
+ requires(same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>) ||
+ (is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
consteval __arg_t __determine_arg_t() {
return __arg_t::__const_char_type_ptr;
}
-// Char array
-template <class _Context, class _Tp>
- requires(is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
-consteval __arg_t __determine_arg_t() {
- return __arg_t::__string_view;
-}
-
// String view
template <class _Context, class _Tp>
requires(same_as<typename _Context::char_type, typename _Tp::value_type> &&
@@ -188,15 +182,8 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu
else if constexpr (__arg == __arg_t::__unsigned_long_long)
return basic_format_arg<_Context>{__arg, static_cast<unsigned long long>(__value)};
else if constexpr (__arg == __arg_t::__string_view)
- // Using std::size on a character array will add the NUL-terminator to the size.
- if constexpr (is_array_v<_Dp>)
- return basic_format_arg<_Context>{
- __arg, basic_string_view<typename _Context::char_type>{__value, extent_v<_Dp> - 1}};
- else
- // When the _Traits or _Allocator are different an implicit conversion will
- // fail.
- return basic_format_arg<_Context>{
- __arg, basic_string_view<typename _Context::char_type>{__value.data(), __value.size()}};
+ return basic_format_arg<_Context>{
+ __arg, basic_string_view<typename _Context::char_type>{__value.data(), __value.size()}};
else if constexpr (__arg == __arg_t::__ptr)
return basic_format_arg<_Context>{__arg, static_cast<const void*>(__value)};
else if constexpr (__arg == __arg_t::__handle)
diff --git a/libcxx/test/std/utilities/format/format.functions/format_tests.h b/libcxx/test/std/utilities/format/format.functions/format_tests.h
index b2ed6775fe8a13..33212fa663e4a5 100644
--- a/libcxx/test/std/utilities/format/format.functions/format_tests.h
+++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h
@@ -3189,6 +3189,10 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
const CharT* data = buffer;
check(SV("hello 09azAZ!"), SV("hello {}"), data);
}
+ {
+ CharT buffer[] = {CharT('a'), CharT('b'), CharT('c'), 0, CharT('d'), CharT('e'), CharT('f'), 0};
+ check(SV("hello abc"), SV("hello {}"), buffer);
+ }
{
std::basic_string<CharT> data = STR("world");
check(SV("hello world"), SV("hello {}"), data);
More information about the libcxx-commits
mailing list