From: Jonathan Wakely Date: Wed, 11 Jun 2025 10:11:52 +0000 (+0100) Subject: libstdc++: Do not specialize std::formatter for incomplete type [PR120625] X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=76bf78d32c683af3bf88f4aef595048edbd82372;p=thirdparty%2Fgcc.git libstdc++: Do not specialize std::formatter for incomplete type [PR120625] 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, formatter) (formatter, formatter) (formatter): Use __formatter_disabled as base class instead of formatter<__disabled, wchar_t>. * testsuite/std/format/formatter/120625.cc: New test. Reviewed-by: Tomasz KamiƄski --- diff --git a/libstdc++-v3/include/std/format b/libstdc++-v3/include/std/format index ec76ab0682e..04fb23eb136 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 - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template<> struct formatter - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template struct formatter - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template struct formatter, wchar_t> - : private formatter<__format::__disabled, wchar_t> { }; + : private __formatter_disabled { }; template struct formatter, 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 00000000000..6b03af93b1c --- /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 + +enum X { }; + +// A concept that cannot be used with incomplete types: +template +concept is_X = !std::is_empty_v && std::is_same_v; + +// A valid program-defined specialization: +template requires is_X +struct std::formatter : std::formatter { }; + +// Instantiate the program-defined formatter specialization: +auto s = sizeof(std::formatter);