On Wed, Jul 15, 2026 at 06:45:30PM +0200, Jakub Jelinek wrote:
> On Wed, Jul 15, 2026 at 05:00:03PM +0100, Jonathan Wakely wrote:
> > So we could just use an object-like macro instead of a function-like macro:
> >
> > template<typename...> struct _GLIBCXX_NO_SPECIALIZATIONS tuple {
>
> If you are fine with the default warning when no_specialization doesn't
> have argument, so just
> error: '...' cannot be specialized
> then sure. Will adjust the patch.
Here is the updated patch with object-like macro instead, and no argument
to the attribute.
I've also added LWG2129 (initializer_list) stuff because PR119561 clearly
shows there is some missing case (I was trying explicit specialization
and that was rejected, but partial specialization might not if it declares
the expected NSDMs).
2026-07-15 Jakub Jelinek <[email protected]>
PR c++/119561
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.
* libsupc++/initializer_list (std::initializer_list): Use it to
resolve LWG2129.
* 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/18_support/initializer_list/lwg2129.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,12 @@ namespace __gnu_cxx
# define _GLIBCXX_USE_BUILTIN_TRAIT(BT) 0
#endif
+#if __has_cpp_attribute(_Clang::__no_specializations__)
+# define _GLIBCXX_NO_SPECIALIZATIONS [[_Clang::__no_specializations__]]
+#else
+# define _GLIBCXX_NO_SPECIALIZATIONS
+#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 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,9 @@ 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 basic_format_parse_context
{
public:
using char_type = _CharT;
@@ -5015,7 +5017,9 @@ 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 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 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 type_order
{
static constexpr strong_ordering value = __builtin_type_order(_Tp, _Up);
using value_type = strong_ordering;
--- libstdc++-v3/libsupc++/initializer_list.jj 2026-05-25 11:49:03.153901251
+0200
+++ libstdc++-v3/libsupc++/initializer_list 2026-07-15 18:57:27.735630582
+0200
@@ -47,7 +47,9 @@ namespace std _GLIBCXX_VISIBILITY(defaul
{
/// initializer_list
template<class _E>
- class initializer_list
+ // _GLIBCXX_RESOLVE_LIB_DEFECTS
+ // 2129. User specializations of std::initializer_list
+ class _GLIBCXX_NO_SPECIALIZATIONS initializer_list
{
public:
typedef _E value_type;
--- 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" }
+
+template<typename T>
+struct std::type_order<B<T>, T> {}; // { dg-error "cannot be
specialized" }
--- libstdc++-v3/testsuite/18_support/initializer_list/lwg2129.cc.jj
2026-07-15 18:58:11.052086039 +0200
+++ libstdc++-v3/testsuite/18_support/initializer_list/lwg2129.cc
2026-07-15 19:06:40.875676889 +0200
@@ -0,0 +1,12 @@
+// { dg-do compile { target c++11 } }
+
+// LWG 2129. User specializations of std::initializer_list
+
+#include <initializer_list>
+
+template<class T>
+class std::initializer_list<T*> { // { dg-error "cannot be specialized" }
+private:
+ void* array;
+ decltype(sizeof(0)) len;
+};
--- 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" }
+
+template<>
+class std::basic_format_context<std::back_insert_iterator<std::string>, A> {};
// { dg-error "cannot be specialized" }
+
+template<typename T>
+class std::basic_format_context<B<T>, T> {}; // { dg-error "cannot be
specialized" }
--- 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" }
+
+template<typename T>
+class std::tuple<B<T>, T> {}; // { dg-error "cannot be specialized" }
--- 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" }
+
+template<typename T>
+class std::variant<B<T>, T> {}; // { dg-error "cannot be specialized" }
Jakub