From ec54aaf919e300f87d0bc2891abe03e800284953 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 8 Jun 2022 03:52:25 +0700 Subject: [PATCH 1/9] fix format with custom types Co-authored-by: S. B. Tam --- stl/inc/format | 3 ++- .../test.cpp | 21 +++++++++++++++++++ 2 files changed, 23 insertions(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index 6fd58906e9..cfe903043d 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3289,7 +3289,8 @@ struct _Formatter_base { return _STD visit_format_arg( _Arg_formatter{ ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{_Val}); + basic_format_arg<_FormatContext>{ + static_cast::template _Storage_type<_Ty>>(_Val)}); } private: diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index bc17230940..2dc9f4009e 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1470,6 +1470,27 @@ void test() { test_localized_char(); } +template +struct Box { + T value; +}; + +template +struct std::formatter, CharT> : std::formatter { + template + auto format(Box t, FormatContext& fc) const { + return formatter::format(t.value, fc); + } +}; + +// Also test GH-2765 ": Cannot format a long value with formatter" +void test_gh_2765() { + Box v = {42}; + assert(format("{:#x}", v) == "0x2a"s); +} + int main() { test(); + + test_gh_2765(); } From 2503d2a25849f2731e4a6d3a9160663cece41d57 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 8 Jun 2022 05:29:57 +0700 Subject: [PATCH 2/9] don't do `static_cast` if `_Storage_type` is `handle` --- stl/inc/format | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index cfe903043d..fe51f7c839 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3286,11 +3286,18 @@ struct _Formatter_base { _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); } - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{ - static_cast::template _Storage_type<_Ty>>(_Val)}); + using _Storage_type = typename _Format_arg_traits<_FormatContext>::template _Storage_type<_Ty>; + if constexpr (is_same_v::handle, _Storage_type>) { + return _STD visit_format_arg( + _Arg_formatter{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, + basic_format_arg<_FormatContext>{_Val}); + } else { + return _STD visit_format_arg( + _Arg_formatter{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, + basic_format_arg<_FormatContext>{static_cast<_Storage_type>(_Val)}); + } } private: From 27721b6c83e67bd561e3a952cc1c28db00023854 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 7 Jun 2022 16:55:31 -0700 Subject: [PATCH 3/9] Use `42L` to initialize `Box`. --- tests/std/tests/P0645R10_text_formatting_formatting/test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index 2dc9f4009e..a83e1c7ff9 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1485,7 +1485,7 @@ struct std::formatter, CharT> : std::formatter { // Also test GH-2765 ": Cannot format a long value with formatter" void test_gh_2765() { - Box v = {42}; + Box v = {42L}; assert(format("{:#x}", v) == "0x2a"s); } From aef5eae69b6b10def7bac7b964c6265a5bc14bb6 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 7 Jun 2022 17:00:48 -0700 Subject: [PATCH 4/9] Test `char` and `wchar_t`. --- .../test.cpp | 42 ++++++++++--------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index a83e1c7ff9..10234b1ffd 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1392,6 +1392,26 @@ void test_localized_char() { assert(format(STR("{:Lc}"), T('c')) == STR("c")); } +template +struct Box { + T value; +}; + +template +struct std::formatter, charT> : std::formatter { + template + auto format(Box t, FormatContext& fc) const { + return formatter::format(t.value, fc); + } +}; + +// Also test GH-2765 ": Cannot format a long value with formatter" +template +void test_gh_2765() { + Box v = {42L}; + assert(format(STR("{:#x}"), v) == STR("0x2a")); +} + void test() { test_simple_formatting(); test_simple_formatting(); @@ -1468,29 +1488,11 @@ void test() { test_localized_char(); test_localized_char(); test_localized_char(); -} - -template -struct Box { - T value; -}; -template -struct std::formatter, CharT> : std::formatter { - template - auto format(Box t, FormatContext& fc) const { - return formatter::format(t.value, fc); - } -}; - -// Also test GH-2765 ": Cannot format a long value with formatter" -void test_gh_2765() { - Box v = {42L}; - assert(format("{:#x}", v) == "0x2a"s); + test_gh_2765(); + test_gh_2765(); } int main() { test(); - - test_gh_2765(); } From 272240762c9671d2e07f8cccc1a3c758cad8f81d Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 7 Jun 2022 17:06:32 -0700 Subject: [PATCH 5/9] Extract `_Arg_formatter`. --- stl/inc/format | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index fe51f7c839..48010d0a70 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3286,17 +3286,14 @@ struct _Formatter_base { _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); } + _Arg_formatter _Arg_fmt{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}; + using _Storage_type = typename _Format_arg_traits<_FormatContext>::template _Storage_type<_Ty>; if constexpr (is_same_v::handle, _Storage_type>) { - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{_Val}); + return _STD visit_format_arg(_Arg_fmt, basic_format_arg<_FormatContext>{_Val}); } else { - return _STD visit_format_arg( - _Arg_formatter{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, - basic_format_arg<_FormatContext>{static_cast<_Storage_type>(_Val)}); + return _STD visit_format_arg(_Arg_fmt, basic_format_arg<_FormatContext>{static_cast<_Storage_type>(_Val)}); } } From a72a280a2ac101d7bd94a8cf5299366491317c2c Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Tue, 7 Jun 2022 17:43:24 -0700 Subject: [PATCH 6/9] Move test coverage to P0645R10_text_formatting_custom_formatting. Co-authored-by: S. B. Tam --- .../test.cpp | 6 +++++ .../test.cpp | 23 ------------------- 2 files changed, 6 insertions(+), 23 deletions(-) diff --git a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp index 02fb975e78..78bcc07288 100644 --- a/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_custom_formatting/test.cpp @@ -172,8 +172,10 @@ void test_format_family_overloads() { template void test_custom_formattable_type() { test_numeric_custom_formattable_type(); + test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); + test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); #ifdef _NATIVE_WCHAR_T_DEFINED @@ -181,13 +183,16 @@ void test_custom_formattable_type() { #endif test_numeric_custom_formattable_type(); test_numeric_custom_formattable_type(); + test_numeric_custom_formattable_type(); } template void test_mixed_custom_formattable_type() { test_numeric_mixed_args_custom_formattable_type(); + test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); + test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); #ifdef _NATIVE_WCHAR_T_DEFINED @@ -195,6 +200,7 @@ void test_mixed_custom_formattable_type() { #endif test_numeric_mixed_args_custom_formattable_type(); test_numeric_mixed_args_custom_formattable_type(); + test_numeric_mixed_args_custom_formattable_type(); } int main() { diff --git a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp index 10234b1ffd..bc17230940 100644 --- a/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_formatting/test.cpp @@ -1392,26 +1392,6 @@ void test_localized_char() { assert(format(STR("{:Lc}"), T('c')) == STR("c")); } -template -struct Box { - T value; -}; - -template -struct std::formatter, charT> : std::formatter { - template - auto format(Box t, FormatContext& fc) const { - return formatter::format(t.value, fc); - } -}; - -// Also test GH-2765 ": Cannot format a long value with formatter" -template -void test_gh_2765() { - Box v = {42L}; - assert(format(STR("{:#x}"), v) == STR("0x2a")); -} - void test() { test_simple_formatting(); test_simple_formatting(); @@ -1488,9 +1468,6 @@ void test() { test_localized_char(); test_localized_char(); test_localized_char(); - - test_gh_2765(); - test_gh_2765(); } int main() { From 8caf0bd0e1c1e0825a124a6d41602f3e7347d51b Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Wed, 8 Jun 2022 16:38:13 +0700 Subject: [PATCH 7/9] same _Storage_type for `const string` and `string` Co-authored-by: S. B. Tam --- stl/inc/format | 2 +- tests/std/tests/P0645R10_text_formatting_args/test.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/stl/inc/format b/stl/inc/format index 48010d0a70..a08387ebde 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -1776,7 +1776,7 @@ struct _Format_arg_traits { -> basic_string_view<_Char_type>; // not defined template - static auto _Phony_basic_format_arg_constructor(const basic_string<_Char_type, _Traits, _Alloc>&) + static auto _Phony_basic_format_arg_constructor(basic_string<_Char_type, _Traits, _Alloc>) -> basic_string_view<_Char_type>; // not defined static auto _Phony_basic_format_arg_constructor(nullptr_t) -> const void*; // not defined diff --git a/tests/std/tests/P0645R10_text_formatting_args/test.cpp b/tests/std/tests/P0645R10_text_formatting_args/test.cpp index 494fd95fc1..2c15bfeaf6 100644 --- a/tests/std/tests/P0645R10_text_formatting_args/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_args/test.cpp @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -212,6 +213,9 @@ void test_format_arg_store() { static_assert(sizeof(_Format_arg_index) == sizeof(size_t)); static_assert(is_same_v<_Format_arg_traits::_Storage_type, const void*>); +static_assert(is_same_v<_Format_arg_traits::_Storage_type, string_view>); +static_assert(is_same_v<_Format_arg_traits::_Storage_type, string_view>); + template void test_visit_monostate() { assert(visit_format_arg(visitor, basic_format_arg()) == Arg_type::none); From ba451e04401091f7db74409cca3bb369df658a22 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Thu, 9 Jun 2022 17:19:13 +0700 Subject: [PATCH 8/9] add `basic_format_arg` constructors, fix `charT*` storage type, remove previous version fix --- stl/inc/format | 18 +++++++++--------- .../P0645R10_text_formatting_args/test.cpp | 2 ++ 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index a08387ebde..e3272f0b41 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -666,6 +666,10 @@ public: : _Active_state(_Basic_format_arg_type::_Int_type), _Int_state(_Val) {} explicit basic_format_arg(const unsigned int _Val) noexcept : _Active_state(_Basic_format_arg_type::_UInt_type), _UInt_state(_Val) {} + explicit basic_format_arg(const long _Val) noexcept + : _Active_state(_Basic_format_arg_type::_Int_type), _Int_state(_Val) {} + explicit basic_format_arg(const unsigned long _Val) noexcept + : _Active_state(_Basic_format_arg_type::_UInt_type), _UInt_state(_Val) {} explicit basic_format_arg(const long long _Val) noexcept : _Active_state(_Basic_format_arg_type::_Long_long_type), _Long_long_state(_Val) {} explicit basic_format_arg(const unsigned long long _Val) noexcept @@ -1769,6 +1773,7 @@ struct _Format_arg_traits { static auto _Phony_basic_format_arg_constructor(double) -> double; // not defined static auto _Phony_basic_format_arg_constructor(long double) -> long double; // not defined + static auto _Phony_basic_format_arg_constructor(_Char_type*) -> const _Char_type*; // not defined static auto _Phony_basic_format_arg_constructor(const _Char_type*) -> const _Char_type*; // not defined template @@ -3286,15 +3291,10 @@ struct _Formatter_base { _FormatCtx.arg(static_cast(_Specs._Dynamic_precision_index))); } - _Arg_formatter _Arg_fmt{ - ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}; - - using _Storage_type = typename _Format_arg_traits<_FormatContext>::template _Storage_type<_Ty>; - if constexpr (is_same_v::handle, _Storage_type>) { - return _STD visit_format_arg(_Arg_fmt, basic_format_arg<_FormatContext>{_Val}); - } else { - return _STD visit_format_arg(_Arg_fmt, basic_format_arg<_FormatContext>{static_cast<_Storage_type>(_Val)}); - } + return _STD visit_format_arg( + _Arg_formatter{ + ._Ctx = _STD addressof(_FormatCtx), ._Specs = _STD addressof(_Format_specs)}, + basic_format_arg<_FormatContext>{_Val}); } private: diff --git a/tests/std/tests/P0645R10_text_formatting_args/test.cpp b/tests/std/tests/P0645R10_text_formatting_args/test.cpp index 2c15bfeaf6..de2f00b88f 100644 --- a/tests/std/tests/P0645R10_text_formatting_args/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_args/test.cpp @@ -215,6 +215,8 @@ static_assert(is_same_v<_Format_arg_traits::_Storage_type static_assert(is_same_v<_Format_arg_traits::_Storage_type, string_view>); static_assert(is_same_v<_Format_arg_traits::_Storage_type, string_view>); +static_assert(is_same_v<_Format_arg_traits::_Storage_type, const char*>); +static_assert(is_same_v<_Format_arg_traits::_Storage_type, const char*>); template void test_visit_monostate() { From 3188b7145e1a68a853dce66fcd6506a8f3bc2ed9 Mon Sep 17 00:00:00 2001 From: Igor Zhukov Date: Thu, 9 Jun 2022 17:45:30 +0700 Subject: [PATCH 9/9] add one more `static_assert` --- tests/std/tests/P0645R10_text_formatting_args/test.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/tests/std/tests/P0645R10_text_formatting_args/test.cpp b/tests/std/tests/P0645R10_text_formatting_args/test.cpp index de2f00b88f..d5ba4e427f 100644 --- a/tests/std/tests/P0645R10_text_formatting_args/test.cpp +++ b/tests/std/tests/P0645R10_text_formatting_args/test.cpp @@ -218,6 +218,12 @@ static_assert(is_same_v<_Format_arg_traits::_Storage_type::_Storage_type, const char*>); static_assert(is_same_v<_Format_arg_traits::_Storage_type, const char*>); +// we rely on the _Storage_type to be int in: +// explicit basic_format_arg(const long _Val) noexcept +// : _Active_state(_Basic_format_arg_type::_Int_type), _Int_state(_Val) {} +static_assert(is_same_v<_Format_arg_traits::_Storage_type, int>); +static_assert(is_same_v<_Format_arg_traits::_Storage_type, unsigned int>); + template void test_visit_monostate() { assert(visit_format_arg(visitor, basic_format_arg()) == Arg_type::none);