On Wed, 15 Jul 2026 at 12:52, Tomasz Kaminski <[email protected]> wrote: > > > > On Wed, Jul 15, 2026 at 1:44 PM Jakub Jelinek <[email protected]> wrote: >> >> Hi! >> >> The following patch adds _Clang::__no_specializations__ attribute >> to a couple of templates: >> 1) LWG3975 - basic_format_{,parse_}context >> 2) LWG3990 - variant, tuple >> 3) LWG4305 - type_order > > >> This assumes all those issues were handled as defect reports.
Yes please. For LWG4305 it's irrelevant because C++23 didn't have std::type_order anyway. For tuple, variant, and the format context types, there was no way to specialize them that wasn't undefined behaviour. >> >> What I haven't touched, but has similar wording: >> 4) LWG2129 - std::initializer_list; the compiler already errors on these >> 5) P2652R2 - std::allocator_traits (dunno if it is a DR or not etc.) > > I think we should apply this as DR, as we implemented allocate_at_least, > so, we will break user-provided specialization when moving from C++11 to > C++23. I think it would be OK to only add the attribute for C++23 and later. If somebody specialized allocator_traits in C++20 then it worked OK (and was considered to be valid by some of the committee, which is why allocate_at_least was originally proposed as a free function). There's no need to break that C++20 code. >> >> 6) P3019R14 - std::indirect (ditto) >> 7) P0912R5 - std::coroutine_handle (ditto) > > The 6/7 are papers that introduced the feature, so requirements were present > from the feature inception, so there is no DR in question. Right, there was never a standard that allowed specializing those. >> >> >> Anything else I'm missing? > > From my notes, we also have SIMD from: > https://cplusplus.github.io/LWG/issue4535 >> >> >> Note, seems libcxx adds the attribute to significantly more places, but not >> sure if that is desirable. [namespace.std] has some restrictions, but those >> generally say that it is UB in that case, which I'm not sure is the right >> case for unconditional error. Compared to that, the above mentioned >> library issues talk about ill-formed (and not IFNDR, so we really should >> be diagnosing that). >> >> So far lightly tested, ok for trunk if it passes full testing? >> >> 2026-07-15 Jakub Jelinek <[email protected]> >> >> PR c++/120635 >> * include/bits/c++config (_GLIBCXX_NO_SPECIALIZATIONS): Define. >> * include/std/variant (std::variant): Use it to resolve LWG3990. >> * include/std/format (std::basic_format_parse_context, >> std::basic_format_context): Use it to resolve LWG3975. >> * libsupc++/compare (std::type_order): Use it to resolve LWG4305. >> * include/std/tuple (std::tuple): Use it to resolve LWG3990. >> Temporarily ignore -Winvalid-specialization around specializations >> of tuple. >> * testsuite/18_support/comparisons/type_order/lwg4305.cc: New test. >> * testsuite/std/format/lwg3975.cc: New test. >> * testsuite/20_util/tuple/lwg3990.cc: New test. >> * testsuite/20_util/variant/lwg3990.cc: New test. >> >> --- libstdc++-v3/include/bits/c++config.jj 2026-01-02 >> 22:41:17.624547836 +0100 >> +++ libstdc++-v3/include/bits/c++config 2026-07-15 12:24:00.321648893 +0200 >> @@ -927,6 +927,14 @@ namespace __gnu_cxx >> # define _GLIBCXX_USE_BUILTIN_TRAIT(BT) 0 >> #endif >> >> +#if __has_cpp_attribute(_Clang::__no_specializations__) >> +# define _GLIBCXX_NO_SPECIALIZATIONS(T) \ >> + [[_Clang::__no_specializations__ ("explicit or partial specialization of >> " \ >> + #T)]] >> +#else >> +# define _GLIBCXX_NO_SPECIALIZATIONS(T) >> +#endif >> + >> // Whether deducing this is usable either officially, if in C++23 mode, or >> // as an extension (Clang doesn't support the latter). >> #if __cpp_explicit_this_parameter \ >> --- libstdc++-v3/include/std/variant.jj 2026-01-02 22:41:17.673547024 +0100 >> +++ libstdc++-v3/include/std/variant 2026-07-15 13:16:35.639939009 +0200 >> @@ -1450,7 +1450,10 @@ namespace __detail::__variant >> }; >> >> template<typename... _Types> >> - class variant >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 3990. Program-defined specializations of std::tuple and std::variant >> + // can't be properly supported >> + class _GLIBCXX_NO_SPECIALIZATIONS (std::variant) variant >> : private __detail::__variant::_Variant_base<_Types...>, >> private _Enable_copy_move< >> __detail::__variant::_Traits<_Types...>::_S_copy_ctor, >> --- libstdc++-v3/include/std/format.jj 2026-07-09 23:02:50.052419808 +0200 >> +++ libstdc++-v3/include/std/format 2026-07-15 12:39:12.876753834 +0200 >> @@ -286,7 +286,10 @@ namespace __format >> #endif >> >> template<typename _CharT> >> - class basic_format_parse_context >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 3975. Specializations of basic_format_context should not be permitted >> + class _GLIBCXX_NO_SPECIALIZATIONS (std::basic_format_parse_context) >> + basic_format_parse_context >> { >> public: >> using char_type = _CharT; >> @@ -5015,7 +5018,10 @@ namespace __format >> * @since C++20 >> */ >> template<typename _Out, typename _CharT> >> - class basic_format_context >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 3975. Specializations of basic_format_context should not be permitted >> + class _GLIBCXX_NO_SPECIALIZATIONS (std::basic_format_context) >> + basic_format_context >> { >> static_assert( output_iterator<_Out, const _CharT&> ); >> >> --- libstdc++-v3/include/std/tuple.jj 2026-05-14 21:26:54.625211399 +0200 >> +++ libstdc++-v3/include/std/tuple 2026-07-15 13:14:56.950203385 +0200 >> @@ -791,7 +791,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> >> /// Primary class template, tuple >> template<typename... _Elements> >> - class tuple : public _Tuple_impl<0, _Elements...> >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 3990. Program-defined specializations of std::tuple and std::variant >> + // can't be properly supported >> + class _GLIBCXX_NO_SPECIALIZATIONS (std::tuple) tuple >> + : public _Tuple_impl<0, _Elements...> >> { >> using _Inherited = _Tuple_impl<0, _Elements...>; >> >> @@ -1942,6 +1946,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> tuple(allocator_arg_t, _Alloc, tuple<_UTypes...>) -> tuple<_UTypes...>; >> #endif >> >> +#pragma GCC diagnostic push >> +#pragma GCC diagnostic ignored "-Winvalid-specialization" >> // Explicit specialization, zero-element tuple. >> template<> >> class tuple<> >> @@ -2416,6 +2422,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION >> { _Inherited::_M_swap(__in); } >> }; >> #endif // concepts && conditional_explicit >> +#pragma GCC diagnostic pop >> >> /// class tuple_size >> template<typename... _Elements> >> --- libstdc++-v3/libsupc++/compare.jj 2026-01-19 22:16:24.654213651 +0100 >> +++ libstdc++-v3/libsupc++/compare 2026-07-15 13:03:05.962281429 +0200 >> @@ -1267,7 +1267,9 @@ namespace std _GLIBCXX_VISIBILITY(defaul >> /// @since C++26 >> >> template<typename _Tp, typename _Up> >> - struct type_order >> + // _GLIBCXX_RESOLVE_LIB_DEFECTS >> + // 4305. Missing user requirements on type_order template >> + struct _GLIBCXX_NO_SPECIALIZATIONS (std::type_order) type_order >> { >> static constexpr strong_ordering value = __builtin_type_order(_Tp, >> _Up); >> using value_type = strong_ordering; >> --- libstdc++-v3/testsuite/18_support/comparisons/type_order/lwg4305.cc.jj >> 2026-07-15 13:04:03.355551554 +0200 >> +++ libstdc++-v3/testsuite/18_support/comparisons/type_order/lwg4305.cc >> 2026-07-15 13:06:12.380910724 +0200 >> @@ -0,0 +1,15 @@ >> +// { dg-do compile { target c++26 } } >> + >> +// LWG 4305. Missing user requirements on type_order template >> + >> +#include <compare> >> + >> +struct A {}; >> +template<typename T> >> +struct B {}; >> + >> +template<> >> +struct std::type_order<A, A> {}; // { dg-error "cannot be >> specialized: 'explicit or partial specialization of std::type_order'" } >> + >> +template<typename T> >> +struct std::type_order<B<T>, T> {}; // { dg-error "cannot be >> specialized: 'explicit or partial specialization of std::type_order'" } >> --- libstdc++-v3/testsuite/std/format/lwg3975.cc.jj 2026-07-15 >> 12:48:54.752220096 +0200 >> +++ libstdc++-v3/testsuite/std/format/lwg3975.cc 2026-07-15 >> 13:06:25.909738675 +0200 >> @@ -0,0 +1,18 @@ >> +// { dg-do compile { target c++20 } } >> + >> +// LWG 3975. Specializations of basic_format_context should not be permitted >> + >> +#include <format> >> + >> +struct A {}; >> +template<typename T> >> +struct B {}; >> + >> +template<> >> +class std::basic_format_parse_context<A> {}; // { dg-error "cannot be >> specialized: 'explicit or partial specialization of >> std::basic_format_parse_context'" } >> + >> +template<> >> +class std::basic_format_context<std::back_insert_iterator<std::string>, A> >> {}; // { dg-error "cannot be specialized: 'explicit or partial >> specialization of std::basic_format_context'" } >> + >> +template<typename T> >> +class std::basic_format_context<B<T>, T> {}; // { dg-error "cannot be >> specialized: 'explicit or partial specialization of >> std::basic_format_context'" } >> --- libstdc++-v3/testsuite/20_util/tuple/lwg3990.cc.jj 2026-07-15 >> 13:18:53.806168876 +0200 >> +++ libstdc++-v3/testsuite/20_util/tuple/lwg3990.cc 2026-07-15 >> 13:20:38.915822255 +0200 >> @@ -0,0 +1,16 @@ >> +// { dg-do compile { target c++11 } } >> + >> +// LWG 3990. Program-defined specializations of std::tuple and std::variant >> +// can't be properly supported >> + >> +#include <tuple> >> + >> +struct A {}; >> +template<typename T> >> +struct B {}; >> + >> +template<> >> +class std::tuple<A, A> {}; // { dg-error "cannot be specialized: >> 'explicit or partial specialization of std::tuple'" } >> + >> +template<typename T> >> +class std::tuple<B<T>, T> {}; // { dg-error "cannot be specialized: >> 'explicit or partial specialization of std::tuple'" } >> --- libstdc++-v3/testsuite/20_util/variant/lwg3990.cc.jj 2026-07-15 >> 13:18:57.962115630 +0200 >> +++ libstdc++-v3/testsuite/20_util/variant/lwg3990.cc 2026-07-15 >> 13:21:06.574467909 +0200 >> @@ -0,0 +1,16 @@ >> +// { dg-do compile { target c++11 } } >> + >> +// LWG 3990. Program-defined specializations of std::tuple and std::variant >> +// can't be properly supported >> + >> +#include <variant> >> + >> +struct A {}; >> +template<typename T> >> +struct B {}; >> + >> +template<> >> +class std::variant<A, A> {}; // { dg-error "cannot be specialized: >> 'explicit or partial specialization of std::variant'" } >> + >> +template<typename T> >> +class std::variant<B<T>, T> {}; // { dg-error "cannot be >> specialized: 'explicit or partial specialization of std::variant'" } >> >> Jakub >>
