On Fri, 6 Mar 2026 at 13:41, Jonathan Wakely <[email protected]> wrote: > > On Fri, 6 Mar 2026 at 13:37, Jonathan Wakely <[email protected]> wrote: > > > > On Fri, 6 Mar 2026 at 12:44, Nathan Myers <[email protected]> wrote: > > > > > > [Work-in-progress, posting to verify direction.] > > > > > > Implement P0401R6, "Providing size feedback in the Allocator > > > interface". > > > > > > libstdc++-v3/ChangeLog: > > > PR libstdc++/118030 > > > * include/bits/alloc_traits.h (allocate_at_least, > > > allocation_result, > > > __at_least_result, __complete_type_allocator): Define. > > > * include/bits/allocator.h (allocate_at_least): Define. > > > * include/std/memory (__glibcxx_want_allocate_at_least): Define. > > > * include/bits/version.def (allocate_at_least): Add. > > > * include/bits/version.h: Regenerate. > > > * testsuite/20_util/allocator/allocate_at_least.cc: New test. > > > * testsuite/20_util/allocator/allocate_at_least_neg.cc: New test. > > > --- > > > libstdc++-v3/include/bits/alloc_traits.h | 27 +++++++++++++++ > > > libstdc++-v3/include/bits/allocator.h | 6 ++++ > > > libstdc++-v3/include/bits/version.def | 8 +++++ > > > libstdc++-v3/include/bits/version.h | 10 ++++++ > > > libstdc++-v3/include/std/memory | 1 + > > > .../20_util/allocator/allocate_at_least.cc | 34 +++++++++++++++++++ > > > .../allocator/allocate_at_least_neg.cc | 22 ++++++++++++ > > > 7 files changed, 108 insertions(+) > > > create mode 100644 > > > libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc > > > create mode 100644 > > > libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc > > > > > > diff --git a/libstdc++-v3/include/bits/alloc_traits.h > > > b/libstdc++-v3/include/bits/alloc_traits.h > > > index c34143a3526..943bf03cc5a 100644 > > > --- a/libstdc++-v3/include/bits/alloc_traits.h > > > +++ b/libstdc++-v3/include/bits/alloc_traits.h > > > @@ -548,6 +548,33 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > }; > > > #pragma GCC diagnostic pop > > > > > > +#ifdef __glibcxx_lib_allocate_at_least // C++23 > > > + template <typename _Pointer> > > > + struct allocation_result > > > + { > > > + _Pointer ptr; > > > + size_t count; > > > > The working draft has a SizeType parameter too: > > > > template<class Pointer, class SizeType = size_t> > > struct allocation_result { > > Pointer ptr; > > SizeType count; > > }; > > > > > > > + }; > > > + > > > + template <typename _Alloc> > > > + using __at_least_result = > > > + allocation_result<typename allocator_traits<_Alloc>::pointer>; > > > + > > > + template <typename _Alloc> > > > + concept __complete_type_allocator = > > > + requires { sizeof(typename allocator_traits<_Alloc>::value_type); > > > }; > > > + > > > + template <__complete_type_allocator _Alloc> > > > + [[nodiscard]] constexpr __at_least_result<_Alloc> > > > + allocate_at_least(_Alloc& __a, size_t __n) > > > + { > > > + if constexpr (requires { __a.allocate_at_least(__n); }) > > > + return __a.allocate_at_least(__n); > > > + else > > > + return { __a.allocate(__n), __n }; > > > + } > > And this was moved to be a member function of allocator_traits by some > LWG issue.
Actually it was part of https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2023/p2652r2.html not an LWG issue. > > Make sure you're implementing the working draft, not just the original > proposal from 2021. > > > > > +#endif > > > + > > > #if _GLIBCXX_HOSTED > > > /** > > > * @brief Partial specialization for `std::allocator` > > > diff --git a/libstdc++-v3/include/bits/allocator.h > > > b/libstdc++-v3/include/bits/allocator.h > > > index 9f9526bd5b0..9c246b77d93 100644 > > > --- a/libstdc++-v3/include/bits/allocator.h > > > +++ b/libstdc++-v3/include/bits/allocator.h > > > @@ -203,6 +203,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION > > > return __allocator_base<_Tp>::allocate(__n, 0); > > > } > > > > > > +#ifdef __glibcxx_allocate_at_least // C++23 > > > + [[nodiscard]] constexpr allocation_result<_Tp*> > > > + allocate_at_least(size_t __n) > > > + { return { allocate(__n), __n }; } > > > +#endif > > > + > > > [[__gnu__::__always_inline__]] > > > constexpr void > > > deallocate(_Tp* __p, size_t __n) > > > diff --git a/libstdc++-v3/include/bits/version.def > > > b/libstdc++-v3/include/bits/version.def > > > index dbe95b8b79f..ecd3315d8a3 100644 > > > --- a/libstdc++-v3/include/bits/version.def > > > +++ b/libstdc++-v3/include/bits/version.def > > > @@ -88,6 +88,14 @@ ftms = { > > > }; > > > }; > > > > > > +ftms = { > > > + name = allocate_at_least; > > > + values = { > > > + v = 202106; > > > + cxxmin = 23; > > > + }; > > > +}; > > > + > > > ftms = { > > > name = is_null_pointer; > > > values = { > > > diff --git a/libstdc++-v3/include/bits/version.h > > > b/libstdc++-v3/include/bits/version.h > > > index eee99847490..f0d9a0010ab 100644 > > > --- a/libstdc++-v3/include/bits/version.h > > > +++ b/libstdc++-v3/include/bits/version.h > > > @@ -80,6 +80,16 @@ > > > #endif /* !defined(__cpp_lib_allocator_traits_is_always_equal) */ > > > #undef __glibcxx_want_allocator_traits_is_always_equal > > > > > > +#if !defined(__cpp_lib_allocate_at_least) > > > +# if (__cplusplus >= 202100L) > > > +# define __glibcxx_allocate_at_least 202106L > > > +# if defined(__glibcxx_want_all) || > > > defined(__glibcxx_want_allocate_at_least) > > > +# define __cpp_lib_allocate_at_least 202106L > > > +# endif > > > +# endif > > > +#endif /* !defined(__cpp_lib_allocate_at_least) */ > > > +#undef __glibcxx_want_allocate_at_least > > > + > > > #if !defined(__cpp_lib_is_null_pointer) > > > # if (__cplusplus >= 201103L) > > > # define __glibcxx_is_null_pointer 201309L > > > diff --git a/libstdc++-v3/include/std/memory > > > b/libstdc++-v3/include/std/memory > > > index c9c9224e599..cbe9f5ad200 100644 > > > --- a/libstdc++-v3/include/std/memory > > > +++ b/libstdc++-v3/include/std/memory > > > @@ -125,6 +125,7 @@ > > > #define __glibcxx_want_to_address > > > #define __glibcxx_want_transparent_operators > > > #define __glibcxx_want_smart_ptr_owner_equality > > > +#define __glibcxx_want_allocate_at_least > > > #include <bits/version.h> > > > > > > #if __cplusplus >= 201103L && __cplusplus <= 202002L && _GLIBCXX_HOSTED > > > diff --git > > > a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc > > > b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc > > > new file mode 100644 > > > index 00000000000..317e7518c35 > > > --- /dev/null > > > +++ b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc > > > @@ -0,0 +1,34 @@ > > > +// { dg-do run { target c++23 } } > > > + > > > +#include <memory> > > > +#include <testsuite_hooks.h> > > > + > > > +template <typename T> > > > + struct A : std::allocator<T> > > > + { > > > + using Base = std::allocator<T>; > > > + > > > + std::allocation_result<T*> > > > + allocate_at_least(std::size_t n) > > > + { return { Base::allocate(2*n), 2*n }; } > > > + }; > > > + > > > +int main() > > > +{ > > > + std::allocator<char> native; > > > + auto a1 = native.allocate_at_least(100); > > > + static_assert(std::is_same_v<decltype(a1), > > > std::allocation_result<char*>>); > > > + > > > + auto a2 = std::allocate_at_least<char*>(native, 100); > > > + static_assert(std::is_same_v<decltype(a2), > > > std::allocation_result<char*>>); > > > + > > > + A<char> custom; > > > + auto a3 = std::allocate_at_least<char*>(custom, 100); > > > + static_assert(std::is_same_v<decltype(a3), > > > std::allocation_result<char*>>); > > > + VERIFY(a1.count == 100); > > > + VERIFY(a2.count == 100); > > > + VERIFY(a3.count == 200); > > > + custom.deallocate(a3.ptr, a3.count); > > > + native.deallocate(a2.ptr, a2.count); > > > + native.deallocate(a1.ptr, a1.count); > > > +} > > > diff --git > > > a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc > > > b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc > > > new file mode 100644 > > > index 00000000000..a377c758b47 > > > --- /dev/null > > > +++ b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least_neg.cc > > > @@ -0,0 +1,22 @@ > > > +// { dg-do compile { target c++23 } } > > > + > > > +#include <memory> > > > +#include <testsuite_hooks.h> > > > + > > > +template <typename T> > > > + struct A : std::allocator<T> > > > + { > > > + using Base = std::allocator<T>; > > > + > > > + std::allocation_result<T*> > > > + allocate_at_least(std::size_t n) > > > + { return { Base::allocate(2*n), 2*n }; } > > > + }; > > > + > > > +struct incomplete; > > > + > > > +int main() > > > +{ > > > + A<incomplete> custom; > > > + auto a3 = std::allocate_at_least<char*>(custom, 100); // { dg-error "" > > > } > > > +} > > > -- > > > 2.52.0 > > >
