From 52de6aa1a8582208b519b6998389d3a801b0de7b Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Tue, 12 Dec 2023 20:53:08 +0000 Subject: libstdc++: Fix std::format("{}", 'c') When I added a fast path for std::format("{}", x) in r14-5587-g41a5ea4cab2c59 I forgot to handle char separately from other integral types. That caused std::format("{}", 'c') to return "99" instead of "c". libstdc++-v3/ChangeLog: * include/std/format (__do_vformat_to): Handle char separately from other integral types. * testsuite/std/format/functions/format.cc: Check for expected output for char and bool arguments. * testsuite/std/format/string.cc: Check that 0 filling is rejected for character and string formats. --- libstdc++-v3/include/std/format | 9 ++++ .../testsuite/std/format/functions/format.cc | 56 ++++++++++++++++++++++ libstdc++-v3/testsuite/std/format/string.cc | 3 ++ 3 files changed, 68 insertions(+) diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index 04d03e0..1f8cd5c 100644 --- a/libstdc++-v3/include/std/format +++ b/libstdc++-v3/include/std/format @@ -3968,6 +3968,15 @@ namespace __format __done = true; } } + else if constexpr (is_same_v<_Tp, char>) + { + if (auto __res = __sink_out._M_reserve(1)) + { + *__res.get() = __arg; + __res._M_bump(1); + __done = true; + } + } else if constexpr (is_integral_v<_Tp>) { make_unsigned_t<_Tp> __uval; diff --git a/libstdc++-v3/testsuite/std/format/functions/format.cc b/libstdc++-v3/testsuite/std/format/functions/format.cc index 9328dec..b3b4f06 100644 --- a/libstdc++-v3/testsuite/std/format/functions/format.cc +++ b/libstdc++-v3/testsuite/std/format/functions/format.cc @@ -257,11 +257,41 @@ test_width() } void +test_char() +{ + std::string s; + + s = std::format("{}", 'a'); + VERIFY( s == "a" ); + + s = std::format("{:c} {:d} {:o}", 'b', '\x17', '\x3f'); + VERIFY( s == "b 23 77" ); + + s = std::format("{:#d} {:#o}", '\x17', '\x3f'); + VERIFY( s == "23 077" ); + + s = std::format("{:04d} {:04o}", '\x17', '\x3f'); + VERIFY( s == "0023 0077" ); + + s = std::format("{:b} {:B} {:#b} {:#B}", '\xff', '\xa0', '\x17', '\x3f'); + if constexpr (std::is_unsigned_v) + VERIFY( s == "11111111 10100000 0b10111 0B111111" ); + else + VERIFY( s == "-1 -1100000 0b10111 0B111111" ); + + s = std::format("{:x} {:#x} {:#X}", '\x12', '\x34', '\x45'); + VERIFY( s == "12 0x34 0X45" ); +} + +void test_wchar() { using namespace std::literals; std::wstring s; + s = std::format(L"{}", L'a'); + VERIFY( s == L"a" ); + s = std::format(L"{} {} {} {} {} {}", L'0', 1, 2LL, 3.4, L"five", L"six"s); VERIFY( s == L"0 1 2 3.4 five six" ); @@ -353,6 +383,9 @@ test_pointer() const void* pc = p; std::string s, str_int; + s = std::format("{}", p); + VERIFY( s == "0x0" ); + s = std::format("{} {} {}", p, pc, nullptr); VERIFY( s == "0x0 0x0 0x0" ); s = std::format("{:p} {:p} {:p}", p, pc, nullptr); @@ -385,6 +418,27 @@ test_pointer() #endif } +void +test_bool() +{ + std::string s; + + s = std::format("{}", true); + VERIFY( s == "true" ); + s = std::format("{:} {:s}", true, false); + VERIFY( s == "true false" ); + s = std::format("{:b} {:#b}", true, false); + VERIFY( s == "1 0b0" ); + s = std::format("{:B} {:#B}", false, true); + VERIFY( s == "0 0B1" ); + s = std::format("{:d} {:#d}", false, true); + VERIFY( s == "0 1" ); + s = std::format("{:o} {:#o} {:#o}", false, true, false); + VERIFY( s == "0 01 0" ); + s = std::format("{:x} {:#x} {:#X}", false, true, false); + VERIFY( s == "0 0x1 0X0" ); +} + int main() { test_no_args(); @@ -393,8 +447,10 @@ int main() test_alternate_forms(); test_locale(); test_width(); + test_char(); test_wchar(); test_minmax(); test_p1652r1(); test_pointer(); + test_bool(); } diff --git a/libstdc++-v3/testsuite/std/format/string.cc b/libstdc++-v3/testsuite/std/format/string.cc index 5d33864..40aaeba 100644 --- a/libstdc++-v3/testsuite/std/format/string.cc +++ b/libstdc++-v3/testsuite/std/format/string.cc @@ -109,6 +109,9 @@ test_format_spec() VERIFY( ! is_format_string_for("{:#?}", "str") ); VERIFY( ! is_format_string_for("{:#?}", 'c') ); + VERIFY( ! is_format_string_for("{:0c}", 'c') ); + VERIFY( ! is_format_string_for("{:0s}", true) ); + // Precision only valid for string and floating-point types. VERIFY( ! is_format_string_for("{:.3d}", 1) ); VERIFY( ! is_format_string_for("{:3.3d}", 1) ); -- cgit v1.1