]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: Reject user-defined specializations for allocator traits.
authorTomasz Kamiński <tkaminsk@redhat.com>
Wed, 29 Jul 2026 10:14:39 +0000 (12:14 +0200)
committerTomasz Kamiński <tkaminsk@redhat.com>
Fri, 31 Jul 2026 13:12:59 +0000 (15:12 +0200)
Marks allocator_traits primary tempalte with [[_Clang::__no_specializations]]
attribute in C++23 or later.

This is QoI improvement for C++23 P2652R2, "Disallow User Specialization
of allocator_traits", that makes such cases ill-formed, but does not
require diagnostic.

libstdc++-v3/ChangeLog:

* include/bits/alloc_traits.h
(_GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS): Define locally.
(std::allocator_traits) [__cplusplus > 202002L]: Add
clang::no_specializations attribute.
(std::allocator_traits<allocator<_Tp>>)
(std::allocator_traits<allocator<void>>): Locally ignore
-Winvalid-specialization warnings.
* include/bits/memory_resource.h
(allocator_traits<pmr::polymorphic_allocator<_Tp>>): Likewise.
* testsuite/20_util/allocator_traits/requirements/specializations_neg.cc:
New test.

Reviewed-by: Jonathan Wakely <jwakely@redhat.com>
Signed-off-by: Tomasz Kamiński <tkaminsk@redhat.com>
libstdc++-v3/include/bits/alloc_traits.h
libstdc++-v3/include/bits/memory_resource.h
libstdc++-v3/testsuite/20_util/allocator_traits/requirements/specializations_neg.cc [new file with mode: 0644]

index 101badff45492578b2623d28b2824086095a9ef0..c113f798690d360d2853705608501d2c98117d08 100644 (file)
@@ -239,6 +239,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       = typename __allocator_traits_base::template __rebind<_Alloc, _Up>::type;
   /// @endcond
 
+#if __cplusplus > 202002L
+# define _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS _GLIBCXX_NO_SPECIALIZATIONS
+#else
+# define _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS
+#endif
+
   /**
    * @brief  Uniform interface to all allocator types.
    * @headerfile memory
@@ -246,7 +252,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
    * @since C++11
   */
   template<typename _Alloc>
-    struct allocator_traits : __allocator_traits_base
+    struct _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS allocator_traits
+    : __allocator_traits_base
     {
       /// The allocator type
       typedef _Alloc allocator_type;
@@ -571,7 +578,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
     };
 #pragma GCC diagnostic pop
 
+#undef _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS
+
 #if _GLIBCXX_HOSTED
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
   /**
    * @brief  Partial specialization for `std::allocator`
    * @headerfile memory
@@ -876,6 +888,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
       select_on_container_copy_construction(const allocator_type& __rhs)
       { return __rhs; }
     };
+#pragma GCC diagnostic pop
 #endif // _GLIBCXX_HOSTED
 
   /// @cond undocumented
index a9db58b76a342aba7b48675453b4a5a796c14961..801184c1bbc63ea360ae2b045e5c77643624948a 100644 (file)
@@ -388,6 +388,9 @@ namespace pmr
 
   template<typename _Alloc> struct allocator_traits;
 
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Winvalid-specialization"
+
   /// Partial specialization for `std::pmr::polymorphic_allocator`
   /**
    * @ingroup pmr
@@ -534,6 +537,7 @@ namespace pmr
       max_size(const allocator_type&) noexcept
       { return size_t(-1) / sizeof(value_type); }
     };
+#pragma GCC diagnostic pop
 
 _GLIBCXX_END_NAMESPACE_VERSION
 } // namespace std
diff --git a/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/specializations_neg.cc b/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/specializations_neg.cc
new file mode 100644 (file)
index 0000000..1a46d87
--- /dev/null
@@ -0,0 +1,19 @@
+// { dg-do compile { target c++11 } }
+
+#include <memory>
+
+template<typename T> struct Alloc : std::allocator<T>
+{
+  template<typename U>
+  struct rebind { using other = Alloc<U>; };
+};
+
+template<typename T>
+struct std::allocator_traits<Alloc<T>> // { dg-error "cannot be specialized" "" { target c++23 } }
+{};
+
+template<>
+struct std::allocator_traits<Alloc<void>> // { dg-error "cannot be specialized" "" { target c++23 } }
+{};
+
+// { dg-bogus "cannot be specialized" "" { target c++20_down } 0 }