diff --git a/libcxx/include/__format/format_arg_store.h b/libcxx/include/__format/format_arg_store.h --- a/libcxx/include/__format/format_arg_store.h +++ b/libcxx/include/__format/format_arg_store.h @@ -17,8 +17,6 @@ #include <__config> #include <__format/concepts.h> #include <__format/format_arg.h> -#include <__iterator/data.h> -#include <__iterator/size.h> #include #include #include @@ -173,13 +171,15 @@ else if constexpr (__arg == __arg_t::__unsigned_long_long) return basic_format_arg<_Context>{__arg, static_cast(__value)}; else if constexpr (__arg == __arg_t::__string_view) - // When the _Traits or _Allocator are different an implicit conversion will - // fail. - // - // Note since the input can be an array use the non-member functions to - // extract the constructor arguments. - return basic_format_arg<_Context>{ - __arg, basic_string_view{_VSTD::data(__value), _VSTD::size(__value)}}; + // Using std::size on a character array will add the NUL-terminator to the size. + if constexpr (is_array_v>) + return basic_format_arg<_Context>{ + __arg, basic_string_view{__value, extent_v> - 1}}; + else + // When the _Traits or _Allocator are different an implicit conversion will + // fail. + return basic_format_arg<_Context>{ + __arg, basic_string_view{__value.data(), __value.size()}}; else if constexpr (__arg == __arg_t::__ptr) return basic_format_arg<_Context>{__arg, static_cast(__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 --- a/libcxx/test/std/utilities/format/format.functions/format_tests.h +++ b/libcxx/test/std/utilities/format/format.functions/format_tests.h @@ -174,8 +174,10 @@ return result; } -template -void format_test_string(T world, T universe, TestFunction check, ExceptionTest check_exception) { +// Using a const ref for world and universe so a string literal will be a character array. +// When passed as character array W and U have different types. +template +void format_test_string(const W& world, const U& universe, TestFunction check, ExceptionTest check_exception) { // *** Valid input tests *** // Unsed argument is ignored. TODO FMT what does the Standard mandate? @@ -291,6 +293,44 @@ void format_test_string_unicode(TestFunction check) { (void)check; #ifndef TEST_HAS_NO_UNICODE + // Make sure all possible types are tested. For clarity don't use macros. + if constexpr (std::same_as) { + const char* c_string = "aßc"; + check.template operator()<"{:*^5}">(SV("*aßc*"), c_string); + check.template operator()<"{:*^4.2}">(SV("*aß*"), c_string); + + check.template operator()<"{:*^5}">(SV("*aßc*"), const_cast(c_string)); + check.template operator()<"{:*^4.2}">(SV("*aß*"), const_cast(c_string)); + + check.template operator()<"{:*^5}">(SV("*aßc*"), "aßc"); + check.template operator()<"{:*^4.2}">(SV("*aß*"), "aßc"); + + check.template operator()<"{:*^5}">(SV("*aßc*"), std::string("aßc")); + check.template operator()<"{:*^4.2}">(SV("*aß*"), std::string("aßc")); + + check.template operator()<"{:*^5}">(SV("*aßc*"), std::string_view("aßc")); + check.template operator()<"{:*^4.2}">(SV("*aß*"), std::string_view("aßc")); + } +# ifndef TEST_HAS_NO_WIDE_CHARACTERS + else { + const wchar_t* c_string = L"aßc"; + check.template operator()<"{:*^5}">(SV("*aßc*"), c_string); + check.template operator()<"{:*^4.2}">(SV("*aß*"), c_string); + + check.template operator()<"{:*^5}">(SV("*aßc*"), const_cast(c_string)); + check.template operator()<"{:*^4.2}">(SV("*aß*"), const_cast(c_string)); + + check.template operator()<"{:*^5}">(SV("*aßc*"), L"aßc"); + check.template operator()<"{:*^4.2}">(SV("*aß*"), L"aßc"); + + check.template operator()<"{:*^5}">(SV("*aßc*"), std::wstring(L"aßc")); + check.template operator()<"{:*^4.2}">(SV("*aß*"), std::wstring(L"aßc")); + + check.template operator()<"{:*^5}">(SV("*aßc*"), std::wstring_view(L"aßc")); + check.template operator()<"{:*^4.2}">(SV("*aß*"), std::wstring_view(L"aßc")); + } +# endif + // ß requires one column check.template operator()<"{}">(SV("aßc"), STR("aßc")); @@ -330,9 +370,14 @@ std::basic_string world = STR("world"); std::basic_string universe = STR("universe"); - // Testing the char const[] is a bit tricky due to array to pointer decay. - // Since there are separate tests in format.formatter.spec the array is not - // tested here. + // Test a string literal in a way it won't decay to a pointer. + if constexpr (std::same_as) + format_test_string("world", "universe", check, check_exception); +#ifndef TEST_HAS_NO_WIDE_CHARACTERS + else + format_test_string(L"world", L"universe", check, check_exception); +#endif + format_test_string(world.c_str(), universe.c_str(), check, check_exception); format_test_string(const_cast(world.c_str()), const_cast(universe.c_str()), check, check_exception);