[PATCH] libstdc++: Do not specialize std::formatter for incomplete type [PR120625]
Tomasz Kaminski
tkaminsk@redhat.com
Thu Jun 12 06:16:05 GMT 2025
On Thu, Jun 12, 2025 at 12:04 AM Jonathan Wakely <jwakely@redhat.com> wrote:
> Using an incomplete type as the template argument for std::formatter
> specializations causes problems for program-defined specializations of
> std::formatter which have constraints. When the compiler has to find
> which specialization of std::formatter to use for the incomplete type it
> considers the program-defined specializations and checks to see if their
> constraints are satisfied, which can give errors if the constraints
> cannot be checked for incomplete types.
>
> This replaces the base class of the disabled specializations with a
> concrete class __formatter_disabled, so there is no need to match a
> specialization and no more incomplete type.
>
> libstdc++-v3/ChangeLog:
>
> PR libstdc++/120625
> * include/std/format (__format::__disabled): Remove.
> (__formatter_disabled): New type.
> (formatter<char*, wchar_t>, formatter<const char*, wchar_t>)
> (formatter<char[N], wchar_t>, formatter<string, wchar_t>)
> (formatter<string_view, wchar_t>): Use __formatter_disabled as
> base class instead of formatter<__disabled, wchar_t>.
> * testsuite/std/format/formatter/120625.cc: New test.
> ---
>
> Tested x86_64-linux.
>
LGTM. Thanks.
>
> This is needed for trunk and gcc-15.
>
> The diagnostic for trying to use those disabled formatters will now
> show:
>
> 3119 | __formatter_disabled() = delete; // Cannot format char
> sequence to wchar_t
>
> which seems fine.
>
> libstdc++-v3/include/std/format | 18 +++++++++++-------
> .../testsuite/std/format/formatter/120625.cc | 19 +++++++++++++++++++
> 2 files changed, 30 insertions(+), 7 deletions(-)
> create mode 100644 libstdc++-v3/testsuite/std/format/formatter/120625.cc
>
> diff --git a/libstdc++-v3/include/std/format
> b/libstdc++-v3/include/std/format
> index ec76ab0682e0..04fb23eb1367 100644
> --- a/libstdc++-v3/include/std/format
> +++ b/libstdc++-v3/include/std/format
> @@ -3114,24 +3114,28 @@ namespace __format
> // _GLIBCXX_RESOLVE_LIB_DEFECTS
> // 3944. Formatters converting sequences of char to sequences of wchar_t
>
> - namespace __format { struct __disabled; }
> + struct __formatter_disabled
> + {
> + __formatter_disabled() = delete; // Cannot format char sequence to
> wchar_t
> + __formatter_disabled(const __formatter_disabled&) = delete;
> + __formatter_disabled& operator=(const __formatter_disabled&) = delete;
> + };
>
> - // std::formatter<__disabled, C> uses the primary template, which is
> disabled.
> template<>
> struct formatter<char*, wchar_t>
> - : private formatter<__format::__disabled, wchar_t> { };
> + : private __formatter_disabled { };
> template<>
> struct formatter<const char*, wchar_t>
> - : private formatter<__format::__disabled, wchar_t> { };
> + : private __formatter_disabled { };
> template<size_t _Nm>
> struct formatter<char[_Nm], wchar_t>
> - : private formatter<__format::__disabled, wchar_t> { };
> + : private __formatter_disabled { };
> template<class _Traits, class _Allocator>
> struct formatter<basic_string<char, _Traits, _Allocator>, wchar_t>
> - : private formatter<__format::__disabled, wchar_t> { };
> + : private __formatter_disabled { };
> template<class _Traits>
> struct formatter<basic_string_view<char, _Traits>, wchar_t>
> - : private formatter<__format::__disabled, wchar_t> { };
> + : private __formatter_disabled { };
> #endif
>
> /// An iterator after the last character written, and the number of
> diff --git a/libstdc++-v3/testsuite/std/format/formatter/120625.cc
> b/libstdc++-v3/testsuite/std/format/formatter/120625.cc
> new file mode 100644
> index 000000000000..6b03af93b1c7
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/std/format/formatter/120625.cc
> @@ -0,0 +1,19 @@
> +// { dg-do compile { target c++20 } }
> +
> +// Bug libstdc++/120625
> +// std::formatter<__disabled> specializations cause errors in user code
> +
> +#include <format>
> +
> +enum X { };
> +
> +// A concept that cannot be used with incomplete types:
> +template<typename T>
> +concept is_X = !std::is_empty_v<T> && std::is_same_v<X, T>;
> +
> +// A valid program-defined specialization:
> +template<typename T, typename C> requires is_X<T>
> +struct std::formatter<T, C> : std::formatter<int, C> { };
> +
> +// Instantiate the program-defined formatter specialization:
> +auto s = sizeof(std::formatter<X, char>);
> --
> 2.49.0
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://gcc.gnu.org/pipermail/libstdc++/attachments/20250612/73d02989/attachment-0001.htm>
More information about the Libstdc++
mailing list