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