[PATCH] libstdc++: Use _Clang::__no_specializations__ attribute in a few spots [PR120635]
Jonathan Wakely
jwakely@redhat.com
Wed Jul 15 14:47:55 GMT 2026
On Wed, 15 Jul 2026 at 13:44 +0200, Jakub Jelinek 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.
>
>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.)
>6) P3019R14 - std::indirect (ditto)
>7) P0912R5 - std::coroutine_handle (ditto)
>
>Anything else I'm missing?
>
>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 <jakub@redhat.com>
>
> 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
I wonder if we should do:
#if __has_cpp_attribute(_Clang::__no_specializations__)
# define _GLIBCXX_NO_SPECIALIZATIONS(T) \
[[_Clang::__no_specializations__ ("explicit or partial specialization of std::" \
#T)]] T
#else
# define _GLIBCXX_NO_SPECIALIZATIONS(T) T
#endif
And then we would not have to repeat the type:
class _GLIBCXX_NO_SPECIALIZATIONS(tuple) {
But that's minor and could be changed later.
>+
> // 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"
Does this need '#pragma clang diagnostic' as well?
> // 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
>
>
More information about the Libstdc++
mailing list