[{"id":3673398,"web_url":"http://patchwork.ozlabs.org/comment/3673398/","msgid":"<CAH6eHdSFKCuFErEantMBHLyYZ4QOu3UCTHf8-8fsi6_JEuvboQ@mail.gmail.com>","list_archive_url":null,"date":"2026-04-04T07:14:00","subject":"Re: [RFC] libstdc++: Use allocate_at_least in vector,\n string (P0401) [PR118030]","submitter":{"id":4329,"url":"http://patchwork.ozlabs.org/api/people/4329/","name":"Jonathan Wakely","email":"jwakely.gcc@gmail.com"},"content":"On Sat, 4 Apr 2026, 06:03 Nathan Myers, <ncm@cantrip.org> wrote:\n\n>  - Implement as much of allocator<>::allocate_at_least as is\n>   possible relying solely on known alignment behavior of\n>   standard operator new.\n>  - Use allocator_at_least in string and vector to maximize usage\n>   of actually allocated storage, so far as is known.\n>\n> Defines and uses {string,vector}::_Alloc_result for all c++-*,\n> to reduce churn, actually calling allocate_at_least only where\n> defined. User-defined allocators can implement larger benefits,\n> and string and vector will take full advantage.\n>\n> To do: Add tests; Fix constexpr test failures; By detecting\n> whether ::operator new has been replaced, we may rely on details\n> of our allocator implementation.\n>\n> libstdc++-v3/ChangeLog:\n>         PR libstdc++/118030\n>         * include/bits/alloc_traits.h (allocate_at_least): Call\n>         __a.allocate_at_least only if it exists.\n>         * include/bits/allocator.h (allocate_at_least): Remove.\n>         * include/bits/basic_string.h (_Alloc_result): Define.\n>         (_S_allocate): Delete.\n>         (_S_allocate_at_least): Define.\n>         (assign): Use _S_allocate_at_least.\n>         * include/bits/basic_string.tcc (_M_create, reserve, _M_replace):\n>         Use _S_allocate_at_least.\n>         * include/bits/memory_resource.h (allocate_at_least): Define.\n>         * include/bits/new_allocator.h (allocate_at_least): Define.\n>         * include/bits/stl_vector.h (_S_max_size): Move to _Vector_base.\n>         (_M_allocate): Remove.\n>         (_M_allocate_at_least): Define.\n>         (_Alloc_result): Define.\n>         (max_size, _S_check_init_len): Use _S_max_size as moved.\n>         (_M_create_storage, append_range, _M_allocate_and_copy,\n>         _M_initialize_dispatch, _M_range_initialize): Use\n> _M_allocate_at_least.\n>         (_M_check_len): Improve logic.\n>         * include/bits/vector.tcc (reserve, _M_realloc_insert,\n>         _M_realloc_append, _M_fill_insert, _M_fill_append,\n> _M_default_append,\n>         _M_range_insert, insert_range): Use _M_allocate_at_least.\n>         * include/std/string: Define __glibcxx_want_allocate_at_least.\n>         * include/std/vector: Same.\n>         * testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc:\n>         * testsuite/util/testsuite_allocator.h (allocate_at_least (2x)):\n> Define.\n>         (allocate): Use allocate_at_least.\n> ---\n>  libstdc++-v3/include/bits/alloc_traits.h      |  9 +-\n>  libstdc++-v3/include/bits/allocator.h         |  6 --\n>  libstdc++-v3/include/bits/basic_string.h      | 24 +++--\n>  libstdc++-v3/include/bits/basic_string.tcc    | 17 ++--\n>  libstdc++-v3/include/bits/memory_resource.h   | 16 ++++\n>  libstdc++-v3/include/bits/new_allocator.h     | 43 +++++++++\n>  libstdc++-v3/include/bits/stl_vector.h        | 95 ++++++++++++-------\n>  libstdc++-v3/include/bits/vector.tcc          | 66 ++++++++-----\n>  libstdc++-v3/include/std/string               |  1 +\n>  libstdc++-v3/include/std/vector               |  1 +\n>  .../basic_string/cons/wchar_t/constexpr.cc    |  2 +-\n>  .../testsuite/util/testsuite_allocator.h      | 40 ++++++++\n>  12 files changed, 239 insertions(+), 81 deletions(-)\n>\n> diff --git a/libstdc++-v3/include/bits/alloc_traits.h\n> b/libstdc++-v3/include/bits/alloc_traits.h\n> index 2be8ed561d4..b773be365bc 100644\n> --- a/libstdc++-v3/include/bits/alloc_traits.h\n> +++ b/libstdc++-v3/include/bits/alloc_traits.h\n> @@ -419,7 +419,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>        */\n>        [[nodiscard]] static constexpr auto\n>        allocate_at_least(_Alloc& __a, size_type __n)\n> -       -> allocation_result<pointer, size_type>\n> +      -> allocation_result<pointer, size_type>\n>        {\n>         if constexpr (requires { __a.allocate_at_least(__n); })\n>           return __a.allocate_at_least(__n);\n> @@ -672,7 +672,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>        [[nodiscard]] static constexpr auto\n>        allocate_at_least(allocator_type __a, size_type __n)\n>         -> allocation_result<pointer, size_type>\n> -      { return __a.allocate_at_least(__n); }\n> +      {\n> +       if constexpr(requires { __a.__allocate_at_least(__n); })\n> +         return __a.allocate_at_least(__n);\n> +       else\n> +         return { __a.allocate(__n), __n };\n> +      }\n>  #endif\n>\n>        /**\n> diff --git a/libstdc++-v3/include/bits/allocator.h\n> b/libstdc++-v3/include/bits/allocator.h\n> index 9c22c805ebe..ec160f44a1e 100644\n> --- a/libstdc++-v3/include/bits/allocator.h\n> +++ b/libstdc++-v3/include/bits/allocator.h\n> @@ -219,12 +219,6 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>        }\n>  #endif // C++20\n>\n> -#ifdef __glibcxx_allocate_at_least  // C++23\n> -      [[nodiscard]] constexpr allocation_result<_Tp*, size_t>\n> -      allocate_at_least(size_t __n)\n> -      { return { this->allocate(__n), __n }; }\n> -#endif\n>\n\n\nThe standard requires this to exist, so if you move it to the base class\nyou need to implement it in all the possible base classes:\nmalloc_allocator, bitmap_allocator, etc.\n\nAlternatively, keep it here, but use a requires expression to see if it's\npresent in the base class, and either call base::allocate_at_least or\nbase::allocate.\n\n\n-\n>        friend __attribute__((__always_inline__)) _GLIBCXX20_CONSTEXPR\n>        bool\n>        operator==(const allocator&, const allocator&) _GLIBCXX_NOTHROW\n> diff --git a/libstdc++-v3/include/bits/basic_string.h\n> b/libstdc++-v3/include/bits/basic_string.h\n> index 202a911f9ef..09a87d27910 100644\n> --- a/libstdc++-v3/include/bits/basic_string.h\n> +++ b/libstdc++-v3/include/bits/basic_string.h\n> @@ -135,10 +135,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n>  #endif\n>\n>      private:\n> -      static _GLIBCXX20_CONSTEXPR pointer\n> -      _S_allocate(_Char_alloc_type& __a, size_type __n)\n>\n\nRemoving this function will break ABI.\n\nI think it needs to be kept, even if it is no longer used.\n\n\n+      struct _Alloc_result { pointer __ptr; size_type __count; };\n> +\n> +      static _GLIBCXX20_CONSTEXPR _Alloc_result\n> +      _S_allocate_at_least(_Char_alloc_type& __a, size_type __n)\n>        {\n> -       pointer __p = _Alloc_traits::allocate(__a, __n);\n> +       _Alloc_result __r;\n> +#ifdef __glibcxx_allocate_at_least  // C++23\n> +       auto [__ptr, __count] = _Alloc_traits::allocate_at_least(__a, __n);\n> +       __r.__ptr = __ptr, __r.__count = __count;\n> +#else\n> +       __r.__ptr = _Alloc_traits::allocate(__a, __n), __r.__count = __n;\n> +#endif\n>  #if __glibcxx_constexpr_string >= 201907L\n>         // std::char_traits begins the lifetime of characters,\n>         // but custom traits might not, so do it here.\n> @@ -146,9 +154,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n>           if (std::__is_constant_evaluated())\n>             // Begin the lifetime of characters in allocated storage.\n>             for (size_type __i = 0; __i < __n; ++__i)\n> -             std::construct_at(__builtin_addressof(__p[__i]));\n> +             std::construct_at(__builtin_addressof(__r.__ptr[__i]));\n>\n\nDo we need to begin the lifetime of all characters up to r.count, not only\nup to n?\n\n\n #endif\n> -       return __p;\n> +       return __r;\n>        }\n>\n>  #ifdef __glibcxx_string_view // >= C++17\n> @@ -1782,10 +1790,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n>                     const auto __len = __str.size();\n>                     auto __alloc = __str._M_get_allocator();\n>                     // If this allocation throws there are no effects:\n> -                   auto __ptr = _S_allocate(__alloc, __len + 1);\n> +                   auto __r = _S_allocate_at_least(__alloc, __len + 1);\n>                     _M_destroy(_M_allocated_capacity);\n> -                   _M_data(__ptr);\n> -                   _M_capacity(__len);\n> +                   _M_data(__r.__ptr);\n> +                   _M_capacity(__r.__count);\n>                     _M_set_length(__len);\n>                   }\n>               }\n> diff --git a/libstdc++-v3/include/bits/basic_string.tcc\n> b/libstdc++-v3/include/bits/basic_string.tcc\n> index a223edf67ac..c56b214a3fd 100644\n> --- a/libstdc++-v3/include/bits/basic_string.tcc\n> +++ b/libstdc++-v3/include/bits/basic_string.tcc\n> @@ -161,7 +161,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n>        // NB: Need an array of char_type[__capacity], plus a terminating\n>        // null char_type() element.\n> -      return _S_allocate(_M_get_allocator(), __capacity + 1);\n> +      _Alloc_result __r = _S_allocate_at_least(\n> +       _M_get_allocator(), __capacity + 1);\n> +      __capacity = __r.__count - 1;\n> +      return __r.__ptr;\n>      }\n>\n>    // NB: This is the special case for Input Iterators, used in\n> @@ -444,11 +447,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>        else if (__length < __capacity)\n>         try\n>           {\n> -           pointer __tmp = _S_allocate(_M_get_allocator(), __length + 1);\n> -           this->_S_copy(__tmp, _M_data(), __length + 1);\n> +           _Alloc_result __r = _S_allocate_at_least(\n> +             _M_get_allocator(), __length + 1);\n> +           this->_S_copy(__r.__ptr, _M_data(), __length + 1);\n>             _M_dispose();\n> -           _M_data(__tmp);\n> -           _M_capacity(__length);\n> +           _M_data(__r.__ptr);\n> +           _M_capacity(__r.__count - 1);  // reserve room for NUL.\n>           }\n>         catch (const __cxxabiv1::__forced_unwind&)\n>           { throw; }\n> @@ -588,7 +592,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>  #if __cpp_lib_is_constant_evaluated\n>           if (std::is_constant_evaluated())\n>             {\n> -             auto __newp = _S_allocate(_M_get_allocator(), __new_size);\n> +             auto __newp =\n> +               _S_allocate_at_least(_M_get_allocator(), __new_size).__ptr;\n>               _S_copy(__newp, this->_M_data(), __pos);\n>               _S_copy(__newp + __pos, __s, __len2);\n>               _S_copy(__newp + __pos + __len2, __p + __len1, __how_much);\n> diff --git a/libstdc++-v3/include/bits/memory_resource.h\n> b/libstdc++-v3/include/bits/memory_resource.h\n> index e5c6697b07e..ee3872e2bcd 100644\n> --- a/libstdc++-v3/include/bits/memory_resource.h\n> +++ b/libstdc++-v3/include/bits/memory_resource.h\n> @@ -468,6 +468,22 @@ namespace pmr\n>        allocate(allocator_type& __a, size_type __n, const_void_pointer)\n>        { return __a.allocate(__n); }\n>\n> +#ifdef __glibcxx_allocate_at_least\n> +      /**\n> +       *  @brief  Allocate memory, generously.\n> +       *  @param  __a  An allocator.\n> +       *  @param  __n  The number of objects to allocate space for.\n> +       *  @return Memory of suitable size and alignment for `n` objects\n> +       *          of type `value_type`.\n> +       *\n> +       *  Returns `a.allocate(n)`.\n> +      */\n> +      [[nodiscard]] static auto\n> +      allocate_at_least(allocator_type& __a, size_type __n)\n> +       -> std::allocation_result<pointer, size_type>\n> +      { return { __a.allocate(__n), __n }; }\n> +#endif\n> +\n>        /**\n>         *  @brief  Deallocate memory.\n>         *  @param  __a  An allocator.\n> diff --git a/libstdc++-v3/include/bits/new_allocator.h\n> b/libstdc++-v3/include/bits/new_allocator.h\n> index fbe03e392aa..13018036e3a 100644\n> --- a/libstdc++-v3/include/bits/new_allocator.h\n> +++ b/libstdc++-v3/include/bits/new_allocator.h\n> @@ -162,6 +162,49 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>           return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__n *\n> sizeof(_Tp)));\n>        }\n>\n> +#ifdef __glibcxx_allocate_at_least  // C++23\n> +      [[nodiscard]] constexpr auto\n> +      allocate_at_least(size_t __n)\n> +      -> std::allocation_result<_Tp*, size_t>\n> +      {\n> +       static_assert(requires { sizeof(_Tp); },\n> +         \"cannot allocate incomplete types\");\n> +\n> +       const std::size_t __align_mask = __STDCPP_DEFAULT_NEW_ALIGNMENT__\n> - 1;\n> +\n> +       if constexpr (!requires { sizeof(_Tp); })\n> +         return { nullptr, 0 }; // static_assert already failed\n> +       else if (__builtin_expect(__n > this->_M_max_size(), false))\n> +         {\n> +           if (__n > (std::size_t(-1) / sizeof(_Tp)))\n> +             std::__throw_bad_array_new_length();\n> +           std::__throw_bad_alloc();\n> +         }\n> +       else if constexpr (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)\n> +         {\n> +           const std::align_val_t __al = std::align_val_t(alignof(_Tp));\n> +           auto __p = _GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp), __al);\n> +           return { static_cast<_Tp*>(__p), __n };\n> +         }\n> +       else if constexpr (sizeof(_Tp) > __align_mask)\n> +         {\n> +           auto __p = _GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp));\n> +           return { static_cast<_Tp*>(__p), __n };\n> +         }\n> +       else // See if more _Tp elements can fit into the allocation.\n> +         {\n> +           const auto __need = __n * sizeof(_Tp);\n> +           const auto __ask = (__need + __align_mask) & ~__align_mask;\n> +           const auto __p = _GLIBCXX_OPERATOR_NEW(__ask);\n> +           using _Uchar = const unsigned char;\n> +           static_assert(sizeof(_Tp) <= _Uchar(-1));\n> +           // Use 8-bit division.\n> +           _Uchar __spare = __ask - __need, __size = sizeof(_Tp);\n> +           return { static_cast<_Tp*>(__p), __n + __spare / __size };\n> +         }\n> +      }\n> +#endif\n> +\n>        // __p is not permitted to be a null pointer.\n>        _GLIBCXX20_CONSTEXPR void\n>        deallocate(_Tp* __p, size_type __n __attribute__ ((__unused__)))\n> diff --git a/libstdc++-v3/include/bits/stl_vector.h\n> b/libstdc++-v3/include/bits/stl_vector.h\n> index c4ca214752a..571018cb6f7 100644\n> --- a/libstdc++-v3/include/bits/stl_vector.h\n> +++ b/libstdc++-v3/include/bits/stl_vector.h\n> @@ -317,6 +317,19 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        get_allocator() const _GLIBCXX_NOEXCEPT\n>        { return allocator_type(_M_get_Tp_allocator()); }\n>\n> +      static _GLIBCXX20_CONSTEXPR size_t\n> +      _S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT\n> +      {\n> +       // std::distance(begin(), end()) cannot be greater than\n> PTRDIFF_MAX,\n> +       // and realistically we can't store more than PTRDIFF_MAX/sizeof(T)\n> +       // (even if std::allocator_traits::max_size says we can).\n> +       const size_t __diffmax =\n> +         __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);\n> +       const size_t __allocmax =\n> +         __gnu_cxx::__alloc_traits<_Alloc>::max_size(__a);\n> +       return (std::min)(__diffmax, __allocmax);\n> +      }\n> +\n>  #if __cplusplus >= 201103L\n>        _Vector_base() = default;\n>  #else\n> @@ -381,12 +394,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>      public:\n>        _Vector_impl _M_impl;\n>\n> +      struct _Alloc_result { pointer __ptr; size_t __count; };\n> +\n>        _GLIBCXX20_CONSTEXPR\n> -      pointer\n> -      _M_allocate(size_t __n)\n> +      _Alloc_result\n> +      _M_allocate_at_least(size_t __n)\n>        {\n>         typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;\n> -       return __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer();\n> +       _Alloc_result __r;\n> +       if (__builtin_expect(__n != 0, true))\n> +         {\n> +#ifdef __glibcxx_allocate_at_least  // C++23\n> +           auto [__ptr, __count] = _Tr::allocate_at_least(_M_impl, __n);\n> +           if (__count > __n)\n> +             {\n> +               size_t __max = _S_max_size(_M_get_Tp_allocator());\n> +               if (__builtin_expect(__count > __max, false))\n> +                 __count = __max;\n> +             }\n> +           __r.__ptr = __ptr, __r.__count = __count;\n> +#else\n> +           __r.__ptr = _Tr::allocate(_M_impl, __n), __r.__count = __n;\n> +#endif\n> +         }\n> +       else __r.__ptr = pointer(), __r.__count = 0;\n> +       return __r;\n>        }\n>\n>        _GLIBCXX20_CONSTEXPR\n> @@ -404,9 +436,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        void\n>        _M_create_storage(size_t __n)\n>        {\n> -       this->_M_impl._M_start = this->_M_allocate(__n);\n> -       this->_M_impl._M_finish = this->_M_impl._M_start;\n> -       this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;\n> +       _Alloc_result __r = this->_M_allocate_at_least(__n);\n> +       this->_M_impl._M_finish = this->_M_impl._M_start = __r.__ptr;\n> +       this->_M_impl._M_end_of_storage = this->_M_impl._M_start +\n> __r.__count;\n>        }\n>\n>  #if __glibcxx_containers_ranges // C++ >= 23\n> @@ -480,6 +512,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        typedef _Vector_base<_Tp, _Alloc>                        _Base;\n>        typedef typename _Base::_Tp_alloc_type           _Tp_alloc_type;\n>        typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>\n> _Alloc_traits;\n> +      typedef typename _Base::_Alloc_result             _Alloc_result;\n>\n>      public:\n>        typedef _Tp                                      value_type;\n> @@ -535,7 +568,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>  #endif // C++11\n>\n>      protected:\n> -      using _Base::_M_allocate;\n> +      using _Base::_M_allocate_at_least;\n>        using _Base::_M_deallocate;\n>        using _Base::_M_impl;\n>        using _Base::_M_get_Tp_allocator;\n> @@ -1116,7 +1149,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR\n>        size_type\n>        max_size() const _GLIBCXX_NOEXCEPT\n> -      { return _S_max_size(_M_get_Tp_allocator()); }\n> +      { return _Base::_S_max_size(_M_get_Tp_allocator()); }\n>\n>  #if __cplusplus >= 201103L\n>        /**\n> @@ -1682,16 +1715,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>                   return;\n>                 }\n>\n> -             const size_type __len = _M_check_len(__n,\n> \"vector::append_range\");\n> +             const size_type __len1 = _M_check_len(__n,\n> \"vector::append_range\");\n>\n>               pointer __old_start = this->_M_impl._M_start;\n>               pointer __old_finish = this->_M_impl._M_finish;\n>\n> -             allocator_type& __a = _M_get_Tp_allocator();\n> -             const pointer __start = this->_M_allocate(__len);\n> +             auto [__ptr, __count] = this->_M_allocate_at_least(__len1);\n> +             const size_type __len = __count;\n> +             const pointer __start = __ptr;\n>               const pointer __mid = __start + __sz;\n>               const pointer __back = __mid + __n;\n>               _Guard_alloc __guard(__start, __len, *this);\n> +             allocator_type& __a = _M_get_Tp_allocator();\n>               std::__uninitialized_copy_a(ranges::begin(__rg),\n>                                           ranges::end(__rg),\n>                                           __mid, __a);\n> @@ -1897,7 +1932,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>         _M_allocate_and_copy(size_type __n,\n>                              _ForwardIterator __first, _ForwardIterator\n> __last)\n>         {\n> -         _Guard_alloc __guard(this->_M_allocate(__n), __n, *this);\n> +         _Alloc_result __r = this->_M_allocate_at_least(__n);\n> +         _Guard_alloc __guard(__r.__ptr, __r.__count, *this);\n>           std::__uninitialized_copy_a\n>             (__first, __last, __guard._M_storage, _M_get_Tp_allocator());\n>           return __guard._M_release();\n> @@ -1916,8 +1952,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>         _M_initialize_dispatch(_Integer __int_n, _Integer __value,\n> __true_type)\n>         {\n>           const size_type __n = static_cast<size_type>(__int_n);\n> -         pointer __start =\n> -           _M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator()));\n> +         pointer __start = _M_allocate_at_least(\n> +             _S_check_init_len(__n, _M_get_Tp_allocator())).__ptr;\n>           this->_M_impl._M_start = __start;\n>           this->_M_impl._M_end_of_storage = __start + __n;\n>\n\nDoesn't this just discard any additional capacity that was allocated?\n\n          _M_fill_initialize(__n, __value);\n> @@ -1971,10 +2007,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>         _M_range_initialize_n(_Iterator __first, _Sentinel __last,\n>                               size_type __n)\n>         {\n> -         pointer __start =\n> -           this->_M_allocate(_S_check_init_len(__n,\n> _M_get_Tp_allocator()));\n> +         _Alloc_result __r = this->_M_allocate_at_least(\n> +           _S_check_init_len(__n, _M_get_Tp_allocator()));\n> +         pointer __start = __r.__ptr;\n>           this->_M_impl._M_start = this->_M_impl._M_finish = __start;\n> -         this->_M_impl._M_end_of_storage = __start + __n;\n> +         this->_M_impl._M_end_of_storage = __start + __r.__count;\n>           this->_M_impl._M_finish\n>               = std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,\n>                                             __start,\n> _M_get_Tp_allocator());\n> @@ -2191,35 +2228,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        size_type\n>        _M_check_len(size_type __n, const char* __s) const\n>        {\n> -       if (max_size() - size() < __n)\n> +       const size_type __room = max_size() - size();\n> +       if (__room < __n)\n>           __throw_length_error(__N(__s));\n>\n> -       const size_type __len = size() + (std::max)(size(), __n);\n> -       return (__len < size() || __len > max_size()) ? max_size() : __len;\n> +       if (__n < size())\n> +         __n = size();  // Grow by (at least) doubling ...\n> +       if (__n > __room)\n> +         __n = __room;  //  ... but only as much as will fit.\n> +       return size() + __n;\n>        }\n>\n>        // Called by constructors to check initial size.\n>        static _GLIBCXX20_CONSTEXPR size_type\n>        _S_check_init_len(size_type __n, const allocator_type& __a)\n>        {\n> -       if (__n > _S_max_size(_Tp_alloc_type(__a)))\n> +       if (__n > _Base::_S_max_size(_Tp_alloc_type(__a)))\n>           __throw_length_error(\n>               __N(\"cannot create std::vector larger than max_size()\"));\n>         return __n;\n>        }\n>\n> -      static _GLIBCXX20_CONSTEXPR size_type\n> -      _S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT\n> -      {\n> -       // std::distance(begin(), end()) cannot be greater than\n> PTRDIFF_MAX,\n> -       // and realistically we can't store more than PTRDIFF_MAX/sizeof(T)\n> -       // (even if std::allocator_traits::max_size says we can).\n> -       const size_t __diffmax\n> -         = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);\n> -       const size_t __allocmax = _Alloc_traits::max_size(__a);\n> -       return (std::min)(__diffmax, __allocmax);\n> -      }\n> -\n>        // Internal erase functions follow.\n>\n>        // Called by erase(q1,q2), clear(), resize(), _M_fill_assign,\n> diff --git a/libstdc++-v3/include/bits/vector.tcc\n> b/libstdc++-v3/include/bits/vector.tcc\n> index b790fca2964..9524038b7d1 100644\n> --- a/libstdc++-v3/include/bits/vector.tcc\n> +++ b/libstdc++-v3/include/bits/vector.tcc\n> @@ -79,7 +79,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>  #if __cplusplus >= 201103L\n>           if constexpr (_S_use_relocate())\n>             {\n> -             __tmp = this->_M_allocate(__n);\n> +             auto __res = this->_M_allocate_at_least(__n);\n> +             __tmp = __res.__ptr;\n> +             __n = __res.__count;\n>               std::__relocate_a(this->_M_impl._M_start,\n> this->_M_impl._M_finish,\n>                                 __tmp, _M_get_Tp_allocator());\n>             }\n> @@ -106,12 +108,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>  #if __cplusplus >= 201103L\n>    template<typename _Tp, typename _Alloc>\n>      template<typename... _Args>\n> -#if __cplusplus > 201402L\n> +# if __cplusplus > 201402L\n>        _GLIBCXX20_CONSTEXPR\n>        typename vector<_Tp, _Alloc>::reference\n> -#else\n> +# else\n>        void\n> -#endif\n> +# endif\n>        vector<_Tp, _Alloc>::\n>        emplace_back(_Args&&... __args)\n>        {\n> @@ -125,11 +127,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>           }\n>         else\n>           _M_realloc_append(std::forward<_Args>(__args)...);\n> -#if __cplusplus > 201402L\n> +# if __cplusplus > 201402L\n>         return back();\n> -#endif\n> +# endif\n>        }\n> -#endif\n> +#endif  // __cplusplus >= 201103L\n>\n>    template<typename _Tp, typename _Alloc>\n>      _GLIBCXX20_CONSTEXPR\n> @@ -464,13 +466,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>      _M_realloc_insert(iterator __position, const _Tp& __x)\n>  #endif\n>      {\n> -      const size_type __len = _M_check_len(1u,\n> \"vector::_M_realloc_insert\");\n> -      if (__len <= 0)\n> +      const size_type __len1 = _M_check_len(1u,\n> \"vector::_M_realloc_insert\");\n> +      if (__len1 <= 0)\n>         __builtin_unreachable();\n>        pointer __old_start = this->_M_impl._M_start;\n>        pointer __old_finish = this->_M_impl._M_finish;\n>        const size_type __elems_before = __position - begin();\n> -      pointer __new_start(this->_M_allocate(__len));\n> +      _Alloc_result __r = this->_M_allocate_at_least(__len1);\n> +      const size_type __len = __r.__count;\n> +      pointer __new_start(__r.__ptr);\n>        pointer __new_finish(__new_start);\n>\n>        {\n> @@ -574,14 +578,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>        const size_type __len = _M_check_len(1u,\n> \"vector::_M_realloc_append\");\n>        if (__len <= 0)\n>         __builtin_unreachable();\n> -      pointer __old_start = this->_M_impl._M_start;\n> -      pointer __old_finish = this->_M_impl._M_finish;\n> +      const pointer __old_start = this->_M_impl._M_start;\n> +      const pointer __old_finish = this->_M_impl._M_finish;\n>        const size_type __elems = size();\n> -      pointer __new_start(this->_M_allocate(__len));\n> +      const _Alloc_result __r = this->_M_allocate_at_least(__len);\n> +      const size_type __rlen = __r.__count;\n> +      const pointer __new_start(__r.__ptr);\n>        pointer __new_finish(__new_start);\n>\n>        {\n> -       _Guard_alloc __guard(__new_start, __len, *this);\n> +       _Guard_alloc __guard(__new_start, __rlen, *this);\n>\n>         // The order of the three operations is dictated by the C++11\n>         // case, where the moves could alter a new element belonging\n> @@ -652,7 +658,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>\n>        this->_M_impl._M_start = __new_start;\n>        this->_M_impl._M_finish = __new_finish;\n> -      this->_M_impl._M_end_of_storage = __new_start + __len;\n> +      this->_M_impl._M_end_of_storage = __new_start + __rlen;\n>      }\n>  #pragma GCC diagnostic pop\n>\n> @@ -716,10 +722,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>               pointer __old_finish = this->_M_impl._M_finish;\n>               const pointer __pos = __position.base();\n>\n> -             const size_type __len =\n> +             const size_type __len1 =\n>                 _M_check_len(__n, \"vector::_M_fill_insert\");\n>               const size_type __elems_before = __pos - __old_start;\n> -             pointer __new_start(this->_M_allocate(__len));\n> +             _Alloc_result __r = this->_M_allocate_at_least(__len1);\n> +             const size_type __len = __r.__count;\n> +             pointer __new_start(__r.__ptr);\n>               pointer __new_finish(__new_start);\n>               __try\n>                 {\n> @@ -787,7 +795,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>\n>            const size_type __len =\n>              _M_check_len(__n, \"vector::_M_fill_append\");\n> -          pointer __new_start(this->_M_allocate(__len));\n> +          _Alloc_result __r = this->_M_allocate_at_least(__len);\n> +          __len = __r.__count;\n> +          pointer __new_start(__r.__ptr);\n>            pointer __new_finish(__new_start + __old_size);\n>            __try\n>              {\n> @@ -852,9 +862,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>               pointer __old_start = this->_M_impl._M_start;\n>               pointer __old_finish = this->_M_impl._M_finish;\n>\n> -             const size_type __len =\n> +             const size_type __len1 =\n>                 _M_check_len(__n, \"vector::_M_default_append\");\n> -             pointer __new_start(this->_M_allocate(__len));\n> +             _Alloc_result __r = this->_M_allocate_at_least(__len1);\n> +             const size_type __len = __r.__count;\n> +             pointer __new_start(__r.__ptr);\n>\n>               {\n>                 _Guard_alloc __guard(__new_start, __len, *this);\n> @@ -1003,14 +1015,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>                 pointer __old_start = this->_M_impl._M_start;\n>                 pointer __old_finish = this->_M_impl._M_finish;\n>\n> -               const size_type __len =\n> +               const size_type __len1 =\n>                   _M_check_len(__n, \"vector::_M_range_insert\");\n>  #if __cplusplus < 201103L\n> -               if (__len < (__n + (__old_finish - __old_start)))\n> +               if (__len1 < (__n + (__old_finish - __old_start)))\n>                   __builtin_unreachable();\n>  #endif\n>\n> -               pointer __new_start(this->_M_allocate(__len));\n> +               _Alloc_result __r = this->_M_allocate_at_least(__len1);\n> +               const size_type __len = __r.__count;\n> +               pointer __new_start(__r.__ptr);\n>                 pointer __new_finish(__new_start);\n>                 __try\n>                   {\n> @@ -1111,7 +1125,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>               }\n>             else // Reallocate\n>               {\n> -               const size_type __len\n> +               const size_type __len1\n>                   = _M_check_len(__n, \"vector::insert_range\");\n>\n>                 struct _Guard : _Guard_alloc\n> @@ -1130,7 +1144,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>                 };\n>\n>                 // Allocate new storage:\n> -               pointer __new_start(this->_M_allocate(__len));\n> +               _Alloc_result __r = this->_M_allocate_at_least(__len1);\n> +               const size_type __len = __r.__count;\n> +               pointer __new_start(__r.__ptr);\n>                 _Guard __guard(__new_start, __len, *this);\n>\n>                 auto& __alloc = _M_get_Tp_allocator();\n> diff --git a/libstdc++-v3/include/std/string\n> b/libstdc++-v3/include/std/string\n> index c2b37391fc7..da50bce2e7d 100644\n> --- a/libstdc++-v3/include/std/string\n> +++ b/libstdc++-v3/include/std/string\n> @@ -67,6 +67,7 @@\n>  #endif\n>\n>  #define __glibcxx_want_algorithm_default_value_type\n> +#define __glibcxx_want_allocate_at_least\n>  #define __glibcxx_want_allocator_traits_is_always_equal\n>  #define __glibcxx_want_constexpr_char_traits\n>  #define __glibcxx_want_constexpr_string\n> diff --git a/libstdc++-v3/include/std/vector\n> b/libstdc++-v3/include/std/vector\n> index 343483e9519..ac041cc9408 100644\n> --- a/libstdc++-v3/include/std/vector\n> +++ b/libstdc++-v3/include/std/vector\n> @@ -79,6 +79,7 @@\n>  #endif\n>\n>  #define __glibcxx_want_algorithm_default_value_type\n> +#define __glibcxx_want_allocate_at_least\n>  #define __glibcxx_want_allocator_traits_is_always_equal\n>  #define __glibcxx_want_constexpr_vector\n>  #define __glibcxx_want_containers_ranges\n> diff --git\n> a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc\n> b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc\n> index 44c8391ebc2..9942e1cfb6a 100644\n> ---\n> a/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc\n> +++\n> b/libstdc++-v3/testsuite/21_strings/basic_string/cons/wchar_t/constexpr.cc\n> @@ -34,7 +34,7 @@ struct Alloc : std::allocator<T>\n>    { return personality == a.personality; }\n>  };\n>\n> -constexpr bool\n> +consteexpr bool\n>\n\nTypo\n\n test_default_ctor()\n>  {\n>    std::basic_string<C> s0;\n> diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h\n> b/libstdc++-v3/testsuite/util/testsuite_allocator.h\n> index 892a385e307..d8914229c7a 100644\n> --- a/libstdc++-v3/testsuite/util/testsuite_allocator.h\n> +++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h\n> @@ -176,6 +176,16 @@ namespace __gnu_test\n>         return p;\n>        }\n>\n> +#ifdef __glibcxx_allocate_at_least\n> +      std::allocation_result<pointer, size_type>\n> +      allocate_at_least(size_type n)\n> +      {\n> +       auto r = AllocTraits::allocate_at_least(*this, n);\n>\n\nIs this recursive now?\n\n+       counter_type::allocate(r.count * sizeof(T));\n> +       return r;\n> +      }\n> +#endif\n> +\n>  #if __cplusplus >= 201103L\n>        template<typename U, typename... Args>\n>         void\n> @@ -353,6 +363,9 @@ namespace __gnu_test\n>        _GLIBCXX20_CONSTEXPR\n>        pointer\n>        allocate(size_type n, const void* = 0)\n> +#ifdef __glibcxx_allocate_at_least\n> +      { return this->allocate_at_least(n).ptr; }\n> +#else\n>        {\n>         pointer p = AllocTraits::allocate(*this, n);\n>\n> @@ -372,6 +385,33 @@ namespace __gnu_test\n>\n>         return p;\n>        }\n> +#endif\n> +\n> +#ifdef __glibcxx_allocate_at_least\n> +      _GLIBCXX20_CONSTEXPR\n> +      auto\n> +      allocate_at_least(size_type n)\n> +      -> std::allocation_result<Tp*, size_t>\n> +      {\n> +       auto r = AllocTraits::allocate_at_least(*this, n);\n> +\n> +       if (std::__is_constant_evaluated())\n> +         return r;\n> +\n> +       try\n> +         {\n> +           get_map().insert(map_type::value_type(\n> +                 reinterpret_cast<void*>(r.ptr), personality));\n> +         }\n> +       catch(...)\n> +         {\n> +           AllocTraits::deallocate(*this, r.ptr, r.count);\n> +           __throw_exception_again;\n> +         }\n> +\n> +       return r;\n> +      }\n> +#endif\n>\n>        _GLIBCXX14_CONSTEXPR\n>        void\n> --\n> 2.53.0\n>\n>","headers":{"Return-Path":"<gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org>","X-Original-To":["incoming@patchwork.ozlabs.org","gcc-patches@gcc.gnu.org"],"Delivered-To":["patchwork-incoming@legolas.ozlabs.org","gcc-patches@gcc.gnu.org"],"Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=BWCfm9MU;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=2620:52:6:3111::32; helo=vm01.sourceware.org;\n envelope-from=gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org;\n receiver=patchwork.ozlabs.org)","sourceware.org;\n\tdkim=pass (2048-bit key,\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=BWCfm9MU","sourceware.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","sourceware.org; spf=pass smtp.mailfrom=gmail.com","server2.sourceware.org;\n arc=pass smtp.remote-ip=209.85.167.41"],"Received":["from vm01.sourceware.org (vm01.sourceware.org\n [IPv6:2620:52:6:3111::32])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fnn0x6mMtz1yCs\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 04 Apr 2026 18:15:13 +1100 (AEDT)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id B01EA4BA23E6\n\tfor <incoming@patchwork.ozlabs.org>; Sat,  4 Apr 2026 07:15:11 +0000 (GMT)","from mail-lf1-f41.google.com (mail-lf1-f41.google.com\n [209.85.167.41])\n by sourceware.org (Postfix) with ESMTPS id C77114BA23D8\n for <gcc-patches@gcc.gnu.org>; Sat,  4 Apr 2026 07:14:13 +0000 (GMT)","by mail-lf1-f41.google.com with SMTP id\n 2adb3069b0e04-5a0fc5e2c59so2564411e87.1\n for <gcc-patches@gcc.gnu.org>; Sat, 04 Apr 2026 00:14:13 -0700 (PDT)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org B01EA4BA23E6","OpenDKIM Filter v2.11.0 sourceware.org C77114BA23D8"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org C77114BA23D8","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org C77114BA23D8","ARC-Seal":["i=2; a=rsa-sha256; d=sourceware.org; s=key; t=1775286854; cv=pass;\n b=slklWjxsp0CWGX44hr8UOHQd4C1JKg8a6qHj9g6kFCgqGK0NGH/90umQyO0LWLeBZzBtKXINwqVD6Bc4LZia9hY6dqvj1cdF0H9ub1nBVcPgq3eyjJDXjFTm7kjYrZuXxPRDH5puLchg0kjlOgnktHfyUXQCvfzDzkj3rf0lKoo=","i=1; a=rsa-sha256; t=1775286852; cv=none;\n d=google.com; s=arc-20240605;\n b=AeODQsLAZvc/1EAacIgZUAFI9XA/I/E03/D305xtsNZmOcB5tYBN1EabwZ4VyECTn3\n 8yVkuaOPLbhP4RWw+GS76Dp8vvAjA4+JjRVwBY0FnNOLYR7x8CJ5EJhWmw3DFY6zcRqO\n NfRzbvBbOiDk7vyHRQ0sCsN5b/C6P1j3mgYxjIZFT8MjILohGUCYrq1fJWp3UV6EP/nx\n jkvp4e+E7SUai+lCUEDHfw3fICXJJpDHW4VOVf8AO9/UYLngdsKJHqI1T2xrxvMxSv1g\n rluRew1KxTT2Lw6uJHu4TBMGLvqy4iGyHspppYeuOZ3FDSMTfTBrcZ8rAmKLRo7ztXRD\n Oz+Q=="],"ARC-Message-Signature":["i=2; a=rsa-sha256; d=sourceware.org; s=key;\n t=1775286854; c=relaxed/simple;\n bh=V7UEOIxkZ+YBmbu/GGvgBLkHf4cTKBgnS7tE+s+MQ34=;\n h=DKIM-Signature:MIME-Version:From:Date:Message-ID:Subject:To;\n b=YFxjqLktM9Ro22aAgTob18MOF/tmoypBS2m/Nglv6XMlQHF3gVxrP+r1eImB1jh+SIFvLWVbYt0u5uxzwX4s6TsZBMwCgv+OUQ6Kf9OVsOwK7j0s9AWZ9hfj9kdPaJXmi6KwMspl6gIvlUPpo9ekMcEP8YHx2OaY+UK1q8bcxQ0=","i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com;\n s=arc-20240605;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:dkim-signature;\n bh=wshfT8xW3USfLS8hnl7vyz4p3JdedUvRhWz2BMxUz14=;\n fh=V8CLVXrvOQyKIpx2qB0un9Xqz/NDUrp4auxBK2+EfNE=;\n b=LFK7aoobIIr9gn/ypsENT4pQSXK5WBDfduu8n369sr9Z+ZfG9GN9OwQI2twGa6KDFv\n 9TRAmMk6Q7VxwJlULCNOyGvvNXiFgJdTcuFUg3HrJ/r2WnQltuzPhgljINRuZl+6VZ2O\n xCds/ZBDqpUsWqD5Zif7sjeDTlN2y0p8z9lI7AWeh/q5pc64xZlXctX3W6H1tuAinfuF\n ODPuZjrVdiT2c6vQraIK0ZBVflNuHgIPvilEp24OV12ehp/Tfg/dLnEZXNBW1rzqf4Iq\n E3uOvt5IJrNEhP6URv/Nm5OgePBvc/t6x15MKHwaPjA/zrqJD9pV5S0UXrVGQseahpf5\n g+6Q==; darn=gcc.gnu.org"],"ARC-Authentication-Results":["i=2; server2.sourceware.org","i=1; mx.google.com; arc=none"],"DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1775286852; x=1775891652; darn=gcc.gnu.org;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:from:to:cc:subject:date:message-id:reply-to;\n bh=wshfT8xW3USfLS8hnl7vyz4p3JdedUvRhWz2BMxUz14=;\n b=BWCfm9MUufzY+ecqzCse6HMEttEZ+kUsWGDknarcPMHBH/5GvKw5K3C72x2u3+BurO\n /EJG/XnB8X3QgUZEPz5ieepM6Tgagl+MGeU8B5olAUxtWlXayEuooDXU8w9L0PDuNSzZ\n RjSUczHRL91aBPHrW/hczPgASxezYlQrdZqT3PKjO45W73hdrbnGtbTyoWNkSivOL5pU\n zaQiuL+M2s6va3w7FG6DrnHpmv2snOWhwa+cXGQML54GwCDik9/fpkfyZh7Y7X3DuqpB\n YXc/aEPTygVSYAcmbzWqTNQMryuvvNQvmfTH1UgmmsuGVpSCek2vVD7jTMyHwDupLVCN\n J9dA==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1775286852; x=1775891652;\n h=cc:to:subject:message-id:date:from:in-reply-to:references\n :mime-version:x-gm-gg:x-gm-message-state:from:to:cc:subject:date\n :message-id:reply-to;\n bh=wshfT8xW3USfLS8hnl7vyz4p3JdedUvRhWz2BMxUz14=;\n b=iM9MHdQH8nPrDpMtlZertyzuxnzAvP2JduduN0ptNboNFhLqVLfXZr3eOwGTEzIsox\n WufbXh0TJHrJ6rNYErpln19Ryh+alKrtyrszHBvfCujNDv/p48XeLKWtRioEmeoU8KVv\n i9GZBRnkrQJijFxIr9YC42Ue3G50QbazCWjwS915CpV71kn4Pjt8CqpkElOb0ZmX/Lte\n +DUTIX4mROf9sF9vT4dNv+RN36tvMPyEpKZsiT6plCnMhNf9F783SKfIrSWDOmiVIsuy\n 5ltLro5LSli77sDBcYrQvSlVR6uqvQuRu1oDo/hq8BpVw1TCiT28/G/i0bCmCyKIBNEy\n 2DHA==","X-Gm-Message-State":"AOJu0YxMxTGPG6PjuaU4iA6Wch+sqGm3G/ye72uEJsb9XcXXGNG2VXXC\n vmogg+q4Ao8sPjjWEvZWalmUqjdeIv1Jd5U2Pz7VRKEJo9LtC5/9hp3vxLs+Yx9zOJmz7s2yUJZ\n mMfOhrUgshV/PSiPLNq3QcAI1NjoNq5Q=","X-Gm-Gg":"AeBDietfVNjKJXwr5zdmvC4ARHAART2RBbY555kLoUnzIJQK0K+d8j151qwEUu/YoR9\n 6WR3jP4kgJ6ohg4/LIrek1e9YRHUFhjrlfr5igxKBpQalFKw5nWCJPQEsQteYG1pT+C31FRCB13\n yidoJJ7RIkfRgZzblbka2bIT61T6hMHubhk6G/cBwzqc5BXd6ONHoYLquVA6eTn5wC4vYgYavSZ\n WqI7rfpvHfrWTjDWg3irbYiAT2mWNyYhdLsT1+ArR8umSUfQH7ca6/8+VN1Bk3Oo/+5BtqJsRoz\n cQTXTMiVjmg7YMxH3MVMftN+JPKVcYJZGR6PBkHQ2lUmR77ykUrwF5JD4Pd3Q/7lZoRGOVSbl16\n Zb0F2dIQ8YMrzOKzK5zzxjeLoYAI=","X-Received":"by 2002:a05:6512:158e:b0:5a3:cebc:65c5 with SMTP id\n 2adb3069b0e04-5a3cebc6c5emr1284576e87.35.1775286851900; Sat, 04 Apr 2026\n 00:14:11 -0700 (PDT)","MIME-Version":"1.0","References":"<20260404050329.949729-1-ncm@cantrip.org>","In-Reply-To":"<20260404050329.949729-1-ncm@cantrip.org>","From":"Jonathan Wakely <jwakely.gcc@gmail.com>","Date":"Sat, 4 Apr 2026 08:14:00 +0100","X-Gm-Features":"AQROBzBQLo2UgS_hhaZW1EZ22917-zllgspS5thRTYKfPxGTH7jGVRHfDYT7sNc","Message-ID":"\n <CAH6eHdSFKCuFErEantMBHLyYZ4QOu3UCTHf8-8fsi6_JEuvboQ@mail.gmail.com>","Subject":"Re: [RFC] libstdc++: Use allocate_at_least in vector,\n string (P0401) [PR118030]","To":"Nathan Myers <ncm@cantrip.org>","Cc":"gcc-patches <gcc-patches@gcc.gnu.org>, \"libstdc++\" <libstdc++@gcc.gnu.org>","Content-Type":"multipart/alternative; boundary=\"0000000000002e9a0a064e9d2e00\"","X-BeenThere":"gcc-patches@gcc.gnu.org","X-Mailman-Version":"2.1.30","Precedence":"list","List-Id":"Gcc-patches mailing list <gcc-patches.gcc.gnu.org>","List-Unsubscribe":"<https://gcc.gnu.org/mailman/options/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=unsubscribe>","List-Archive":"<https://gcc.gnu.org/pipermail/gcc-patches/>","List-Post":"<mailto:gcc-patches@gcc.gnu.org>","List-Help":"<mailto:gcc-patches-request@gcc.gnu.org?subject=help>","List-Subscribe":"<https://gcc.gnu.org/mailman/listinfo/gcc-patches>,\n <mailto:gcc-patches-request@gcc.gnu.org?subject=subscribe>","Errors-To":"gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org"}}]