1717#include < __concepts/arithmetic.h>
1818#include < __concepts/same_as.h>
1919#include < __config>
20+ #include < __cstddef/size_t.h>
2021#include < __format/concepts.h>
2122#include < __format/format_arg.h>
2223#include < __type_traits/conditional.h>
@@ -32,6 +33,12 @@ _LIBCPP_BEGIN_NAMESPACE_STD
3233
3334namespace __format {
3435
36+ template <class _Arr , class _Elem >
37+ inline constexpr bool __is_bounded_array_of = false ;
38+
39+ template <class _Elem , size_t _Len>
40+ inline constexpr bool __is_bounded_array_of<_Elem[_Len], _Elem> = true ;
41+
3542// / \returns The @c __arg_t based on the type of the formatting argument.
3643// /
3744// / \pre \c __formattable<_Tp, typename _Context::char_type>
@@ -101,14 +108,20 @@ consteval __arg_t __determine_arg_t() {
101108 return __arg_t ::__long_double;
102109}
103110
104- // Char pointer or array
111+ // Char pointer
105112template <class _Context , class _Tp >
106- requires (same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>) ||
107- (is_array_v<_Tp> && same_as<_Tp, typename _Context::char_type[extent_v<_Tp>]>)
113+ requires (same_as<typename _Context::char_type*, _Tp> || same_as<const typename _Context::char_type*, _Tp>)
108114consteval __arg_t __determine_arg_t () {
109115 return __arg_t ::__const_char_type_ptr;
110116}
111117
118+ // Char array
119+ template <class _Context , class _Tp >
120+ requires __is_bounded_array_of<_Tp, typename _Context::char_type>
121+ consteval __arg_t __determine_arg_t () {
122+ return __arg_t ::__string_view;
123+ }
124+
112125// String view
113126template <class _Context , class _Tp >
114127 requires (same_as<typename _Context::char_type, typename _Tp::value_type> &&
@@ -162,13 +175,14 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu
162175 static_assert (__arg != __arg_t ::__none, " the supplied type is not formattable" );
163176 static_assert (__formattable_with<_Tp, _Context>);
164177
178+ using __context_char_type = _Context::char_type;
165179 // Not all types can be used to directly initialize the
166180 // __basic_format_arg_value. First handle all types needing adjustment, the
167181 // final else requires no adjustment.
168182 if constexpr (__arg == __arg_t ::__char_type)
169183
170184# if _LIBCPP_HAS_WIDE_CHARACTERS
171- if constexpr (same_as<typename _Context::char_type , wchar_t > && same_as<_Dp, char >)
185+ if constexpr (same_as<__context_char_type , wchar_t > && same_as<_Dp, char >)
172186 return basic_format_arg<_Context>{__arg, static_cast <wchar_t >(static_cast <unsigned char >(__value))};
173187 else
174188# endif
@@ -182,8 +196,17 @@ _LIBCPP_HIDE_FROM_ABI basic_format_arg<_Context> __create_format_arg(_Tp& __valu
182196 else if constexpr (__arg == __arg_t ::__unsigned_long_long)
183197 return basic_format_arg<_Context>{__arg, static_cast <unsigned long long >(__value)};
184198 else if constexpr (__arg == __arg_t ::__string_view)
185- return basic_format_arg<_Context>{
186- __arg, basic_string_view<typename _Context::char_type>{__value.data (), __value.size ()}};
199+ // Using std::size on a character array will add the NUL-terminator to the size.
200+ if constexpr (__is_bounded_array_of<_Dp, __context_char_type>) {
201+ if (const auto __pzero = char_traits<__context_char_type>::find (__value, extent_v<_Dp>, __context_char_type{}))
202+ return basic_format_arg<_Context>{
203+ __arg, basic_string_view<__context_char_type>{__value, static_cast <size_t >(__pzero - __value)}};
204+ else
205+ // The behavior is undefined in this case.
206+ return basic_format_arg<_Context>{__arg, basic_string_view<__context_char_type>{__value, extent_v<_Dp>}};
207+ } else
208+ // When the _Traits or _Allocator are different an implicit conversion will fail.
209+ return basic_format_arg<_Context>{__arg, basic_string_view<__context_char_type>{__value.data (), __value.size ()}};
187210 else if constexpr (__arg == __arg_t ::__ptr)
188211 return basic_format_arg<_Context>{__arg, static_cast <const void *>(__value)};
189212 else if constexpr (__arg == __arg_t ::__handle)
0 commit comments