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
>>

Reply via email to