Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2224811/?format=api
{ "id": 2224811, "url": "http://patchwork.ozlabs.org/api/patches/2224811/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/20260418220741.1548332-1-ncm@cantrip.org/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/projects/17/?format=api", "name": "GNU Compiler Collection", "link_name": "gcc", "list_id": "gcc-patches.gcc.gnu.org", "list_email": "gcc-patches@gcc.gnu.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260418220741.1548332-1-ncm@cantrip.org>", "list_archive_url": null, "date": "2026-04-18T21:56:44", "name": "libstdc++: Use allocate_at_least in vector, string (P0401) [PR118030]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "44e35a49e81dbb13b2fa95931cd6247c4253e3e6", "submitter": { "id": 90892, "url": "http://patchwork.ozlabs.org/api/people/90892/?format=api", "name": "Nathan Myers", "email": "ncm@cantrip.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/20260418220741.1548332-1-ncm@cantrip.org/mbox/", "series": [ { "id": 500470, "url": "http://patchwork.ozlabs.org/api/series/500470/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=500470", "date": "2026-04-18T21:56:44", "name": "libstdc++: Use allocate_at_least in vector, string (P0401) [PR118030]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500470/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2224811/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2224811/checks/", "tags": {}, "related": [], "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 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 dmarc=none (p=none dis=none) header.from=cantrip.org", "sourceware.org; spf=fail smtp.mailfrom=cantrip.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=205.139.111.44" ], "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 4fym982ldRz1yDF\n\tfor <incoming@patchwork.ozlabs.org>; Sun, 19 Apr 2026 08:08:27 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 270A64B920AF\n\tfor <incoming@patchwork.ozlabs.org>; Sat, 18 Apr 2026 22:08:25 +0000 (GMT)", "from us-smtp-delivery-44.mimecast.com\n (us-smtp-delivery-44.mimecast.com [205.139.111.44])\n by sourceware.org (Postfix) with ESMTP id E5EA54BA2E37\n for <gcc-patches@gcc.gnu.org>; Sat, 18 Apr 2026 22:07:48 +0000 (GMT)", "from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com\n (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by\n relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3,\n cipher=TLS_AES_256_GCM_SHA384) id us-mta-36-Gkzqy2p9MheMTduAEMj_0g-1; Sat,\n 18 Apr 2026 18:07:45 -0400", "from mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com\n (mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.111])\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-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS\n id 330A4195608F; Sat, 18 Apr 2026 22:07:44 +0000 (UTC)", "from redhat.redhat.com (unknown [10.22.88.26])\n by mx-prod-int-08.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP\n id E4D661800446; Sat, 18 Apr 2026 22:07:42 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 270A64B920AF", "OpenDKIM Filter v2.11.0 sourceware.org E5EA54BA2E37" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org E5EA54BA2E37", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org E5EA54BA2E37", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776550069; cv=none;\n b=uYWcSDc0f3cFRVsNLiXAmG5atYDwurfyG3NwkXp/kO3yxvQk+yteasNhbfQ0k5Lc8qeQnsQyNB/RiQphalaEHxgU0RktVx8MbVzGa8lJ+Gu211saE0JGUrV+i5ALLlUk3T1Oioa8Xy5Atq7vQTa78mnNVwHpKXonqwUu+xw9o9o=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776550069; c=relaxed/simple;\n bh=nGuupvGgjfUyFVJT1PS2fuNoca/bQUMIDk4JBlNKz3k=;\n h=From:To:Subject:Date:Message-ID:MIME-Version;\n b=oQM5luIQ/rfQQATtkZYnBRJ2bLAfnTqd8Vp1D52XBeKf9mYODkEr7IV0e/QIdj/KjzubF/JunfbrIrwcdPT7w3XuRQE7Kk7Sv/dbY3M69MKzDn+vMZ49UbukN9fqdmnkBF78AeTHbsnuLiAVBNgaLnqhtuya4vA9GTdvJTAuFVw=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "X-MC-Unique": "Gkzqy2p9MheMTduAEMj_0g-1", "X-Mimecast-MFC-AGG-ID": "Gkzqy2p9MheMTduAEMj_0g_1776550064", "From": "Nathan Myers <ncm@cantrip.org>", "To": "gcc-patches@gcc.gnu.org,\n\tlibstdc++@gcc.gnu.org", "Subject": "[PATCH] libstdc++: Use allocate_at_least in vector,\n string (P0401) [PR118030]", "Date": "Sat, 18 Apr 2026 17:56:44 -0400", "Message-ID": "<20260418220741.1548332-1-ncm@cantrip.org>", "MIME-Version": "1.0", "X-Scanned-By": "MIMEDefang 3.4.1 on 10.30.177.111", "X-Mimecast-Spam-Score": "0", "X-Mimecast-MFC-PROC-ID": "7yaUpUP7IwR8VGqDmP0XYy8s2V_i9GWHEKAfB22D_X4_1776550064", "X-Mimecast-Originator": "cantrip.org", "Content-Transfer-Encoding": "quoted-printable", "content-type": "text/plain; charset=WINDOWS-1252; x-default=true", "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" }, "content": "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\nChanges 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\nImplement as much of allocator<>::allocate_at_least as possible\nrelying solely on known alignment behavior of standard operator\nnew. Provide apparatus for users' allocators to do the same.\n\nUse allocator_at_least in string and vector to maximize usage of\nactually allocated storage, as revealed by the allocator in use.\nFor user-supplied allocators this may make a big difference.\n\nFixes omitted _GLIBCXX_ASAN_ANNOTATE_REINIT in vector<>::operator=.\n\nNothing is changed in include/ext/malloc_allocator or others.\nThey can be updated at leisure, piecemeal.\n\nlibstdc++-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(-)", "diff": "diff --git a/libstdc++-v3/config/abi/pre/gnu.ver b/libstdc++-v3/config/abi/pre/gnu.ver\nindex 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+\n+\n #if defined (_WIN32) && !defined (__CYGWIN__)\n _ZSt19__get_once_callablev;\n _ZSt15__get_once_callv;\ndiff --git a/libstdc++-v3/include/bits/alloc_traits.h b/libstdc++-v3/include/bits/alloc_traits.h\nindex 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+\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+ 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+\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+ -> 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+\t using _U8 = const unsigned char;\n+\t static_assert(__objsize <= ~_U8());\n+\t // Use 8-bit division:\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\ndiff --git a/libstdc++-v3/include/bits/allocator.h b/libstdc++-v3/include/bits/allocator.h\nindex 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+\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+ }\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\ndiff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h\nindex 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+\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 }\ndiff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc\nindex 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+ __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 \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();\ndiff --git a/libstdc++-v3/include/bits/memory_resource.h b/libstdc++-v3/include/bits/memory_resource.h\nindex 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+\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.\ndiff --git a/libstdc++-v3/include/bits/memoryfwd.h b/libstdc++-v3/include/bits/memoryfwd.h\nindex 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 \ndiff --git a/libstdc++-v3/include/bits/new_allocator.h b/libstdc++-v3/include/bits/new_allocator.h\nindex 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+\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\ndiff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h\nindex 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+\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+\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+\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 \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+ {\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+\t size_type __n, _ForwardIterator __first, _ForwardIterator __last)\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,\ndiff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc\nindex 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 }\ndiff --git a/libstdc++-v3/include/std/string b/libstdc++-v3/include/std/string\nindex 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\ndiff --git a/libstdc++-v3/include/std/vector b/libstdc++-v3/include/std/vector\nindex 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\ndiff --git a/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc b/libstdc++-v3/testsuite/20_util/allocator/allocate_at_least.cc\nindex 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+}\ndiff --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\nindex 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 \ndiff --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\nindex 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()\ndiff --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\nindex 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 \ndiff --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\nindex 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()\ndiff --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\nindex 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()\ndiff --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\nindex 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()\ndiff --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\nindex 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 \ndiff --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\nindex 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 \ndiff --git a/libstdc++-v3/testsuite/util/testsuite_allocator.h b/libstdc++-v3/testsuite/util/testsuite_allocator.h\nindex 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+\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+\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", "prefixes": [] }