[{"id":3679422,"web_url":"http://patchwork.ozlabs.org/comment/3679422/","msgid":"<aeY1KJ2OEFCrmVKe@zen.kayari.org>","list_archive_url":null,"date":"2026-04-20T14:16:08","subject":"Re: [PATCH] libstdc++: Use allocate_at_least in vector, string\n (P0401) [PR118030]","submitter":{"id":48004,"url":"http://patchwork.ozlabs.org/api/people/48004/","name":"Jonathan Wakely","email":"jwakely@redhat.com"},"content":"On Sat, 18 Apr 2026 at 17:56 -0400, Nathan Myers wrote:\n>Changes in v2:\n> - Avoid PR108377 \"exceeds maximum object size\" warning\n>  differently, contained to __allocate_to_alignment.\n> - Rename _S_allocate_to_alignment to __allocate_to_alignment\n>  because it is not a member. Generalize it for arbitrary pointer\n>  and size types.\n> - Declare allocator_traits<allocator<void>>::allocate_at_least\n>  with \" = delete;\", matching others.\n> - In allocator_traits<>::allocate_at_least, de-structure and\n>  reconstruct the allocation result to enable an implicit\n>  pointer type conversion on the way, as used (e.g.) for\n>  testsuite_allocator.h.\n> - Define allocate_at_least in the polymorphic specialization\n>  of allocator_traits (bits/memory_resource.h), and in the\n>  testsuite allocator, destructuring likewise.\n> - In string:\n>    - Make _M_create use _M_allocate_at_least. (This function\n>     is no longer used, but is retained for ABI stability.)\n>    - Define (in addition to _M_create_plus) a new allocation\n>     helper function _M_create_and_place to abstract common\n>     operations, and use it where suitable.\n>    - Add new member signatures to config/abi/pre/gnu.ver.\n>    - Relax shrink_to_fit()/reserve() to allow a little extra.\n> - In vector, define (on top of _S_allocate_at_least) helper\n>  functions _M_allocate_and_copy, _M_displace_storage,\n>  and _M_allocate_and_migrate to abstract common ops, and\n>  use them. This incidentally corrects an (apparent?) omission\n>  of _GLIBCXX_ASAN_ANNOTATE_REINIT in operator=.\n> - Adjust tests to pass with or without allocate_at_least.\n>  (__STDCPP_DEFAULT_NEW_ALIGNMENT__ is not defined everywhere.)\n>\n>Changes from RFC:\n> - Improve doxygen for new interfaces.\n> - Move code implementing alignment size-round-up logic from\n>  allocator.h to alloc_traits.h for other allocators' reuse.\n> - Restore allocator.h definition of allocate_at_least, that\n>  then explicitly delegates to its base class implementation.\n> - Retain existing string::_S_allocate, vector<>::_M_allocate\n>  interfaces for ABI stability, using new names\n>  _S_allocate_at_least, _M_allocate_at_least for new behavior.\n> - Define string _M_create_plus using S_allocate_at_least, and\n>  use that throughout in place of _M_create, retaining _M_create\n>  for ABI stability.\n> - Make memory_resource::allocate_at_least use argument\n>  allocator's allocate_at_least if present.\n> - Fix std::allocator<>::allocate_at_least so it takes its\n>  allocator object by reference, not by value.\n> - Per review, in constexpr context begin lifetime of all\n>  potential string characters upon allocation.\n> - Revert \"< 2011\"-only vector<>::_M_initialize_dispatch changes.\n> - Fix string new-capacity off-by-one errors.\n> - Export new symbols _S_allocate_at_least and _M_create_plus from\n>  bits/basic_string.h.\n> - Work around PR108377 spurious \"exceeds maximum object size\".\n> - Test.\n> - Patch too-strict capacity tests.\n>\n>Implement as much of allocator<>::allocate_at_least as possible\n>relying solely on known alignment behavior of standard operator\n>new. Provide apparatus for users' allocators to do the same.\n>\n>Use allocator_at_least in string and vector to maximize usage of\n>actually allocated storage, as revealed by the allocator in use.\n>For user-supplied allocators this may make a big difference.\n>\n>Fixes omitted _GLIBCXX_ASAN_ANNOTATE_REINIT in vector<>::operator=.\n>\n>Nothing is changed in include/ext/malloc_allocator or others.\n>They can be updated at leisure, piecemeal.\n>\n>libstdc++-v3/ChangeLog:\n>\tPR libstdc++/118030\n>\t* include/bits/alloc_traits.h (__allocate_to_alignment): Define.\n>\t(allocate_at_least): In allocator_traits template member,\n>\tdestructure and reconstruct result from allocator object's version,\n>\tto enable pointer type conversion.\n>\t(allocate_at_least): Delegate, in allocator_traits<allocator<_Tp>>\n>\tspecialization, to member where defined.\n>\t(allocate_at_least): Declare \"= delete;\" in allocator<void>.\n>\t* include/bits/allocator.h (allocate_at_least): Delegate to base\n>\tallocate_at_least where defined, calling with explicit base-class\n>\tqualification, picking up __new_allocator member.\n>\t* include/bits/basic_string.h (_Alloc_result): Define new type.\n>\t(_S_allocate_at_least): Define.\n>\t(_S_allocate): Delegate to _S_allocate_at_least.\n>\t(_M_create_plus, _M_create_and_place): Declare.\n>\t(assign): Use _S_allocate_at_least.\n>\t* include/bits/basic_string.tcc (_M_create_plus): Define.\n>\t(_M_create_and_place): Define, abstracting common operations.\n>\t(_M_replace, reserve): Use _S_allocate_at_least.\n>\t(_M_construct, input iterators): Use _M_create_plus.\n>\t(_M_construct, others (3x)): Use _M_create_and_place.\n>\t(_M_create, _M_assign, reserve, _M_mutate): Use _M_create_plus.\n>\t* include/bits/memory_resource.h (allocate_at_least): Define,\n>\tdocument.\n>\t* include/bits/memoryfwd.h (__allocate_to_alignment): Declare.\n>\t* include/bits/new_allocator.h (allocate_at_least): Define, relying\n>\ton __allocate_to_alignment from alloc_traits.h.\n>\t(deallocate): Refine \"if constexpr\" logic.\n>\t* include/bits/stl_vector.h:\n>\t(_S_max_size): Move to _Vector_base.\n>\t(_Alloc_result): Define type.\n>\t(_M_allocate_at_least): Define, using allocate_at_least where supported.\n>\t(_M_allocate): Delegate to _M_allocate_at_least.\n>\t(max_size, _S_check_init_len): Use _S_max_size as moved.\n>\t(_M_create_storage, append_range, _M_allocate_and_copy,\n>\t_M_displace_storage): Define, abstracting common operations.\n>\t(_M_allocate_and_migrate): Define, likewise.\n>\t(_M_range_initialize_n): Use _M_allocate_at_least.\n>\t(_M_check_len): Improve logic.\n>\t* include/bits/vector.tcc:\n>\t(reserve, _M_fill_append, _M_range_insert): Use _M_allocate_at_least\n>\tand _M_displace_storage.\n>\t(operator=, _M_assign_aux): Use _M_allocate_and_migrate.\n>\t(_M_realloc_insert, _M_realloc_append, _M_default_append, insert_range):\n>\tUse _M_allocate_at_least.\n>\t(_M_fill_insert): Use _M_displace_storage, normalize whitespace.\n>\t* include/std/string: Define __glibcxx_want_allocate_at_least.\n>\t* include/std/vector: Same.\n>\t* testsuite/util/testsuite_allocator.h\n>\t(allocate_at_least (2x)): Define.\n>\t(allocate): Use allocate_at_least.\n>\t* testsuite/20_util/allocator/allocate_at_least.cc: Add tests.\n>\t* testsuite/21_strings/basic_string/capacity/char/18654.cc:\n>\tLoosen capacity check.\n>\t* testsuite/21_strings/basic_string/capacity/char/shrink_to_fit.cc:\n>\tSame.\n>\t* testsuite/21_strings/basic_string/capacity/wchar_t/18654.cc: Same.\n>\t* testsuite/21_strings/basic_string/capacity/wchar_t/2.cc: Same.\n>\t* testsuite/21_strings/basic_string/capacity/wchar_t/shrink_to_fit.cc:\n>\tSame.\n>\t* testsuite/23_containers/vector/capacity/shrink_to_fit.cc: Same.\n>\t* testsuite/23_containers/vector/capacity/shrink_to_fit2.cc: Same\n>\t* testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc:\n>\tAdapt to looser reserve behavior.\n>\t* config/abi/pre/gnu.ver: Expose string::_S_allocate_at_least,\n>\t_M_create_plus, and _M_create_and_place symbols.\n>---\n> libstdc++-v3/config/abi/pre/gnu.ver           |   5 +\n> libstdc++-v3/include/bits/alloc_traits.h      |  62 ++++++-\n> libstdc++-v3/include/bits/allocator.h         |  28 +++-\n> libstdc++-v3/include/bits/basic_string.h      |  38 ++++-\n> libstdc++-v3/include/bits/basic_string.tcc    | 108 +++++++-----\n> libstdc++-v3/include/bits/memory_resource.h   |  25 +++\n> libstdc++-v3/include/bits/memoryfwd.h         |   6 +-\n> libstdc++-v3/include/bits/new_allocator.h     |  41 ++++-\n> libstdc++-v3/include/bits/stl_vector.h        | 132 +++++++++++----\n> libstdc++-v3/include/bits/vector.tcc          | 155 +++++++-----------\n> libstdc++-v3/include/std/string               |   1 +\n> libstdc++-v3/include/std/vector               |   1 +\n> .../20_util/allocator/allocate_at_least.cc    | 108 +++++++++++-\n> .../basic_string/capacity/char/18654.cc       |   7 +-\n> .../capacity/char/shrink_to_fit.cc            |   7 +-\n> .../basic_string/capacity/wchar_t/18654.cc    |   8 +-\n> .../basic_string/capacity/wchar_t/2.cc        |  13 +-\n> .../capacity/wchar_t/shrink_to_fit.cc         |   7 +-\n> .../vector/capacity/shrink_to_fit.cc          |   7 +-\n> .../vector/capacity/shrink_to_fit2.cc         |  14 +-\n> .../vector/modifiers/emplace/self_emplace.cc  |  36 ++--\n> .../testsuite/util/testsuite_allocator.h      |  35 ++++\n> 22 files changed, 614 insertions(+), 230 deletions(-)\n>\n>diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver\n>index 624de951d41..bfb710cc9bc 100644\n>--- a/libstdc++-v3/config/abi/pre/gnu.ver\n>+++ b/libstdc++-v3/config/abi/pre/gnu.ver\n>@@ -2606,6 +2606,11 @@ GLIBCXX_3.4.35 {\n>     _ZNSbIwSt11char_traitsIwESaIwEEC[12]EvQ26is_default_constructible_vIT1_E;\n>     _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EEC[1-2]EvQ26is_default_constructible_vIT1_E;\n>\n>+    # std::basic_string:_S_allocate_at_least\n>+    _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE*_S_allocate_*;\n>+    _ZNSt7__cxx1112basic_stringI[cw]St11char_traitsI[cw]ESaI[cw]EE*_M_create_*;\n\nThis patch should waiot for GCC 17 now, so the new symbols will need\nto be in a new symbol version, GLIBCXX_3.4.36. We can deal with that\nafter the 16.1.0 release.\n\n>+\n>+\n> #if defined (_WIN32) && !defined (__CYGWIN__)\n>     _ZSt19__get_once_callablev;\n>     _ZSt15__get_once_callv;\n>diff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h\n>index 2be8ed561d4..3ded07eba3c 100644\n>--- a/libstdc++-v3/include/bits/alloc_traits.h\n>+++ b/libstdc++-v3/include/bits/alloc_traits.h\n>@@ -42,6 +42,9 @@\n> #  include <bits/stl_iterator.h> // __make_move_if_noexcept_iterator\n> # endif\n> #endif\n>+#ifdef __glibcxx_allocate_at_least  // C++23\n>+# include <bit>  // for rotl\n>+#endif\n>\n> namespace std _GLIBCXX_VISIBILITY(default)\n> {\n>@@ -419,10 +422,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       */\n>       [[nodiscard]] static constexpr auto\n>       allocate_at_least(_Alloc& __a, size_type __n)\n>-\t-> allocation_result<pointer, size_type>\n>+      -> allocation_result<pointer, size_type>\n>       {\n> \tif constexpr (requires { __a.allocate_at_least(__n); })\n>-\t  return __a.allocate_at_least(__n);\n>+\t  {\n>+\t    // Destructure to enable implicit __p -> pointer conversion.\n\nWhy is any conversion needed here?\n\nallocator_traits::pointer has to be the same type as the allocator\nreturns.\n\n>+\t    auto [__p, __c] = __a.allocate_at_least(__n);\n>+\t    return { __p, __c };\n>+\t  }\n> \telse\n> \t  return { __a.allocate(__n), __n };\n>       }\n>@@ -664,15 +671,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>        *  @brief  Allocate memory, generously.\n>        *  @param  __a  An allocator.\n>        *  @param  __n  The minimum number of objects to allocate space for.\n>-       *  @return Memory of suitable size and alignment for `n` or more\n>-       *  contiguous objects of type `value_type`.\n>+       *  @return Memory of suitable size and alignment for `m >= n`\n>+       *  contiguous objects of type `value_type`, and `m`.\n>        *\n>-       *  Returns `a.allocate_at_least(n)`.\n>+       *  Returns `a.allocate_at_least(n)` if that is well-formed,\n>+       *  or `{ a.allocate(n), n } otherwise.\n>       */\n>-      [[nodiscard]] static constexpr auto\n>-      allocate_at_least(allocator_type __a, size_type __n)\n>-\t-> allocation_result<pointer, size_type>\n>-      { return __a.allocate_at_least(__n); }\n>+      [[nodiscard,__gnu__::__always_inline__]] static constexpr auto\n\nA newline after the attributes please\n\n>+      allocate_at_least(allocator_type& __a, size_type __n)\n>+      -> allocation_result<pointer, size_type>\n>+      {\n>+\tif constexpr (requires\n>+\t       { __a.allocate_at_least(__n); })\n\nDo we need this condition?\n\nstd::allocator guarantees that the member is available. A\nprogram-defined specialization of std::allocator needs to provide it\nto be valid in C++26.\n\n>+\t  return __a.allocate_at_least(__n);\n>+\telse\n>+\t  return { __a.allocate(__n), __n };\n>+      }\n> #endif\n>\n>       /**\n>@@ -822,6 +836,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       static void*\n>       allocate(allocator_type&, size_type, const void* = nullptr) = delete;\n>\n>+#ifdef __glibcxx_allocate_at_least\n>+      static allocation_result<pointer, size_type>\n>+      allocate_at_least(allocator_type&, size_type) = delete;\n>+#endif\n>+\n>       /// deallocate is ill-formed for allocator<void>\n>       static void\n>       deallocate(allocator_type&, void*, size_type) = delete;\n>@@ -874,6 +893,31 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>     };\n> #endif\n>\n>+#ifdef __glibcxx_allocate_at_least\n>+  template <typename _Pointer, typename _Size, typename _Alloc_fn>\n>+    [[nodiscard]] constexpr auto\n>+    __allocate_to_alignment(_Size __n, _Alloc_fn&& __af)\n\nThis function is used in exactly one place, and is specific to\noperator new because of the use of __STDCPP_DEFAULT_NEW_ALIGNMENT__ so\nI think it would be better to just inline this code into\n__new_allocator::allocate_at_least, or make this a private static\nmember function of __new_allocator.\n\nThat way we know that n * objsize won't overflow (because we know that\nit's already been checked by __new_allocator, whereas here it's\ncallable by any arbitrary code which might not have checked that).\n\nI also don't like passing in the allocation function, that seems ugly\nand potentially an optimization barrier.\n\n>+    -> allocation_result<_Pointer, _Size>\n>+    {\n>+      const _Size __align_mask = __STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1;\n>+      const _Size __objsize = sizeof(*declval<_Pointer>());\n>+      if constexpr (__objsize > __align_mask)\n>+\treturn { __af(__n * __objsize), __n };\n>+      else\n>+\t{\n>+\t  const _Size __need = __n * __objsize;\n>+\t  _Size __ask = (__need + __align_mask) & ~__align_mask;\n>+\t  // Avoid rounding up to and asking for 2^63 bytes (PR108377):\n>+\t  __ask -= rotl(__ask, 1) & 1;\n\nDoes this optimize as well as:\n\n     __ask -= bool(__ask & (_Size(1) << (__SIZE_WIDTH__ - 1)));\n\n?\n\n>+\t  using _U8 = const unsigned char;\n>+\t  static_assert(__objsize <= ~_U8());\n>+\t  // Use 8-bit division:\n\nWhy?\n\n>+\t  _U8 __spare = __ask - __need, __size = __objsize;\n>+\t  return { __af(__ask), __n + __spare / __size };\n>+\t}\n>+    }\n>+#endif\n>+\n>   /// @cond undocumented\n> #pragma GCC diagnostic push\n> #pragma GCC diagnostic ignored \"-Wc++17-extensions\" // if constexpr\n>diff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h\n>index 9c22c805ebe..790edfaba41 100644\n>--- a/libstdc++-v3/include/bits/allocator.h\n>+++ b/libstdc++-v3/include/bits/allocator.h\n>@@ -193,9 +193,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       constexpr _Tp*\n>       allocate(size_t __n)\n>       {\n>-#if __cpp_concepts\n>+# if __cpp_concepts\n> \tif constexpr (requires { sizeof(_Tp); })\n>-#endif\n>+# endif\n> \tif (std::__is_constant_evaluated())\n> \t  {\n> \t    if (__builtin_mul_overflow(__n, sizeof(_Tp), &__n))\n>@@ -205,7 +205,25 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n> \treturn __allocator_base<_Tp>::allocate(__n, 0);\n>       }\n>+#endif\n>+\n>+#ifdef __glibcxx_allocate_at_least  // C++23\n>+      [[nodiscard,__gnu__::__always_inline__]]\n>+      constexpr auto\n>+      allocate_at_least(size_t __n)\n>+      -> allocation_result<_Tp*, size_t>\n>+      {\n>+\tif (std::is_constant_evaluated())\n\nIt's preferable to use if consteval in code that doesn't need to\ncompile as <= C++20. It is less work for the compiler.\n\n>+\t  return { allocate(__n), __n };\n>+\telse if constexpr (requires\n>+\t       { __allocator_base<_Tp>::allocate_at_least(__n); })\n>+\t  return __allocator_base<_Tp>::allocate_at_least(__n);\n>+\telse\n>+\t  return { __allocator_base<_Tp>::allocate(__n, 0), __n };\n\nYou don't need to pass a hint argument to allocate\n(we might remove the second parameter some day, since the two-argument\nform of std::allocator::allocate was deprecated and removed).\n\n>+      }\n>+#endif\n>\n>+#if __cpp_constexpr_dynamic_alloc // >= C++20\n>       [[__gnu__::__always_inline__]]\n>       constexpr void\n>       deallocate(_Tp* __p, size_t __n)\n>@@ -219,12 +237,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>       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 b/libstdc++-v3/include/bits/basic_string.h\n>index af4e5d9486f..98bffa50f32 100644\n>--- a/libstdc++-v3/include/bits/basic_string.h\n>+++ b/libstdc++-v3/include/bits/basic_string.h\n>@@ -135,20 +135,35 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n> #endif\n>\n>     private:\n>+      // For ABI reasons this must remain, though unused in active code.\n>       static _GLIBCXX20_CONSTEXPR pointer\n>       _S_allocate(_Char_alloc_type& __a, size_type __n)\n>+      { return _S_allocate_at_least(__a, __n).__ptr; }\n\nThis means that all callers of this function in objects compiled with\nolder versions of GCC will now execute the extra instructions in\nallocate_at_least to round up the size, and then ignore it. That goes\nagainst \"you don't pay for what you don't use\".\n\nIt seems better to keep the old behaviour of this function.\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>-\tpointer __p = _Alloc_traits::allocate(__a, __n);\n>+\t_Alloc_result __r;\n>+#ifdef __glibcxx_allocate_at_least  // C++23\n>+\tauto [__ptr, __count] = _Alloc_traits::allocate_at_least(__a, __n);\n>+\t__r.__ptr = __ptr;\n>+\t__r.__count = __count;\n>+#else\n>+\t__r.__ptr = _Alloc_traits::allocate(__a, __n);\n>+\t__r.__count = __n;\n>+#endif\n> #if __glibcxx_constexpr_string >= 201907L\n> \t// std::char_traits begins the lifetime of characters,\n> \t// but custom traits might not, so do it here.\n> \tif constexpr (!is_same_v<_Traits, char_traits<_CharT>>)\n> \t  if (std::__is_constant_evaluated())\n> \t    // Begin the lifetime of characters in allocated storage.\n>-\t    for (size_type __i = 0; __i < __n; ++__i)\n>-\t      std::construct_at(__builtin_addressof(__p[__i]));\n>+\t    for (size_type __i = 0; __i < __r.__count; ++__i)\n>+\t      std::construct_at(__builtin_addressof(__r.__ptr[__i]));\n> #endif\n>-\treturn __p;\n>+\treturn __r;\n>       }\n>\n> #ifdef __glibcxx_string_view // >= C++17\n>@@ -287,6 +302,15 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n>\n>       // Create & Destroy\n>       _GLIBCXX20_CONSTEXPR\n>+      _Alloc_result\n>+      _M_create_plus(size_type __new_capacity, size_type __old_capacity);\n>+\n>+      _GLIBCXX20_CONSTEXPR\n>+      void\n>+      _M_create_and_place(size_type __new_capacity, size_type __old_capacity);\n>+\n>+      // This must remain for ABI stability though unused.\n>+      _GLIBCXX20_CONSTEXPR\n>       pointer\n>       _M_create(size_type&, size_type);\n>\n>@@ -1782,10 +1806,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11\n> \t\t    const auto __len = __str.size();\n> \t\t    auto __alloc = __str._M_get_allocator();\n> \t\t    // If this allocation throws there are no effects:\n>-\t\t    auto __ptr = _S_allocate(__alloc, __len + 1);\n>+\t\t    auto __r = _S_allocate_at_least(__alloc, __len + 1);\n> \t\t    _M_destroy(_M_allocated_capacity);\n>-\t\t    _M_data(__ptr);\n>-\t\t    _M_capacity(__len);\n>+\t\t    _M_data(__r.__ptr);\n>+\t\t    _M_capacity(__r.__count - 1);\n> \t\t    _M_set_length(__len);\n> \t\t  }\n> \t      }\n>diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc\n>index b00dd550237..aaf8df26b1a 100644\n>--- a/libstdc++-v3/include/bits/basic_string.tcc\n>+++ b/libstdc++-v3/include/bits/basic_string.tcc\n>@@ -139,14 +139,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n>   template<typename _CharT, typename _Traits, typename _Alloc>\n>     _GLIBCXX20_CONSTEXPR\n>-    typename basic_string<_CharT, _Traits, _Alloc>::pointer\n>+    typename basic_string<_CharT, _Traits, _Alloc>::_Alloc_result\n>     basic_string<_CharT, _Traits, _Alloc>::\n>-    _M_create(size_type& __capacity, size_type __old_capacity)\n>+    _M_create_plus(size_type __capacity, size_type __old_capacity)\n>     {\n>       // _GLIBCXX_RESOLVE_LIB_DEFECTS\n>       // 83.  String::npos vs. string::max_size()\n>       if (__capacity > max_size())\n>-\tstd::__throw_length_error(__N(\"basic_string::_M_create\"));\n>+\tstd::__throw_length_error(__N(\"basic_string::_M_create_plus\"));\n>\n>       // The below implements an exponential growth policy, necessary to\n>       // meet amortized linear time requirements of the library: see\n>@@ -161,7 +161,31 @@ _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>+      return _S_allocate_at_least(_M_get_allocator(), __capacity + 1);\n>+    }\n>+\n>+\n>+  template<typename _CharT, typename _Traits, typename _Alloc>\n>+    _GLIBCXX20_CONSTEXPR\n>+    void\n>+    basic_string<_CharT, _Traits, _Alloc>::\n>+    _M_create_and_place(size_type __capacity, size_type __old_capacity)\n>+    {\n>+      _Alloc_result __r = _M_create_plus(__capacity, __old_capacity);\n>+      _M_data(__r.__ptr);\n>+      _M_capacity(__r.__count - 1);  // Leave room for NUL.\n>+    }\n>+\n>+  // This must remain for ABI stability, though unused in current code.\n>+  template<typename _CharT, typename _Traits, typename _Alloc>\n>+    _GLIBCXX20_CONSTEXPR\n>+    typename basic_string<_CharT, _Traits, _Alloc>::pointer\n>+    basic_string<_CharT, _Traits, _Alloc>::\n>+    _M_create(size_type& __capacity, size_type __old_capacity)\n>+    {\n>+      _Alloc_result __r = _M_create_plus(__capacity, __old_capacity);\n\nAgain, this makes existing callers of _M_create perform more work,\nalthough in this case they will actually use the extra capacity, so\nit's not wasted work.\n\n>+      __capacity = __r.__count - 1;  // Leave room for NUL.\n>+      return __r.__ptr;\n>     }\n>\n>   // NB: This is the special case for Input Iterators, used in\n>@@ -203,11 +227,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t    if (__len == __capacity)\n> \t      {\n> \t\t// Allocate more space.\n>-\t\t__capacity = __len + 1;\n>-\t\tpointer __another = _M_create(__capacity, __len);\n>-\t\tthis->_S_copy(__another, _M_data(), __len);\n>+\t\t_Alloc_result __another = _M_create_plus(__len + 1, __len);\n>+\t\t__capacity = __another.__count - 1; // Leave room for NUL.\n>+\t\tthis->_S_copy(__another.__ptr, _M_data(), __len);\n> \t\t_M_dispose();\n>-\t\t_M_data(__another);\n>+\t\t_M_data(__another.__ptr);\n> \t\t_M_capacity(__capacity);\n> \t      }\n> \t    traits_type::assign(_M_data()[__len++],\n>@@ -231,10 +255,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \tsize_type __dnew = static_cast<size_type>(std::distance(__beg, __end));\n>\n> \tif (__dnew > size_type(_S_local_capacity))\n>-\t  {\n>-\t    _M_data(_M_create(__dnew, size_type(0)));\n>-\t    _M_capacity(__dnew);\n>-\t  }\n>+\t  _M_create_and_place(__dnew, size_type(0));\n> \telse\n> \t  _M_init_local_buf();\n>\n>@@ -264,10 +285,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>     _M_construct(size_type __n, _CharT __c)\n>     {\n>       if (__n > size_type(_S_local_capacity))\n>-\t{\n>-\t  _M_data(_M_create(__n, size_type(0)));\n>-\t  _M_capacity(__n);\n>-\t}\n>+\t_M_create_and_place(__n, size_type(0));\n>       else\n> \t_M_init_local_buf();\n>\n>@@ -281,16 +299,13 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>   // than difference between iterators.\n>   template<typename _CharT, typename _Traits, typename _Alloc>\n>     template<bool _Terminated>\n>-    _GLIBCXX20_CONSTEXPR\n>+    _GLIBCXX20_CONSTEXPR\n>     void\n>     basic_string<_CharT, _Traits, _Alloc>::\n>     _M_construct(const _CharT* __str, size_type __n)\n>     {\n>       if (__n > size_type(_S_local_capacity))\n>-\t{\n>-\t  _M_data(_M_create(__n, size_type(0)));\n>-\t  _M_capacity(__n);\n>-\t}\n>+\t_M_create_and_place(__n, size_type(0));\n>       else\n> \t_M_init_local_buf();\n>\n>@@ -347,11 +362,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>\n> \t  if (__rsize > __capacity)\n> \t    {\n>-\t      size_type __new_capacity = __rsize;\n>-\t      pointer __tmp = _M_create(__new_capacity, __capacity);\n>+\t      // if _M_create_plus throws, there is no effect.\n>+\t      _Alloc_result __tmp = _M_create_plus(__rsize, __capacity);\n> \t      _M_dispose();\n>-\t      _M_data(__tmp);\n>-\t      _M_capacity(__new_capacity);\n>+\t      _M_data(__tmp.__ptr);\n>+\t      _M_capacity(__tmp.__count - 1);\n> \t    }\n>\n> \t  if (__rsize)\n>@@ -375,11 +390,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       if (__res <= __capacity)\n> \treturn;\n>\n>-      pointer __tmp = _M_create(__res, __capacity);\n>-      this->_S_copy(__tmp, _M_data(), length() + 1);\n>+      _Alloc_result __r = _M_create_plus(__res, __capacity);\n>+      this->_S_copy(__r.__ptr, _M_data(), length() + 1);\n>       _M_dispose();\n>-      _M_data(__tmp);\n>-      _M_capacity(__res);\n>+      _M_data(__r.__ptr);\n>+      _M_capacity(__r.__count - 1);  // Leave room for NUL.\n>     }\n>\n>   template<typename _CharT, typename _Traits, typename _Alloc>\n>@@ -392,19 +407,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       const size_type __how_much = length() - __pos - __len1;\n>\n>       size_type __new_capacity = length() + __len2 - __len1;\n>-      pointer __r = _M_create(__new_capacity, capacity());\n>+      _Alloc_result __r = _M_create_plus(__new_capacity, capacity());\n>\n>       if (__pos)\n>-\tthis->_S_copy(__r, _M_data(), __pos);\n>+\tthis->_S_copy(__r.__ptr, _M_data(), __pos);\n>       if (__s && __len2)\n>-\tthis->_S_copy(__r + __pos, __s, __len2);\n>+\tthis->_S_copy(__r.__ptr + __pos, __s, __len2);\n>       if (__how_much)\n>-\tthis->_S_copy(__r + __pos + __len2,\n>+\tthis->_S_copy(__r.__ptr + __pos + __len2,\n> \t\t      _M_data() + __pos + __len1, __how_much);\n>\n>       _M_dispose();\n>-      _M_data(__r);\n>-      _M_capacity(__new_capacity);\n>+      _M_data(__r.__ptr);\n>+      _M_capacity(__r.__count - 1);  // Leave room for NUL.\n>     }\n>\n>   template<typename _CharT, typename _Traits, typename _Alloc>\n>@@ -430,6 +445,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       if (_M_is_local())\n> \treturn;\n>\n>+# ifdef __glibcxx_allocate_at_least  // C++23\n>+      const size_type __limit = (__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1) / sizeof(_CharT);\n>+# else\n>+      const size_type __limit = 0;\n>+# endif\n>       const size_type __length = length();\n>       const size_type __capacity = _M_allocated_capacity;\n>\n>@@ -441,14 +461,15 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t  _M_data(_M_local_data());\n> \t}\n> #if __cpp_exceptions\n>-      else if (__length < __capacity)\n>+      else if (__capacity - __length > __limit )\n> \ttry\n> \t  {\n>-\t    pointer __tmp = _S_allocate(_M_get_allocator(), __length + 1);\n>-\t    this->_S_copy(__tmp, _M_data(), __length + 1);\n>+\t    _Alloc_result __r = _S_allocate_at_least(\n>+\t      _M_get_allocator(), __length + 1);\n>+\t    this->_S_copy(__r.__ptr, _M_data(), __length + 1);\n> \t    _M_dispose();\n>-\t    _M_data(__tmp);\n>-\t    _M_capacity(__length);\n>+\t    _M_data(__r.__ptr);\n>+\t    _M_capacity(__r.__count - 1);  // reserve room for NUL.\n> \t  }\n> \tcatch (const __cxxabiv1::__forced_unwind&)\n> \t  { throw; }\n>@@ -588,7 +609,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> #if __cpp_lib_is_constant_evaluated\n> \t  if (std::is_constant_evaluated())\n> \t    {\n>-\t      auto __newp = _S_allocate(_M_get_allocator(), __new_size);\n>+\t      auto __newp =\n>+\t\t_S_allocate_at_least(_M_get_allocator(), __new_size).__ptr;\n\nIf this branch isn't going to use the excess capacity, why bother\nusing _S_allocate_at_least? _S_allocate seems simpler here.\n\n> \t      _S_copy(__newp, this->_M_data(), __pos);\n> \t      _S_copy(__newp + __pos, __s, __len2);\n> \t      _S_copy(__newp + __pos + __len2, __p + __len1, __how_much);\n>@@ -677,7 +699,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> #endif // C++11\n>\n> #endif  // _GLIBCXX_USE_CXX11_ABI\n>-\n>+\n> #if __glibcxx_constexpr_string >= 201907L\n> # define _GLIBCXX_STRING_CONSTEXPR constexpr\n> #else\n>@@ -916,7 +938,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t      // Avoid reallocation for common case.\n> \t      __str.erase();\n> \t      _CharT __buf[128];\n>-\t      __size_type __len = 0;\t\n>+\t      __size_type __len = 0;\n> \t      const streamsize __w = __in.width();\n> \t      const __size_type __n = __w > 0 ? static_cast<__size_type>(__w)\n> \t\t                              : __str.max_size();\n>diff --git a/libstdc++-v3/include/bits/memory_resource.h b/libstdc++-v3/include/bits/memory_resource.h\n>index e5c6697b07e..0a0f799437b 100644\n>--- a/libstdc++-v3/include/bits/memory_resource.h\n>+++ b/libstdc++-v3/include/bits/memory_resource.h\n>@@ -48,6 +48,7 @@\n> # include <bits/utility.h>\t\t// index_sequence\n> # include <tuple>\t\t\t// tuple, forward_as_tuple\n> #endif\n>+#include <bits/memoryfwd.h>\n>\n> namespace std _GLIBCXX_VISIBILITY(default)\n> {\n>@@ -468,6 +469,30 @@ 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 `m >= n`\n>+       *          objects of type `value_type`, and `m`.\n>+       *\n>+       *  Returns `a.allocate_at_least(n)` if it exists, otherwise\n>+       *  `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>+      {\n>+\tif constexpr (requires { __a.allocate_at_least(__n); })\n\npmr::polymorphic_allocator doesn't have allocate_at_least so this\ncondition is never true.\n\nWe do want allocate_at_least in this allocator_traits partial\nspecialization but it should just return { __a.allocate(__n), __n}\nunconditionally.\n\n>+\t  {\n>+\t    auto [__p, __c] =    __a.allocate_at_least(__n);\n>+\t    return { __p, __c };  // Enable conversion en route.\n>+\t  }\n>+\telse return { __a.allocate(__n), __n };\n>+      }\n>+#endif\n>+\n>       /**\n>        *  @brief  Deallocate memory.\n>        *  @param  __a  An allocator.\n>diff --git a/libstdc++-v3/include/bits/memoryfwd.h b/libstdc++-v3/include/bits/memoryfwd.h\n>index 9efe72b38ba..6742f75499e 100644\n>--- a/libstdc++-v3/include/bits/memoryfwd.h\n>+++ b/libstdc++-v3/include/bits/memoryfwd.h\n>@@ -88,8 +88,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n>       _Pointer ptr;\n>       _Size count;\n>     };\n>-#endif\n>\n>+  template <typename _Pointer, typename _Size, typename _Alloc_fn>\n>+    [[nodiscard]] constexpr auto\n>+    __allocate_to_alignment(_Size __n, _Alloc_fn&& __af)\n>+    -> allocation_result<_Pointer, _Size>;\n>+#endif\n>\n>   /// @} group memory\n>\n>diff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h\n>index fbe03e392aa..9a3f245f2aa 100644\n>--- a/libstdc++-v3/include/bits/new_allocator.h\n>+++ b/libstdc++-v3/include/bits/new_allocator.h\n>@@ -37,6 +37,7 @@\n> #if __cplusplus >= 201103L\n> #include <type_traits>\n> #endif\n>+#include <bits/memoryfwd.h>\n>\n> namespace std _GLIBCXX_VISIBILITY(default)\n> {\n>@@ -150,6 +151,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t      std::__throw_bad_array_new_length();\n> \t    std::__throw_bad_alloc();\n> \t  }\n>+\n> #if __cpp_aligned_new && __cplusplus >= 201103L\n> \telse if constexpr (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)\n> \t  {\n>@@ -162,6 +164,41 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t  return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__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>+\tstatic_assert(requires { sizeof(_Tp); },\n>+\t  \"cannot allocate incomplete types\");\n>+\n>+\tif constexpr (!requires { sizeof(_Tp); })\n>+\t  return { nullptr, 0 }; // static_assert already failed\n>+\telse if (__builtin_expect(__n > this->_M_max_size(), false))\n>+\t  {\n>+\t    // _GLIBCXX_RESOLVE_LIB_DEFECTS\n>+\t    // 3190. allocator::allocate sometimes returns too little storage\n>+\t    if (__n > (std::size_t(-1) / sizeof(_Tp)))\n>+\t      std::__throw_bad_array_new_length();\n>+\t    std::__throw_bad_alloc();\n>+\t  }\n>+\telse if (std::__is_constant_evaluated())\n\nThis should be 'if consteval'\n\n>+\t  {\n>+\t    auto __p = _GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp));\n>+\t    return { static_cast<_Tp*>(__p), __n };\n>+\t  }\n>+\telse if constexpr (alignof(_Tp) > __STDCPP_DEFAULT_NEW_ALIGNMENT__)\n>+\t  {\n>+\t    const std::align_val_t __al = std::align_val_t(alignof(_Tp));\n>+\t    auto __p = _GLIBCXX_OPERATOR_NEW(__n * sizeof(_Tp), __al);\n>+\t    return { static_cast<_Tp*>(__p), __n };\n>+\t  }\n>+\telse\n>+\t  return __allocate_to_alignment<_Tp*>(__n, [](size_t __bytes)\n>+\t   { return static_cast<_Tp*>(_GLIBCXX_OPERATOR_NEW(__bytes)); });\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>@@ -177,10 +214,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n> \t  {\n> \t    _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n),\n> \t\t\t\t     std::align_val_t(alignof(_Tp)));\n>-\t    return;\n> \t  }\n>+\telse\n> #endif\n>-\t_GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));\n>+\t  _GLIBCXX_OPERATOR_DELETE(_GLIBCXX_SIZED_DEALLOC(__p, __n));\n>       }\n>\n> #pragma GCC diagnostic pop\n>diff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h\n>index c4ca214752a..4efe3d0f9d2 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>+\t// std::distance(begin(), end()) cannot be greater than PTRDIFF_MAX,\n>+\t// and realistically we can't store more than PTRDIFF_MAX/sizeof(T)\n>+\t// (even if std::allocator_traits::max_size says we can).\n>+\tconst size_t __diffmax =\n>+\t  __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);\n>+\tconst size_t __allocmax =\n>+\t  __gnu_cxx::__alloc_traits<_Alloc>::max_size(__a);\n>+\treturn (std::min)(__diffmax, __allocmax);\n>+      }\n>+\n> #if __cplusplus >= 201103L\n>       _Vector_base() = default;\n> #else\n>@@ -384,9 +397,37 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       _GLIBCXX20_CONSTEXPR\n>       pointer\n>       _M_allocate(size_t __n)\n>+      { return _M_allocate_at_least(__n).__ptr; }\n\nThis also does the rounding up work, then ignores it.\n\n>+\n>+      struct _Alloc_result { pointer __ptr; size_t __count; };\n>+\n>+      _GLIBCXX20_CONSTEXPR\n>+      _Alloc_result\n>+      _M_allocate_at_least(size_t __n)\n>       {\n> \ttypedef __gnu_cxx::__alloc_traits<_Tp_alloc_type> _Tr;\n>-\treturn __n != 0 ? _Tr::allocate(_M_impl, __n) : pointer();\n>+\t_Alloc_result __r;\n>+\tif (__builtin_expect(__n != 0, true))\n>+\t  {\n>+#ifdef __glibcxx_allocate_at_least  // C++23\n>+\t    if constexpr (\n>+\t\trequires(_Tp_alloc_type& __a, size_t __n) { _Tr::allocate_at_least(__a, __n); })\n>+\t      {\n>+\t\tauto [__ptr, __count] = _Tr::allocate_at_least(_M_impl, __n);\n>+\t\tif (__count > __n)\n>+\t\t  {\n>+\t\t    size_t __max = _S_max_size(_M_get_Tp_allocator());\n>+\t\t    if (__builtin_expect(__count > __max, false))\n>+\t\t      __count = __max;\n>+\t\t  }\n>+\t\t__r.__ptr = __ptr, __r.__count = __count;\n\nSeparate statements for the assignments please.\n\n>+\t      }\n>+\t    else\n>+#endif\n>+\t      __r.__ptr = _Tr::allocate(_M_impl, __n), __r.__count = __n;\n>+\t  }\n>+\telse __r.__ptr = pointer(), __r.__count = 0;\n\nAnd again, although this line could be avoided by initializing __r\nusing {}.\n\n>+\treturn __r;\n>       }\n>\n>       _GLIBCXX20_CONSTEXPR\n>@@ -404,9 +445,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       void\n>       _M_create_storage(size_t __n)\n>       {\n>-\tthis->_M_impl._M_start = this->_M_allocate(__n);\n>-\tthis->_M_impl._M_finish = this->_M_impl._M_start;\n>-\tthis->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;\n>+\t_Alloc_result __r = this->_M_allocate_at_least(__n);\n>+\tthis->_M_impl._M_finish = this->_M_impl._M_start = __r.__ptr;\n>+\tthis->_M_impl._M_end_of_storage = this->_M_impl._M_start + __r.__count;\n>       }\n>\n> #if __glibcxx_containers_ranges // C++ >= 23\n>@@ -480,6 +521,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       typedef _Vector_base<_Tp, _Alloc>\t\t\t_Base;\n>       typedef typename _Base::_Tp_alloc_type\t\t_Tp_alloc_type;\n>       typedef __gnu_cxx::__alloc_traits<_Tp_alloc_type>\t_Alloc_traits;\n>+      typedef typename _Base::_Alloc_result             _Alloc_result;\n>\n>     public:\n>       typedef _Tp\t\t\t\t\tvalue_type;\n>@@ -536,6 +578,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\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 +1159,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 +1725,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t  return;\n> \t\t}\n>\n>-\t      const size_type __len = _M_check_len(__n, \"vector::append_range\");\n>+\t      const size_type __ask = _M_check_len(__n, \"vector::append_range\");\n>\n> \t      pointer __old_start = this->_M_impl._M_start;\n> \t      pointer __old_finish = this->_M_impl._M_finish;\n>\n>-\t      allocator_type& __a = _M_get_Tp_allocator();\n>-\t      const pointer __start = this->_M_allocate(__len);\n>+\t      auto [__ptr, __got] = this->_M_allocate_at_least(__ask);\n>+\t      const pointer __start = __ptr;\n> \t      const pointer __mid = __start + __sz;\n> \t      const pointer __back = __mid + __n;\n>-\t      _Guard_alloc __guard(__start, __len, *this);\n>+\t      _Guard_alloc __guard(__start, __got, *this);\n>+\t      allocator_type& __a = _M_get_Tp_allocator();\n> \t      std::__uninitialized_copy_a(ranges::begin(__rg),\n> \t\t\t\t\t  ranges::end(__rg),\n> \t\t\t\t\t  __mid, __a);\n>@@ -1733,7 +1777,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      // Finally, take ownership of new storage:\n> \t      this->_M_impl._M_start = __start;\n> \t      this->_M_impl._M_finish = __back;\n>-\t      this->_M_impl._M_end_of_storage = __start + __len;\n>+\t      this->_M_impl._M_end_of_storage = __start + __got;\n> \t    }\n> \t  else\n> \t    {\n>@@ -1889,20 +1933,45 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>     protected:\n>       /**\n>        *  Memory expansion handler.  Uses the member allocation function to\n>-       *  obtain @a n bytes of memory, and then copies [first,last) into it.\n>+       *  obtain at least `n` objects worth of memory, copies `[first,last)`\n>+       *  into it, reports what was actually allocated.\n>        */\n>       template<typename _ForwardIterator>\n> \t_GLIBCXX20_CONSTEXPR\n>-\tpointer\n>-\t_M_allocate_and_copy(size_type __n,\n>-\t\t\t     _ForwardIterator __first, _ForwardIterator __last)\n>+\t_Alloc_result\n>+\t_M_allocate_and_copy(\n>+\t  size_type __n, _ForwardIterator __first, _ForwardIterator __last)\n\nThe parameter formatting was correct before this change.\n\n> \t{\n>-\t  _Guard_alloc __guard(this->_M_allocate(__n), __n, *this);\n>+\t  _Alloc_result __r = this->_M_allocate_at_least(__n);\n>+\t  _Guard_alloc __guard(__r.__ptr, __r.__count, *this);\n> \t  std::__uninitialized_copy_a\n> \t    (__first, __last, __guard._M_storage, _M_get_Tp_allocator());\n>-\t  return __guard._M_release();\n>+\t  (void) __guard._M_release();\n>+\t  return __r;\n> \t}\n>\n>+      _GLIBCXX20_CONSTEXPR void\n>+      _M_displace_storage(pointer __start, pointer __end, size_type __cap)\n\nWould _M_replace_storage be a better name?\n\n\"displace\" has three meanings, one of which is to take the place of\nsomething else (the intended meaning here, where the new storage\nreplaces the old), but another meaning is to just push something out\nof its place. So at the call site, if I read \"displace storage\" I\ndon't know what it's doing.\n\n\n>+      {\n>+\t  _GLIBCXX_ASAN_ANNOTATE_REINIT;\n>+\t  _M_deallocate(this->_M_impl._M_start,\n>+\t    this->_M_impl._M_end_of_storage - this->_M_impl._M_start);\n>+\t  this->_M_impl._M_start = __start;\n>+\t  this->_M_impl._M_finish = __end;\n>+\t  this->_M_impl._M_end_of_storage = __start + __cap;\n>+      }\n>+\n>+      template<typename _ForwardIterator>\n>+\t_GLIBCXX20_CONSTEXPR\n>+\tvoid\n>+\t_M_allocate_and_migrate(\n\nThis name doesn't tell me what it does either, \"migrate\" doesn't tell\nme that it makes a copy of [first, last) rather than migrating\nsomething *to* that range.\n\nWould _M_replace_with be better? The fact it allocates isn't really\nthe more pertinent thing about this function, what it does is replace\nthe current storage with new storage containing a copy of the range\n[first, last).\n\n>+\t  size_type __n, _ForwardIterator __first, _ForwardIterator __last)\n\nIncorrect formatting again.\n\n>+\t{\n>+\t  _Alloc_result __r = _M_allocate_and_copy(__n, __first, __last);\n>+\t  std::_Destroy(this->_M_impl._M_start,\n>+\t    this->_M_impl._M_finish, _M_get_Tp_allocator());\n>+\t  _M_displace_storage(__r.__ptr, __r.__ptr + __n, __r.__count);\n>+\t}\n>\n>       // Internal constructor functions follow.\n>\n>@@ -1971,10 +2040,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t_M_range_initialize_n(_Iterator __first, _Sentinel __last,\n> \t\t\t      size_type __n)\n> \t{\n>-\t  pointer __start =\n>-\t    this->_M_allocate(_S_check_init_len(__n, _M_get_Tp_allocator()));\n>+\t  _Alloc_result __r = this->_M_allocate_at_least(\n>+\t    _S_check_init_len(__n, _M_get_Tp_allocator()));\n>+\t  pointer __start = __r.__ptr;\n> \t  this->_M_impl._M_start = this->_M_impl._M_finish = __start;\n>-\t  this->_M_impl._M_end_of_storage = __start + __n;\n>+\t  this->_M_impl._M_end_of_storage = __start + __r.__count;\n> \t  this->_M_impl._M_finish\n> \t      = std::__uninitialized_copy_a(_GLIBCXX_MOVE(__first), __last,\n> \t\t\t\t\t    __start, _M_get_Tp_allocator());\n>@@ -2191,35 +2261,27 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       size_type\n>       _M_check_len(size_type __n, const char* __s) const\n>       {\n>-\tif (max_size() - size() < __n)\n>+\tconst size_type __room = max_size() - size();\n>+\tif (__room < __n)\n> \t  __throw_length_error(__N(__s));\n>\n>-\tconst size_type __len = size() + (std::max)(size(), __n);\n>-\treturn (__len < size() || __len > max_size()) ? max_size() : __len;\n>+\tif (__n < size())\n>+\t  __n = size();  // Grow by (at least) doubling ...\n>+\tif (__n > __room)\n>+\t  __n = __room;  //  ... but only as much as will fit.\n>+\treturn 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>-\tif (__n > _S_max_size(_Tp_alloc_type(__a)))\n>+\tif (__n > _Base::_S_max_size(_Tp_alloc_type(__a)))\n> \t  __throw_length_error(\n> \t      __N(\"cannot create std::vector larger than max_size()\"));\n> \treturn __n;\n>       }\n>\n>-      static _GLIBCXX20_CONSTEXPR size_type\n>-      _S_max_size(const _Tp_alloc_type& __a) _GLIBCXX_NOEXCEPT\n>-      {\n>-\t// std::distance(begin(), end()) cannot be greater than PTRDIFF_MAX,\n>-\t// and realistically we can't store more than PTRDIFF_MAX/sizeof(T)\n>-\t// (even if std::allocator_traits::max_size says we can).\n>-\tconst size_t __diffmax\n>-\t  = __gnu_cxx::__numeric_traits<ptrdiff_t>::__max / sizeof(_Tp);\n>-\tconst size_t __allocmax = _Alloc_traits::max_size(__a);\n>-\treturn (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 b/libstdc++-v3/include/bits/vector.tcc\n>index b790fca2964..86da54bdff1 100644\n>--- a/libstdc++-v3/include/bits/vector.tcc\n>+++ b/libstdc++-v3/include/bits/vector.tcc\n>@@ -75,13 +75,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       if (this->capacity() < __n)\n> \t{\n> \t  const size_type __old_size = size();\n>-\t  pointer __tmp;\n>+\t  _Alloc_result __tmp;\n> #if __cplusplus >= 201103L\n> \t  if constexpr (_S_use_relocate())\n> \t    {\n>-\t      __tmp = this->_M_allocate(__n);\n>+\t      __tmp = this->_M_allocate_at_least(__n);\n> \t      std::__relocate_a(this->_M_impl._M_start, this->_M_impl._M_finish,\n>-\t\t\t\t__tmp, _M_get_Tp_allocator());\n>+\t\t\t\t__tmp.__ptr, _M_get_Tp_allocator());\n> \t    }\n> \t  else\n> #endif\n>@@ -92,13 +92,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,\n> \t\t\t    _M_get_Tp_allocator());\n> \t    }\n>-\t  _GLIBCXX_ASAN_ANNOTATE_REINIT;\n>-\t  _M_deallocate(this->_M_impl._M_start,\n>-\t\t\tthis->_M_impl._M_end_of_storage\n>-\t\t\t- this->_M_impl._M_start);\n>-\t  this->_M_impl._M_start = __tmp;\n>-\t  this->_M_impl._M_finish = __tmp + __old_size;\n>-\t  this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __n;\n>+\t  _M_displace_storage(\n>+\t    __tmp.__ptr, __tmp.__ptr + __old_size, __tmp.__count);\n> \t}\n>     }\n> #pragma GCC diagnostic pop\n>@@ -106,12 +101,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 +120,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t  }\n> \telse\n> \t  _M_realloc_append(std::forward<_Args>(__args)...);\n>-#if __cplusplus > 201402L\n>+# if __cplusplus > 201402L\n> \treturn back();\n>-#endif\n>+# endif\n>       }\n>-#endif\n>+#endif  // __cplusplus >= 201103L\n>\n>   template<typename _Tp, typename _Alloc>\n>     _GLIBCXX20_CONSTEXPR\n>@@ -238,22 +233,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> #endif\n> \t  const size_type __xlen = __x.size();\n> \t  if (__xlen > capacity())\n>-\t    {\n>-\t      pointer __tmp = _M_allocate_and_copy(__xlen, __x.begin(),\n>-\t\t\t\t\t\t   __x.end());\n>-\t      std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,\n>-\t\t\t    _M_get_Tp_allocator());\n>-\t      _M_deallocate(this->_M_impl._M_start,\n>-\t\t\t    this->_M_impl._M_end_of_storage\n>-\t\t\t    - this->_M_impl._M_start);\n>-\t      this->_M_impl._M_start = __tmp;\n>-\t      this->_M_impl._M_end_of_storage = this->_M_impl._M_start + __xlen;\n>-\t    }\n>+\t    _M_allocate_and_migrate(__xlen, __x.begin(), __x.end());\n> \t  else if (size() >= __xlen)\n>-\t    {\n>-\t      std::_Destroy(std::copy(__x.begin(), __x.end(), begin()),\n>-\t\t\t    end(), _M_get_Tp_allocator());\n>-\t    }\n>+\t    std::_Destroy(std::copy(__x.begin(), __x.end(), begin()),\n>+\t      end(), _M_get_Tp_allocator());\n> \t  else\n> \t    {\n> \t      std::copy(__x._M_impl._M_start, __x._M_impl._M_start + size(),\n>@@ -332,16 +315,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      __builtin_unreachable();\n>\n> \t    _S_check_init_len(__len, _M_get_Tp_allocator());\n>-\t    pointer __tmp(_M_allocate_and_copy(__len, __first, __last));\n>-\t    std::_Destroy(this->_M_impl._M_start, this->_M_impl._M_finish,\n>-\t\t\t  _M_get_Tp_allocator());\n>-\t    _GLIBCXX_ASAN_ANNOTATE_REINIT;\n>-\t    _M_deallocate(this->_M_impl._M_start,\n>-\t\t\t  this->_M_impl._M_end_of_storage\n>-\t\t\t  - this->_M_impl._M_start);\n>-\t    this->_M_impl._M_start = __tmp;\n>-\t    this->_M_impl._M_finish = this->_M_impl._M_start + __len;\n>-\t    this->_M_impl._M_end_of_storage = this->_M_impl._M_finish;\n>+\t    _M_allocate_and_migrate(__len, __first, __last);\n> \t  }\n> \telse if (__sz >= __len)\n> \t  _M_erase_at_end(std::copy(__first, __last, this->_M_impl._M_start));\n>@@ -464,13 +438,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, \"vector::_M_realloc_insert\");\n>-      if (__len <= 0)\n>+      const size_type __len1 = _M_check_len(1u, \"vector::_M_realloc_insert\");\n>+      if (__len1 <= 0)\n> \t__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 +550,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n>       const size_type __len = _M_check_len(1u, \"vector::_M_realloc_append\");\n>       if (__len <= 0)\n> \t__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>-\t_Guard_alloc __guard(__new_start, __len, *this);\n>+\t_Guard_alloc __guard(__new_start, __rlen, *this);\n>\n> \t// The order of the three operations is dictated by the C++11\n> \t// case, where the moves could alter a new element belonging\n>@@ -652,7 +630,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 +694,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      pointer __old_finish = this->_M_impl._M_finish;\n> \t      const pointer __pos = __position.base();\n>\n>-\t      const size_type __len =\n>+\t      const size_type __len1 =\n> \t\t_M_check_len(__n, \"vector::_M_fill_insert\");\n> \t      const size_type __elems_before = __pos - __old_start;\n>-\t      pointer __new_start(this->_M_allocate(__len));\n>+\t      _Alloc_result __r = this->_M_allocate_at_least(__len1);\n>+\t      const size_type __len = __r.__count;\n>+\t      pointer __new_start(__r.__ptr);\n> \t      pointer __new_finish(__new_start);\n> \t      __try\n> \t\t{\n>@@ -727,21 +707,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t  std::__uninitialized_fill_n_a(__new_start + __elems_before,\n> \t\t\t\t\t\t__n, __x,\n> \t\t\t\t\t\t_M_get_Tp_allocator());\n>-\t\t  __new_finish = pointer();\n>-\n>-\t\t  __new_finish\n>-\t\t    = std::__uninitialized_move_if_noexcept_a\n>-\t\t    (__old_start, __pos, __new_start, _M_get_Tp_allocator());\n>-\n>+\t\t  __new_finish = pointer();  // ... in case of a throw.\n>+\t\t  __new_finish = std::__uninitialized_move_if_noexcept_a(\n>+\t\t      __old_start, __pos, __new_start, _M_get_Tp_allocator());\n> \t\t  __new_finish += __n;\n>-\n>-\t\t  __new_finish\n>-\t\t    = std::__uninitialized_move_if_noexcept_a\n>-\t\t    (__pos, __old_finish, __new_finish, _M_get_Tp_allocator());\n>+\t\t  __new_finish = std::__uninitialized_move_if_noexcept_a(\n>+\t\t      __pos, __old_finish, __new_finish, _M_get_Tp_allocator());\n> \t\t}\n> \t      __catch(...)\n> \t\t{\n>-\t\t  if (!__new_finish)\n>+\t\t  if (__new_finish == pointer())\n> \t\t    std::_Destroy(__new_start + __elems_before,\n> \t\t\t\t  __new_start + __elems_before + __n,\n> \t\t\t\t  _M_get_Tp_allocator());\n>@@ -752,12 +727,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t  __throw_exception_again;\n> \t\t}\n> \t      std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());\n>-\t      _GLIBCXX_ASAN_ANNOTATE_REINIT;\n>-\t      _M_deallocate(__old_start,\n>-\t\t\t    this->_M_impl._M_end_of_storage - __old_start);\n>-\t      this->_M_impl._M_start = __new_start;\n>-\t      this->_M_impl._M_finish = __new_finish;\n>-\t      this->_M_impl._M_end_of_storage = __new_start + __len;\n>+\t      _M_displace_storage(__new_start, __new_finish, __len);\n> \t    }\n> \t}\n>     }\n>@@ -785,9 +755,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t   pointer __old_finish = this->_M_impl._M_finish;\n> \t   const size_type __old_size = __old_finish - __old_start;\n>\n>-\t   const size_type __len =\n>-\t     _M_check_len(__n, \"vector::_M_fill_append\");\n>-\t   pointer __new_start(this->_M_allocate(__len));\n>+\t   size_type __len = _M_check_len(__n, \"vector::_M_fill_append\");\n>+\t   _Alloc_result __r = this->_M_allocate_at_least(__len);\n>+\t   __len = __r.__count;\n>+\t   pointer __new_start(__r.__ptr);\n> \t   pointer __new_finish(__new_start + __old_size);\n> \t   __try\n> \t     {\n>@@ -807,12 +778,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t__throw_exception_again;\n> \t      }\n> \t   std::_Destroy(__old_start, __old_finish, _M_get_Tp_allocator());\n>-\t   _GLIBCXX_ASAN_ANNOTATE_REINIT;\n>-\t   _M_deallocate(__old_start,\n>-\t\t\t this->_M_impl._M_end_of_storage - __old_start);\n>-\t   this->_M_impl._M_start = __new_start;\n>-\t   this->_M_impl._M_finish = __new_finish;\n>-\t   this->_M_impl._M_end_of_storage = __new_start + __len;\n>+\t   _M_displace_storage(__new_start, __new_finish, __len);\n> \t }\n>     }\n>\n>@@ -852,9 +818,11 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      pointer __old_start = this->_M_impl._M_start;\n> \t      pointer __old_finish = this->_M_impl._M_finish;\n>\n>-\t      const size_type __len =\n>+\t      const size_type __len1 =\n> \t\t_M_check_len(__n, \"vector::_M_default_append\");\n>-\t      pointer __new_start(this->_M_allocate(__len));\n>+\t      _Alloc_result __r = this->_M_allocate_at_least(__len1);\n>+\t      const size_type __len = __r.__count;\n>+\t      pointer __new_start(__r.__ptr);\n>\n> \t      {\n> \t\t_Guard_alloc __guard(__new_start, __len, *this);\n>@@ -1003,14 +971,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\tpointer __old_start = this->_M_impl._M_start;\n> \t\tpointer __old_finish = this->_M_impl._M_finish;\n>\n>-\t\tconst size_type __len =\n>+\t\tconst size_type __ask =\n> \t\t  _M_check_len(__n, \"vector::_M_range_insert\");\n> #if __cplusplus < 201103L\n>-\t\tif (__len < (__n + (__old_finish - __old_start)))\n>+\t\tif (__ask < (__n + (__old_finish - __old_start)))\n> \t\t  __builtin_unreachable();\n> #endif\n>\n>-\t\tpointer __new_start(this->_M_allocate(__len));\n>+\t\t_Alloc_result __r = this->_M_allocate_at_least(__ask);\n>+\t\tconst size_type __got = __r.__count;\n>+\t\tpointer __new_start(__r.__ptr);\n> \t\tpointer __new_finish(__new_start);\n> \t\t__try\n> \t\t  {\n>@@ -1031,17 +1001,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t  {\n> \t\t    std::_Destroy(__new_start, __new_finish,\n> \t\t\t\t  _M_get_Tp_allocator());\n>-\t\t    _M_deallocate(__new_start, __len);\n>+\t\t    _M_deallocate(__new_start, __got);\n> \t\t    __throw_exception_again;\n> \t\t  }\n> \t\tstd::_Destroy(__old_start, __old_finish,\n> \t\t\t      _M_get_Tp_allocator());\n>-\t\t_GLIBCXX_ASAN_ANNOTATE_REINIT;\n>-\t\t_M_deallocate(__old_start,\n>-\t\t\t      this->_M_impl._M_end_of_storage - __old_start);\n>-\t\tthis->_M_impl._M_start = __new_start;\n>-\t\tthis->_M_impl._M_finish = __new_finish;\n>-\t\tthis->_M_impl._M_end_of_storage = __new_start + __len;\n>+\t\t_M_displace_storage(__new_start, __new_finish, __got);\n> \t      }\n> \t  }\n>       }\n>@@ -1111,7 +1076,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t      }\n> \t    else // Reallocate\n> \t      {\n>-\t\tconst size_type __len\n>+\t\tconst size_type __ask\n> \t\t  = _M_check_len(__n, \"vector::insert_range\");\n>\n> \t\tstruct _Guard : _Guard_alloc\n>@@ -1130,8 +1095,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t};\n>\n> \t\t// Allocate new storage:\n>-\t\tpointer __new_start(this->_M_allocate(__len));\n>-\t\t_Guard __guard(__new_start, __len, *this);\n>+\t\t_Alloc_result __r = this->_M_allocate_at_least(__ask);\n>+\t\tconst size_type __got = __r.__count;\n>+\t\tpointer __new_start(__r.__ptr);\n>+\t\t_Guard __guard(__new_start, __got, *this);\n>\n> \t\tauto& __alloc = _M_get_Tp_allocator();\n>\n>@@ -1158,13 +1125,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n> \t\t// with __guard so that it cleans up the old storage:\n> \t\tthis->_M_impl._M_start = __guard._M_storage;\n> \t\tthis->_M_impl._M_finish = __guard._M_finish;\n>-\t\tthis->_M_impl._M_end_of_storage = __new_start + __len;\n>+\t\tthis->_M_impl._M_end_of_storage = __new_start + __got;\n> \t\t__guard._M_storage = __old_start;\n> \t\t__guard._M_finish = __old_finish;\n> \t\t__guard._M_len = (__old_finish - __old_start) + __cap;\n> \t\t// _Asan::_Reinit destructor marks unused capacity.\n> \t\t// _Guard destructor destroys [old_start,old_finish).\n>-\t\t// _Guard_alloc destructor frees [old_start,old_start+len).\n>+\t\t// _Guard_alloc destructor frees [old_start,old_start+got).\n> \t      }\n> \t    return begin() + __ins_idx;\n> \t  }\n>diff --git a/libstdc++-v3/include/std/string 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\nThis macro should only defined in <memory> and <version>, not here.\n\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 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\nAnd not here either.\n\n> #define __glibcxx_want_allocator_traits_is_always_equal\n> #define __glibcxx_want_constexpr_vector\n> #define __glibcxx_want_containers_ranges\n>diff --git a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc\n>index 5399096d294..987e2472490 100644\n>--- a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc\n>+++ b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc\n>@@ -29,7 +29,7 @@ template <typename T>\n>       }\n>   };\n>\n>-int main()\n>+void base()\n> {\n>   std::allocator<X> native;\n>   auto a1 = native.allocate_at_least(100);\n>@@ -63,3 +63,109 @@ int main()\n>   VERIFY(a5.ptr == minimal.keep);\n>   minimal_traits::deallocate(minimal, a5.ptr, a5.count);\n> }\n>+\n>+void extra()\n>+{\n>+  using SatC = std::allocator_traits<std::allocator<char>>;\n>+  std::allocator<char> satc;\n>+  {\n>+    auto [p, n] = SatC::allocate_at_least(satc, 1);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatC::deallocate(satc, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatC::allocate_at_least(satc, 2);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatC::deallocate(satc, p, n);\n>+  }\n>+  {\n>+    auto [p, n] =\n>+      SatC::allocate_at_least(satc, __STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatC::deallocate(satc, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatC::allocate_at_least(\n>+\tsatc, __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatC::deallocate(satc, p, n);\n>+  }\n>+\n>+  using SatS = std::allocator_traits<std::allocator<short>>;\n>+  std::allocator<short> sats;\n>+  {\n>+    auto [p, n] = SatS::allocate_at_least(sats, 1);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(short));\n>+    SatS::deallocate(sats, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatS::allocate_at_least(sats, 2);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(short));\n>+    SatS::deallocate(sats, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatS::allocate_at_least(sats,\n>+\t(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1) / sizeof(short));\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(short));\n>+    SatS::deallocate(sats, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatS::allocate_at_least(sats,\n>+\t__STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(short));\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(short));\n>+    SatS::deallocate(sats, p, n);\n>+  }\n>+\n>+  struct A3 { char s[3]; };\n>+  using SatA3 = std::allocator_traits<std::allocator<A3>>;\n>+  std::allocator<A3> sata3;\n>+  {\n>+    auto [p, n] = SatA3::allocate_at_least(sata3, 1);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A3));\n>+    SatA3::deallocate(sata3, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatA3::allocate_at_least(sata3, 2);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A3));\n>+    SatA3::deallocate(sata3, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatA3::allocate_at_least(sata3,\n>+\t(__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1) / sizeof(A3));\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A3));\n>+    SatA3::deallocate(sata3, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatA3::allocate_at_least(sata3,\n>+\t__STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A3));\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A3));\n>+    SatA3::deallocate(sata3, p, n);\n>+  }\n>+\n>+  struct Anm1 { char s[__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1]; };\n>+  using SatAnm1 = std::allocator_traits<std::allocator<Anm1>>;\n>+  std::allocator<Anm1> satanm1;\n>+  {\n>+    auto [p, n] = SatAnm1::allocate_at_least(satanm1, 1);\n>+    VERIFY(n == 1);\n>+    SatAnm1::deallocate(satanm1, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatAnm1::allocate_at_least(satanm1,\n>+\t__STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatAnm1::deallocate(satanm1, p, n);\n>+  }\n>+  {\n>+    auto [p, n] = SatAnm1::allocate_at_least(satanm1,\n>+\t__STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1);\n>+    VERIFY(n == __STDCPP_DEFAULT_NEW_ALIGNMENT__);\n>+    SatAnm1::deallocate(satanm1, p, n);\n>+  }\n>+}\n>+\n>+int main()\n>+{\n>+  base();\n>+  extra();\n>+}\n>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/18654.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/18654.cc\n>index d542f34d08e..59012a1c170 100644\n>--- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/18654.cc\n>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/18654.cc\n>@@ -58,7 +58,12 @@ void test01()\n> #else\n>       str.shrink_to_fit(); // reserve is deprecated in C++20\n> #endif\n>-      VERIFY( str.capacity() == i );\n>+#if __glibcxx_allocate_at_least\n>+      unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1;\n>+#else\n>+      unsigned limit = 0;\n>+#endif\n>+      VERIFY( str.capacity() - i <= limit);\n>     }\n> }\n>\n>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/shrink_to_fit.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/shrink_to_fit.cc\n>index a26d524dddf..ae5df746f35 100644\n>--- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/shrink_to_fit.cc\n>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/char/shrink_to_fit.cc\n>@@ -30,7 +30,12 @@ void test01()\n>   s.push_back('b');\n>   VERIFY( s.size() < s.capacity() );\n>   s.shrink_to_fit();\n>-  VERIFY( s.size() == s.capacity() );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ - 1;\n>+#else\n>+  unsigned limit = 0;\n>+#endif\n>+  VERIFY( s.capacity() - s.size() <= limit );\n> }\n>\n> int main()\n>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/18654.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/18654.cc\n>index 49e45c764c4..bf3b8dd5581 100644\n>--- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/18654.cc\n>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/18654.cc\n>@@ -50,6 +50,7 @@ void test01()\n>       const size_type cap = str.capacity();\n>       VERIFY( cap >= 3 * i );\n>\n>+      // no shrink.\n>       str.reserve(2 * i);\n>       VERIFY( str.capacity() == cap );\n>\n>@@ -58,7 +59,12 @@ void test01()\n> #else\n>       str.shrink_to_fit(); // reserve is deprecated in C++20\n> #endif\n>-      VERIFY( str.capacity() == i );\n>+#if __glibcxx_allocate_at_least\n>+      unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(wchar_t) - 1;\n>+#else\n>+      unsigned limit = 0;\n>+#endif\n>+      VERIFY( str.capacity() - i <= limit);\n>     }\n> }\n>\n>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/2.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/2.cc\n>index bff2bdd1862..04a3763fc77 100644\n>--- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/2.cc\n>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/2.cc\n>@@ -27,14 +27,21 @@\n> void test02()\n> {\n>   std::wstring str01 = L\"twelve chars\";\n>-  // str01 becomes shared\n>-  std::wstring str02 = str01;\n>+  str01.reserve(100);\n> #if __cplusplus <= 201703L\n>   str01.reserve();\n> #else\n>   str01.shrink_to_fit(); // reserve is deprecated in C++20\n> #endif\n>-  VERIFY( str01.capacity() == 12 );\n>+  // These are not guaranteed to absolutely minimize storage.\n>+  // allocator<wchar_t>::allocate_at_least rounds up to what\n>+  // it knows ::op new delivers.\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(wchar_t) - 1;\n>+#else\n>+  unsigned limit = 0;\n>+#endif\n>+  VERIFY( str01.capacity() - str01.size() <= limit);\n> }\n>\n> int main()\n>diff --git a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/shrink_to_fit.cc b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/shrink_to_fit.cc\n>index b4d0224a9d8..fc0f659539f 100644\n>--- a/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/shrink_to_fit.cc\n>+++ b/libstdc++-v3/testsuite/21_strings/basic_string/capacity/wchar_t/shrink_to_fit.cc\n>@@ -30,7 +30,12 @@ void test01()\n>   s.push_back(L'b');\n>   VERIFY( s.size() < s.capacity() );\n>   s.shrink_to_fit();\n>-  VERIFY( s.size() == s.capacity() );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(wchar_t) - 1;\n>+#else\n>+  unsigned limit = 0;\n>+#endif\n>+  VERIFY( s.capacity() - s.size() <= limit );\n> }\n>\n> int main()\n>diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc\n>index 74c68712b47..d4aa4d89b56 100644\n>--- a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc\n>+++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit.cc\n>@@ -30,11 +30,12 @@ void test01()\n>   v.push_back(1);\n>   VERIFY( v.size() < v.capacity() );\n>   v.shrink_to_fit();\n>-#if __cpp_exceptions\n>-  VERIFY( v.size() == v.capacity() );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(int);\n> #else\n>-  VERIFY( v.size() < v.capacity() );\n>+  unsigned limit = 0;\n> #endif\n>+  VERIFY(v.capacity() - v.size() <= limit);\n> }\n>\n> int main()\n>diff --git a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit2.cc b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit2.cc\n>index c8faa9ded80..9489e043845 100644\n>--- a/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit2.cc\n>+++ b/libstdc++-v3/testsuite/23_containers/vector/capacity/shrink_to_fit2.cc\n>@@ -32,7 +32,12 @@ void test01()\n>   v.reserve(100);\n>   VERIFY( v.size() < v.capacity() );\n>   v.shrink_to_fit();\n>-  VERIFY( v.size() == v.capacity() );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(int);\n>+#else\n>+  unsigned limit = 0;\n>+#endif\n>+  VERIFY( v.capacity() - v.size() <= limit);\n>   VERIFY( v.get_allocator().get_personality() == alloc.get_personality() );\n> }\n>\n>@@ -45,7 +50,12 @@ void test02()\n>   v.reserve(100);\n>   VERIFY( v.size() < v.capacity() );\n>   v.shrink_to_fit();\n>-  VERIFY( v.size() == v.capacity() );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned limit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(int);\n>+#else\n>+  unsigned limit = 0;\n>+#endif\n>+  VERIFY( v.capacity() - v.size() <= limit);\n>   VERIFY( v.get_allocator().get_personality() == alloc.get_personality() );\n> }\n>\n>diff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc\n>index 00a0c7b06ea..629f35f05ba 100644\n>--- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc\n>+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/emplace/self_emplace.cc\n>@@ -99,37 +99,37 @@ struct A\n> void\n> test03()\n> {\n>-  std::vector<A> va =\n>-    {\n>-      { A(1) },\n>-      { A(2) },\n>-      { A(3) }\n>-    };\n>-\n>-  // Make sure emplace will imply reallocation.\n>-  VERIFY( va.capacity() == 3 );\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned fit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A);\n>+#else\n>+  unsigned fit = 4;\n>+#endif\n>+  std::vector<A> va; va.reserve(fit);\n>+  for (int i = 1; va.size() < va.capacity(); ++i)\n>+      va.push_back(A(i));\n>\n>   va.emplace(va.begin(), va.begin());\n>\n>-  VERIFY( va.size() == 4 );\n>+  VERIFY( va.size() == fit + 1 );\n>   VERIFY( va[0]._i == 1 );\n> }\n>\n> void\n> test04()\n> {\n>-  std::vector<A> va =\n>-    {\n>-      { A(1) },\n>-      { A(2) },\n>-      { A(3) }\n>-    };\n>+#ifdef __glibcxx_allocate_at_least\n>+  unsigned fit = __STDCPP_DEFAULT_NEW_ALIGNMENT__ / sizeof(A);\n>+#else\n>+  unsigned fit = 4;\n>+#endif\n>+  std::vector<A> va; va.reserve(fit);\n>+  for (int i = 1; va.size() < va.capacity() - 1; ++i)\n>+      va.push_back(A(i));\n>\n>   // Make sure emplace won't reallocate.\n>-  va.reserve(4);\n>   va.emplace(va.begin(), va.begin());\n>\n>-  VERIFY( va.size() == 4 );\n>+  VERIFY( va.size() == fit );\n>   VERIFY( va[0]._i == 1 );\n> }\n>\n>diff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h\n>index 892a385e307..a12099354ca 100644\n>--- a/libstdc++-v3/testsuite/util/testsuite_allocator.h\n>+++ b/libstdc++-v3/testsuite/util/testsuite_allocator.h\n>@@ -168,6 +168,16 @@ namespace __gnu_test\n> \t  : Alloc(alloc)\n> \t{ }\n>\n>+#ifdef __glibcxx_allocate_at_least // C++23\n>+      std::allocation_result<pointer, size_type>\n>+      allocate_at_least(size_type n)\n>+      {\n>+\tauto [p, c] = AllocTraits::allocate_at_least(*this, n);\n>+\tcounter_type::allocate(c * sizeof(T));\n>+\treturn { p, c };\n>+      }\n>+#endif\n>+\n>       pointer\n>       allocate(size_type n, const void* = 0)\n>       {\n>@@ -373,6 +383,31 @@ namespace __gnu_test\n> \treturn p;\n>       }\n>\n>+#ifdef __glibcxx_allocate_at_least\n>+      constexpr auto\n>+      allocate_at_least(size_type n)\n>+      -> std::allocation_result<Tp*, size_t>\n>+      {\n>+\tauto r = AllocTraits::allocate_at_least(*this, n);\n>+\n>+\tif (std::__is_constant_evaluated())\n\nif consteval\n\n>+\t  return r;\n>+\n>+\ttry\n>+\t  {\n>+\t    get_map().insert(map_type::value_type(\n>+\t\t  reinterpret_cast<void*>(r.ptr), personality));\n\nHuh, why do we use reinterpret_cast here when an implicit conversion\nor static_cast<void*> would work fine. But this is consistent with the\nexisting code, so that's a question for another day.\n\n>+\t  }\n>+\tcatch(...)\n>+\t  {\n>+\t    AllocTraits::deallocate(*this, r.ptr, r.count);\n>+\t    __throw_exception_again;\n>+\t  }\n>+\n>+\treturn r;\n>+      }\n>+#endif\n>+\n>       _GLIBCXX14_CONSTEXPR\n>       void\n>       deallocate(pointer p, size_type n)\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 (1024-bit key;\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=OeYh/qoz;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=gcc.gnu.org\n (client-ip=38.145.34.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 (1024-bit key,\n unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256\n header.s=mimecast20190719 header.b=OeYh/qoz","sourceware.org; dmarc=pass (p=quarantine dis=none)\n header.from=redhat.com","sourceware.org; spf=pass smtp.mailfrom=redhat.com","server2.sourceware.org;\n arc=none smtp.remote-ip=170.10.133.124"],"Received":["from vm01.sourceware.org (vm01.sourceware.org [38.145.34.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 4fzncQ5D0pz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Tue, 21 Apr 2026 00:17:09 +1000 (AEST)","from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 2CB9A4A98F05\n\tfor <incoming@patchwork.ozlabs.org>; Mon, 20 Apr 2026 14:17:01 +0000 (GMT)","from us-smtp-delivery-124.mimecast.com\n (us-smtp-delivery-124.mimecast.com [170.10.133.124])\n by sourceware.org (Postfix) with ESMTP id 674994D8D1E2\n for <gcc-patches@gcc.gnu.org>; Mon, 20 Apr 2026 14:16:15 +0000 (GMT)","from mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-35-165-154-97.us-west-2.compute.amazonaws.com [35.165.154.97]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-216-v8KyyHhZNSG9Q7B4gQcyVA-1; Mon,\n 20 Apr 2026 10:16:12 -0400","from mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.93])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest\n SHA256)\n (No client certificate requested)\n by mx-prod-mc-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 515B41800451; Mon, 20 Apr 2026 14:16:11 +0000 (UTC)","from localhost (unknown [10.44.50.46])\n by mx-prod-int-06.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id 016D31800349; Mon, 20 Apr 2026 14:16:09 +0000 (UTC)"],"DKIM-Filter":["OpenDKIM Filter v2.11.0 sourceware.org 2CB9A4A98F05","OpenDKIM Filter v2.11.0 sourceware.org 674994D8D1E2"],"DMARC-Filter":"OpenDMARC Filter v1.4.2 sourceware.org 674994D8D1E2","ARC-Filter":"OpenARC Filter v1.0.0 sourceware.org 674994D8D1E2","ARC-Seal":"i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776694575; cv=none;\n b=uBBnJM4XACicub4bUA+++G/E+c3QI/ZBOjNml9a0kWkvRnU6PvwC4igzUbJgw3MBIZyptbkSeiDQyK2aQTxxOG7NGlvkv5XBsv2nYTNnhXkmIEz88zdHYmHsTLniRhsHfuJq58ovB1tlPOil+065aJNDrlNWDpyihOl+Jwszijs=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776694575; c=relaxed/simple;\n bh=tNXJBT0XcKtYikYyriQDtKTcbwOLz0PxqNIk1xtKHKU=;\n h=DKIM-Signature:Date:From:To:Subject:Message-ID:MIME-Version;\n b=dO16F9xhGHG8iUG2ShOMydvcxOygsZjau860qpE8kWBh/kdNB75dU+ot0VkFF+YAIWFYhIsuD0GOG/rsL5Iay8HHyw114/6bLz5RVl5cP2JlXVFHinrfrYcD0u0AcZt8m2X4UnLYD5pahMcy6c9W8W3zK9IS3IM1fcBV6FVvGbw=","ARC-Authentication-Results":"i=1; server2.sourceware.org","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com;\n s=mimecast20190719; t=1776694575;\n h=from:from:reply-to:subject:subject:date:date:message-id:message-id:\n to:to:cc:cc:mime-version:mime-version:content-type:content-type:\n in-reply-to:in-reply-to:references:references;\n bh=95vbh1Rk5Ch6dgYuElTbD7yRBcB6+4lZAyHa1tDey8A=;\n b=OeYh/qozFtROzYprnm213o953aup2ZFsiJGlpwZHm/7sdaLIpbd5jSAo2H3H1X4aDL04B7\n iR2gQatWyTPz+dts4mcagwuPjBtF1iRk/PSnd1vqJ21Duq42HkhsScvwRVUYJVmepwYg2J\n 97RGEzYwwafjbIaJBlmN0I1w2lxW0Is=","X-MC-Unique":"v8KyyHhZNSG9Q7B4gQcyVA-1","X-Mimecast-MFC-AGG-ID":"v8KyyHhZNSG9Q7B4gQcyVA_1776694571","Date":"Mon, 20 Apr 2026 15:16:08 +0100","From":"Jonathan Wakely <jwakely@redhat.com>","To":"Nathan Myers <ncm@cantrip.org>","Cc":"gcc-patches@gcc.gnu.org, libstdc++@gcc.gnu.org","Subject":"Re: [PATCH] libstdc++: Use allocate_at_least in vector, string\n (P0401) [PR118030]","Message-ID":"<aeY1KJ2OEFCrmVKe@zen.kayari.org>","References":"<20260418220741.1548332-1-ncm@cantrip.org>","MIME-Version":"1.0","In-Reply-To":"<20260418220741.1548332-1-ncm@cantrip.org>","X-Clacks-Overhead":"GNU Terry Pratchett","X-Scanned-By":"MIMEDefang 3.4.1 on 10.30.177.93","X-Mimecast-Spam-Score":"0","X-Mimecast-MFC-PROC-ID":"z7oyqBlGfia8iwKrCcitrUKCo5bbKKp57gLfexx-VJc_1776694571","X-Mimecast-Originator":"redhat.com","Content-Type":"text/plain; charset=utf-8; format=flowed","Content-Disposition":"inline","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"}}]