From ae8a5c5c0aaf1659aa5df5ce6bb95a36ae2e9f16 Mon Sep 17 00:00:00 2001 From: "A. Jiang" Date: Sat, 9 Mar 2024 21:52:42 +0800 Subject: [PATCH 1/2] Conditionally emit special diagnostic message for lack of `const` Also emit `static_assert` error messages for `basic_format_arg::handle`. --- stl/inc/format | 54 ++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 4f7a3ffa3a..10d0ca1c00 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -654,6 +654,14 @@ concept _Formattable_with = semiregular<_Formatter> { __cf.format(__t, __fc) } -> same_as; }; +template >> +concept _Formattable_with_non_const = semiregular<_Formatter> + && requires(_Formatter& __f, _Ty&& __t, _Context __fc, + basic_format_parse_context __pc) { + { __f.parse(__pc) } -> same_as; + { __f.format(__t, __fc) } -> same_as; + }; + template inline constexpr bool _Is_basic_string_like_for = false; @@ -707,15 +715,23 @@ public: using _Td = remove_const_t<_Ty>; // doesn't drop const-qualifier per an unnumbered LWG issue using _Tq = conditional_t<_Formattable_with, const _Ty, _Ty>; + if constexpr (_Formattable_with_non_const<_Tq, _Context>) { + static_assert(_Formattable_with<_Tq, _Context>, + "The format() member function can't be called on const formatter. " + "To make the formatter usable, add const to format(). " + "See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements]."); + } else { + static_assert(_Formattable_with<_Tq, _Context>, + "Cannot format an argument. " + "To make this type formattable, provide a formatter specialization. " + "See N4971 [format.arg]/12, [format.formattable], and [formatter.requirements]."); + } + typename _Context::template formatter_type<_Td> _Formatter; _Parse_ctx.advance_to(_Formatter.parse(_Parse_ctx)); _Format_ctx.advance_to( _Formatter.format(*const_cast<_Tq*>(static_cast(_Ptr)), _Format_ctx)); - }) { - // ditto doesn't drop const-qualifier - using _Tq = conditional_t<_Formattable_with, const _Ty, _Ty>; - static_assert(_Formattable_with<_Tq, _Context>); - } + }) {} void format(basic_format_parse_context<_CharType>& _Parse_ctx, _Context& _Format_ctx) const { _Format(_Parse_ctx, _Format_ctx, _Ptr); @@ -3711,19 +3727,31 @@ _EXPORT_STD using wformat_args = basic_format_args; _EXPORT_STD template _NODISCARD auto make_format_args(_Args&... _Vals) { - // TRANSITION, should cite the new working draft - static_assert((_Formattable_with, _Context> && ...), - "Cannot format an argument. To make type T formattable, provide a formatter specialization. " - "See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements]."); + if constexpr ((_Formattable_with_non_const, _Context> && ...)) { + static_assert((_Formattable_with, _Context> && ...), + "The format() member function can't be called on const formatter. " + "To make the formatter usable, add const to format(). " + "See N4971 [format.arg.store]/2 and [formatter.requirements]."); + } else { + static_assert((_Formattable_with, _Context> && ...), + "Cannot format an argument. To make T formattable, provide a formatter specialization. " + "See N4971 [format.arg.store]/2 and [formatter.requirements]."); + } return _Format_arg_store<_Context, _Args...>{_Vals...}; } _EXPORT_STD template _NODISCARD auto make_wformat_args(_Args&... _Vals) { - // TRANSITION, should cite the new working draft - static_assert((_Formattable_with, wformat_context> && ...), - "Cannot format an argument. To make type T formattable, provide a formatter specialization. " - "See N4964 [format.arg.store]/2 (along with modification in P2905R2) and [formatter.requirements]."); + if constexpr ((_Formattable_with_non_const, wformat_context> && ...)) { + static_assert((_Formattable_with, wformat_context> && ...), + "The format() member function can't be called on const formatter. " + "To make the formatter usable, add const to format(). " + "See N4971 [format.arg.store]/2 and [formatter.requirements]."); + } else { + static_assert((_Formattable_with, wformat_context> && ...), + "Cannot format an argument. To make this type formattable, provide a formatter specialization. " + "See N4971 [format.arg.store]/2 and [formatter.requirements]."); + } return _Format_arg_store{_Vals...}; } From 523bf0e603c3188b6c81ae0dfeca3f5d733a15c7 Mon Sep 17 00:00:00 2001 From: "Stephan T. Lavavej" Date: Wed, 13 Mar 2024 03:28:39 -0700 Subject: [PATCH 2/2] Implement `make_wformat_args` with Effects Equivalent To. --- stl/inc/format | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/stl/inc/format b/stl/inc/format index 10d0ca1c00..4e15d2391b 100644 --- a/stl/inc/format +++ b/stl/inc/format @@ -3742,17 +3742,7 @@ _NODISCARD auto make_format_args(_Args&... _Vals) { _EXPORT_STD template _NODISCARD auto make_wformat_args(_Args&... _Vals) { - if constexpr ((_Formattable_with_non_const, wformat_context> && ...)) { - static_assert((_Formattable_with, wformat_context> && ...), - "The format() member function can't be called on const formatter. " - "To make the formatter usable, add const to format(). " - "See N4971 [format.arg.store]/2 and [formatter.requirements]."); - } else { - static_assert((_Formattable_with, wformat_context> && ...), - "Cannot format an argument. To make this type formattable, provide a formatter specialization. " - "See N4971 [format.arg.store]/2 and [formatter.requirements]."); - } - return _Format_arg_store{_Vals...}; + return _STD make_format_args(_Vals...); } _FMT_P2286_BEGIN