Skip to content

Commit e051073

Browse files
Address review comments
1 parent 96f2f4c commit e051073

File tree

2 files changed

+31
-6
lines changed

2 files changed

+31
-6
lines changed

libcxx/include/__format/format_arg_store.h

Lines changed: 29 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
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

3334
namespace __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
105112
template <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>)
108114
consteval __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
113126
template <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)

libcxx/test/std/utilities/format/format.functions/format_tests.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3190,6 +3190,8 @@ void format_tests(TestFunction check, ExceptionTest check_exception) {
31903190
check(SV("hello 09azAZ!"), SV("hello {}"), data);
31913191
}
31923192
{
3193+
// https://github.com/llvm/llvm-project/issues/115935
3194+
// Contents after the embedded null character are discarded.
31933195
CharT buffer[] = {CharT('a'), CharT('b'), CharT('c'), 0, CharT('d'), CharT('e'), CharT('f'), 0};
31943196
check(SV("hello abc"), SV("hello {}"), buffer);
31953197
}

0 commit comments

Comments
 (0)