]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Use _Clang::__no_specializations__ attribute in a few spots [PR120635]
authorJakub Jelinek <jakub@redhat.com>
Thu, 16 Jul 2026 07:51:48 +0000 (09:51 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Thu, 16 Jul 2026 07:51:48 +0000 (09:51 +0200)
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
4) LWG2129 - std::initializer_list
This assumes all those issues were handled as defect reports.

What I haven't touched, but has similar wording:
5) P2652R2 - std::allocator_traits
6) P3019R14 - std::indirect
7) P0912R5 - std::coroutine_handle
8) LWG4535 - <simd>

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

2026-07-16  Jakub Jelinek  <jakub@redhat.com>

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.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
libstdc++-v3/include/bits/c++config
libstdc++-v3/include/std/format
libstdc++-v3/include/std/tuple
libstdc++-v3/include/std/variant
libstdc++-v3/libsupc++/compare
libstdc++-v3/libsupc++/initializer_list
libstdc++-v3/testsuite/18_support/comparisons/type_order/lwg4305.cc [new file with mode: 0644]
libstdc++-v3/testsuite/18_support/initializer_list/lwg2129.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/tuple/lwg3990.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/variant/lwg3990.cc [new file with mode: 0644]
libstdc++-v3/testsuite/std/format/lwg3975.cc [new file with mode: 0644]

index e23d9dd3c9d068bbb598ceb0f135eb32c9ee7545..60456a48681efae8ed975c81873a20aa963a9ced 100644 (file)
@@ -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 \
index 9bf5e78573b531c015b8500cea51dcb792f76c00..729cb89ec600166d0458de48e6c593585d68b2ad 100644 (file)
@@ -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;
@@ -5014,7 +5016,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&> );
 
index 64b96fe4f599c4679a97945cf0e89d730b24ca3e..63b4010c0b5e8b08af34274470aab4dd897ee3b4 100644 (file)
@@ -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>
index 55568ee913e13cc4694cf4834bd565670b3b653a..6e1388363caa8fba614ebc8d1a740bb50b899c02 100644 (file)
@@ -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,
index 3847d0fb141d831dde4dff98e46094387c6cab32..797e11df55e851ce4bb5cedbf8b5c8573e978b50 100644 (file)
@@ -1267,7 +1267,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
   /// @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;
index fbea49dfb012af50a57a3f6b89703dab9d1839fa..5e164bec42e07c75d0d8f37b6ec9fa9fae0353d7 100644 (file)
@@ -47,7 +47,9 @@ namespace std _GLIBCXX_VISIBILITY(default)
 {
   /// 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;
diff --git a/libstdc++-v3/testsuite/18_support/comparisons/type_order/lwg4305.cc b/libstdc++-v3/testsuite/18_support/comparisons/type_order/lwg4305.cc
new file mode 100644 (file)
index 0000000..4a49d57
--- /dev/null
@@ -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" }
diff --git a/libstdc++-v3/testsuite/18_support/initializer_list/lwg2129.cc b/libstdc++-v3/testsuite/18_support/initializer_list/lwg2129.cc
new file mode 100644 (file)
index 0000000..375f874
--- /dev/null
@@ -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;
+};
diff --git a/libstdc++-v3/testsuite/20_util/tuple/lwg3990.cc b/libstdc++-v3/testsuite/20_util/tuple/lwg3990.cc
new file mode 100644 (file)
index 0000000..d104420
--- /dev/null
@@ -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" }
diff --git a/libstdc++-v3/testsuite/20_util/variant/lwg3990.cc b/libstdc++-v3/testsuite/20_util/variant/lwg3990.cc
new file mode 100644 (file)
index 0000000..eab23c7
--- /dev/null
@@ -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" }
diff --git a/libstdc++-v3/testsuite/std/format/lwg3975.cc b/libstdc++-v3/testsuite/std/format/lwg3975.cc
new file mode 100644 (file)
index 0000000..4703871
--- /dev/null
@@ -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" }