[PATCH] libstdc++: Reject user-defined specializations for allocator traits.

Jonathan Wakely jwakely@redhat.com
Fri Jul 31 12:58:07 GMT 2026


On Fri, 31 Jul 2026 at 13:56, Tomasz Kamiński <tkaminsk@redhat.com> wrote:
>
> Mark 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.
> ---
> Went for _GLIBCXX_NO_ALLOC_TRAITS_SPECIALIZATIONS defined locally,
> instead of something akin _GLIBCXX23_NO_SPECIALIZATIONS, as I do not
> think we will have many conditionally enabled attributes.

Yes, that makes sense to me.

>
> Tested on x86_64-linux locally. OK for trunk?

OK thanks.

>
>  libstdc++-v3/include/bits/alloc_traits.h      | 15 ++++++++++++++-
>  libstdc++-v3/include/bits/memory_resource.h   |  4 ++++
>  .../requirements/specializations_neg.cc       | 19 +++++++++++++++++++
>  3 files changed, 37 insertions(+), 1 deletion(-)
>  create mode 100644 libstdc++-v3/testsuite/20_util/allocator_traits/requirements/specializations_neg.cc
>
> diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h
> index 101badff454..c113f798690 100644
> --- a/libstdc++-v3/include/bits/alloc_traits.h
> +++ b/libstdc++-v3/include/bits/alloc_traits.h
> @@ -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
> diff --git a/libstdc++-v3/include/bits/memory_resource.h b/libstdc++-v3/include/bits/memory_resource.h
> index a9db58b76a3..801184c1bbc 100644
> --- a/libstdc++-v3/include/bits/memory_resource.h
> +++ b/libstdc++-v3/include/bits/memory_resource.h
> @@ -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
> index 00000000000..1a46d8793f0
> --- /dev/null
> +++ b/libstdc++-v3/testsuite/20_util/allocator_traits/requirements/specializations_neg.cc
> @@ -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 }
> --
> 2.55.0
>



More information about the Libstdc++ mailing list