Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.1/patches/2226280/?format=api
{ "id": 2226280, "url": "http://patchwork.ozlabs.org/api/1.1/patches/2226280/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.4@forge-stage.sourceware.org/", "project": { "id": 17, "url": "http://patchwork.ozlabs.org/api/1.1/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 }, "msgid": "<bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.4@forge-stage.sourceware.org>", "date": "2026-04-22T10:36:21", "name": "[v1,4/4] libstdc++: Add fancy pointer support to std::forward_list [PR57272]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "8f73686c6089bb8183f4cdefbad2b1e02376ed8c", "submitter": { "id": 93210, "url": "http://patchwork.ozlabs.org/api/1.1/people/93210/?format=api", "name": "Jonathan Wakely via Sourceware Forge", "email": "forge-bot+redi@forge-stage.sourceware.org" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.4@forge-stage.sourceware.org/mbox/", "series": [ { "id": 500985, "url": "http://patchwork.ozlabs.org/api/1.1/series/500985/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=500985", "date": "2026-04-22T10:36:19", "name": "libstdc++: Add fancy pointer support to std::list and std::forward_list [PR57272]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500985/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2226280/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2226280/checks/", "tags": {}, "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=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; dmarc=none (p=none dis=none)\n header.from=forge-stage.sourceware.org", "sourceware.org;\n spf=pass smtp.mailfrom=forge-stage.sourceware.org", "server2.sourceware.org;\n arc=none smtp.remote-ip=38.145.34.39" ], "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 4g0xGr5XFtz1yD5\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 21:05:56 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id CCAD1409F62B\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 11:05:54 +0000 (GMT)", "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 43CB44BC894D\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:37:13 +0000 (GMT)", "from forge-stage.sourceware.org (localhost [IPv6:::1])\n (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256)\n (No client certificate requested)\n by forge-stage.sourceware.org (Postfix) with ESMTPS id 17DB742B59\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 10:37:13 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org CCAD1409F62B", "OpenDKIM Filter v2.11.0 sourceware.org 43CB44BC894D" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 43CB44BC894D", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 43CB44BC894D", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776854233; cv=none;\n b=hXn6xpeViRpZFkgGYJpq8xwRs0Cit8mxp++ouXFmibDoQnf2BijqwkV7Gf40WjByyzGc5PdUYPvu6ndb1rloMg+loAoxG4AtTv+bigpYimX5RP5zLx//JWHlMcgxYqgzeKMRnUNmGMP3AyRIfocQCIrr5qmU3zhUH2eyHTP49s8=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776854233; c=relaxed/simple;\n bh=DYxLKs8fXYMIruY3XoWU591MDounMHrnt6znheloAN8=;\n h=From:Date:Subject:To:Message-ID;\n b=O8Lq0H5kWgkoCEAzzKBk94S6XON2eyq8saNL6jvhUz43lGPs0ONUEBnolFTtmrFWmX6VQkvyf22U7cHIFf5u3GbROOdsdeVB1Efe4gDMNw5Oi2mUJue7EnVCHg7WqLswgbv98e+ohzDSMOeAou3sUhkS0VdW7DduCjasB3nEuFg=", "ARC-Authentication-Results": "i=1; server2.sourceware.org", "From": "Jonathan Wakely via Sourceware Forge\n <forge-bot+redi@forge-stage.sourceware.org>", "Date": "Wed, 22 Apr 2026 10:36:21 +0000", "Subject": "[PATCH v1 4/4] libstdc++: Add fancy pointer support to\n std::forward_list [PR57272]", "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>", "Message-ID": "\n <bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.4@forge-stage.sourceware.org>", "X-Mailer": "batrachomyomachia", "X-Pull-Request-Organization": "gcc", "X-Pull-Request-Repository": "gcc-TEST", "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/25", "References": "\n <bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.0@forge-stage.sourceware.org>", "In-Reply-To": "\n <bmm.hhubjjpeho.gcc.gcc-TEST.redi.25.1.0@forge-stage.sourceware.org>", "X-Patch-URL": "\n https://forge.sourceware.org/redi/gcc/commit/b26b7f43502a78f7de364a7015566101929a59d4", "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>", "Reply-To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>, redi@gcc.gnu.org", "Errors-To": "gcc-patches-bounces~incoming=patchwork.ozlabs.org@gcc.gnu.org" }, "content": "From: Jonathan Wakely <jwakely@redhat.com>\n\nThis takes a very similar approach to the changes for std::list.\n\nlibstdc++-v3/ChangeLog:\n\n\tPR libstdc++/57272\n\t* include/bits/forward_list.h (_GLIBCXX_USE_ALLOC_PTR_FOR_LIST):\n\tDefine.\n\t(_Fwd_list_node_base::_M_base_ptr): New member functions.\n\t(_Fwd_list_node::_M_node_ptr): New member function.\n\t(_Fwd_list_iterator, _Fwd_list_const_iterator): Make internal\n\tmember functions and data member private. Declare forward_list\n\tand _Fwd_list_base as friends.\n\t(__fwdlist::_Node_base, __fwdlist::_Node, __fwdlist::_Iterator):\n\tNew class templates.\n\t(__fwdlist::_Node_traits): New class template.\n\t(_Fwd_list_base): Use _Node_traits to get types. Use _Base_ptr\n\tinstad of _Fwd_list_node_base*. Use _M_base_ptr() instead of\n\ttaking address of head node.\n\t(forward_list): Likewise.\n\t(_Fwd_list_base::_M_get_node): Do not define for versioned\n\tnamespace.\n\t(_Fwd_list_base::_M_put_node): Only convert pointer if needed.\n\t(_Fwd_list_base::_M_create_node): Use __allocate_guarded_obj.\n\t(_Fwd_list_base::_M_destroy_node): New member function.\n\t* include/bits/forward_list.tcc (_Fwd_list_base::_M_insert_after)\n\t(forward_list::_M_splice_after, forward_list::insert_after): Use\n\tconst_iterator::_M_const_cast() instead of casting pointers.\n\t(_Fwd_list_base::_M_erase_after): Use _M_destroy_node.\n\t(forward_list::remove, forward_list::remove_if): Only do\n\tdowncasts when accessing the value.\n\t(forward_list::sort): Likewise.\n\t* testsuite/23_containers/forward_list/capacity/1.cc: Check\n\tmax_size for new node type.\n\t* testsuite/23_containers/forward_list/capacity/node_sizes.cc:\n\tNew test.\n\t* testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr.cc:\n\tNew test.\n\t* testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr_ignored.cc:\n\tNew test.\n---\n libstdc++-v3/include/bits/forward_list.h | 428 +++++++++++++++---\n libstdc++-v3/include/bits/forward_list.tcc | 124 ++---\n .../23_containers/forward_list/capacity/1.cc | 11 +-\n .../forward_list/capacity/node_sizes.cc | 24 +\n .../forward_list/requirements/completeness.cc | 19 +\n .../explicit_instantiation/alloc_ptr.cc | 86 ++++\n .../alloc_ptr_ignored.cc | 4 +\n 7 files changed, 579 insertions(+), 117 deletions(-)\n create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/capacity/node_sizes.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/requirements/completeness.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr_ignored.cc", "diff": "diff --git a/libstdc++-v3/include/bits/forward_list.h b/libstdc++-v3/include/bits/forward_list.h\nindex c9238cef96fa..e4d24c4b9cac 100644\n--- a/libstdc++-v3/include/bits/forward_list.h\n+++ b/libstdc++-v3/include/bits/forward_list.h\n@@ -40,6 +40,9 @@\n #include <bits/stl_algobase.h>\n #include <bits/stl_function.h>\n #include <bits/allocator.h>\n+#include <bits/allocated_ptr.h>\n+#include <bits/ptr_traits.h>\n+#include <debug/assertions.h>\n #include <ext/alloc_traits.h>\n #include <ext/aligned_buffer.h>\n #if __glibcxx_ranges_to_container // C++ >= 23\n@@ -47,6 +50,10 @@\n # include <bits/ranges_util.h> // ranges::subrange\n #endif\n \n+#if ! defined _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST\n+# define _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST 1\n+#endif\n+\n namespace std _GLIBCXX_VISIBILITY(default)\n {\n _GLIBCXX_BEGIN_NAMESPACE_VERSION\n@@ -54,11 +61,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \n /**\n * @brief A helper basic node class for %forward_list.\n+ *\n * This is just a linked list with nothing inside it.\n * There are purely list shuffling utility methods here.\n */\n struct _Fwd_list_node_base\n {\n+ using _Base_ptr = _Fwd_list_node_base*;\n+\n _Fwd_list_node_base() = default;\n _Fwd_list_node_base(_Fwd_list_node_base&& __x) noexcept\n : _M_next(__x._M_next)\n@@ -107,6 +117,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t _M_next->_M_next = __keep;\n \t}\n }\n+\n+ _Fwd_list_node_base* _M_base_ptr() { return this; }\n+ const _Fwd_list_node_base* _M_base_ptr() const { return this; }\n };\n \n /**\n@@ -119,6 +132,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n struct _Fwd_list_node\n : public _Fwd_list_node_base\n {\n+ using _Node_ptr = _Fwd_list_node*;\n+\n _Fwd_list_node() = default;\n \n __gnu_cxx::__aligned_buffer<_Tp> _M_storage;\n@@ -130,8 +145,14 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n const _Tp*\n _M_valptr() const noexcept\n { return _M_storage._M_ptr(); }\n+\n+ _Node_ptr\n+ _M_node_ptr()\n+ { return this; }\n };\n \n+ template<typename _Tp> struct _Fwd_list_const_iterator;\n+\n /**\n * @brief A forward_list::iterator.\n *\n@@ -199,6 +220,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n { return __x._M_node != __y._M_node; }\n #endif\n \n+ private:\n+ template<typename, typename>\n+\tfriend class forward_list;\n+ template<typename, typename>\n+\tfriend struct _Fwd_list_base;\n+ friend struct _Fwd_list_const_iterator<_Tp>;\n+\n _Self\n _M_next() const noexcept\n {\n@@ -282,6 +310,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n { return __x._M_node != __y._M_node; }\n #endif\n \n+ private:\n+ template<typename, typename>\n+\tfriend class forward_list;\n+ template<typename, typename>\n+\tfriend struct _Fwd_list_base;\n+\n _Self\n _M_next() const noexcept\n {\n@@ -291,23 +325,295 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t return _Fwd_list_const_iterator(nullptr);\n }\n \n+ _Fwd_list_iterator<_Tp>\n+ _M_const_cast() const noexcept\n+ {\n+\treturn _Fwd_list_iterator<_Tp>(\n+\t\t const_cast<_Fwd_list_node_base*>(_M_node));\n+ }\n+\n const _Fwd_list_node_base* _M_node;\n };\n \n+ template<typename _Tp, typename _Allocator> class forward_list;\n+ template<typename _Tp, typename _Allocator> struct _Fwd_list_base;\n+\n+namespace __fwdlist\n+{\n+#if _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST\n+ /// The node-base type for allocators that use fancy pointers.\n+ template<typename _VoidPtr>\n+ struct _Node_base\n+ {\n+ using _Base_ptr = __ptr_rebind<_VoidPtr, _Node_base>;\n+\n+ _Node_base() = default;\n+\n+ _Node_base(_Node_base&& __x) noexcept\n+ : _M_next(__x._M_next)\n+ { __x._M_next = nullptr; }\n+\n+ _Node_base(const _Node_base&) = delete;\n+ _Node_base& operator=(const _Node_base&) = delete;\n+\n+ _Node_base&\n+ operator=(_Node_base&& __x) noexcept\n+ {\n+\t_M_next = __x._M_next;\n+\t__x._M_next = nullptr;\n+\treturn *this;\n+ }\n+\n+ _Base_ptr _M_next = nullptr;\n+\n+ // Splice (begin,end) before _M_next.\n+ _Base_ptr\n+ _M_transfer_after(_Base_ptr __begin, _Base_ptr __end) noexcept\n+ {\n+\t_Base_ptr __keep = __begin->_M_next;\n+\tif (__end)\n+\t {\n+\t __begin->_M_next = __end->_M_next;\n+\t __end->_M_next = _M_next;\n+\t }\n+\telse\n+\t __begin->_M_next = nullptr;\n+\t_M_next = __keep;\n+\treturn __end;\n+ }\n+\n+ void\n+ _M_reverse_after() noexcept\n+ {\n+\t_Base_ptr __tail = _M_next;\n+\tif (!__tail)\n+\t return;\n+\twhile (_Base_ptr __temp = __tail->_M_next)\n+\t {\n+\t _Base_ptr __keep = _M_next;\n+\t _M_next = __temp;\n+\t __tail->_M_next = __temp->_M_next;\n+\t _M_next->_M_next = __keep;\n+\t }\n+ }\n+\n+ // This is not const-correct, but it's only used in a const access path\n+ // by std::forward_list::empty(), where it doesn't escape, and by\n+ // std::forward_list::before_begin() const, where the pointer is used\n+ // to initialize a const_iterator and so constness is restored.\n+ _Base_ptr\n+ _M_base_ptr() const\n+ {\n+\treturn pointer_traits<_Base_ptr>::\n+\t\t pointer_to(const_cast<_Node_base&>(*this));\n+ }\n+ };\n+\n+ /**\n+ * @brief A helper node class for %forward_list.\n+ */\n+ template<typename _ValPtr>\n+ struct _Node\n+ : public _Node_base<__ptr_rebind<_ValPtr, void>>\n+ {\n+ using value_type = typename pointer_traits<_ValPtr>::element_type;\n+ using _Node_ptr = __ptr_rebind<_ValPtr, _Node>;\n+\n+ _Node() { }\n+ ~_Node() { }\n+ _Node(_Node&&) = delete;\n+\n+ union {\n+#if ! _GLIBCXX_INLINE_VERSION\n+\t// For ABI compatibility we need to overalign this member.\n+\talignas(__alignof__(value_type)) // XXX GLIBCXX_ABI Deprecated\n+#endif\n+\tvalue_type _M_data;\n+ };\n+\n+ value_type*\n+ _M_valptr() noexcept\n+ { return std::__addressof(_M_data); }\n+\n+ const value_type*\n+ _M_valptr() const noexcept\n+ { return std::__addressof(_M_data); }\n+\n+ _Node_ptr\n+ _M_node_ptr()\n+ { return pointer_traits<_Node_ptr>::pointer_to(*this); }\n+ };\n+\n+ /// A forward_list iterator when the allocator uses fancy pointers.\n+ template<bool _Const, typename _Ptr>\n+ class _Iterator\n+ {\n+ using _Node = __fwdlist::_Node<_Ptr>;\n+ using _Base_ptr\n+\t= typename __fwdlist::_Node_base<__ptr_rebind<_Ptr, void>>::_Base_ptr;\n+\n+ template<typename _Tp>\n+\tusing __maybe_const = __conditional_t<_Const, const _Tp, _Tp>;\n+\n+ public:\n+ using value_type = typename pointer_traits<_Ptr>::element_type;\n+ using difference_type = ptrdiff_t;\n+ using iterator_category = forward_iterator_tag;\n+ using pointer = __maybe_const<value_type>*;\n+ using reference = __maybe_const<value_type>&;\n+\n+ constexpr _Iterator() noexcept : _M_node() { }\n+\n+ _Iterator(const _Iterator&) = default;\n+ _Iterator& operator=(const _Iterator&) = default;\n+\n+#ifdef __glibcxx_concepts\n+ constexpr\n+ _Iterator(const _Iterator<false, _Ptr>& __i) requires _Const\n+#else\n+ template<bool _OtherConst,\n+\t typename = __enable_if_t<_Const && !_OtherConst>>\n+\tconstexpr\n+\t_Iterator(const _Iterator<_OtherConst, _Ptr>& __i)\n+#endif\n+\t: _M_node(__i._M_node) { }\n+\n+ constexpr explicit\n+ _Iterator(_Base_ptr __x) noexcept\n+ : _M_node(__x) { }\n+\n+ [[__nodiscard__]]\n+ constexpr reference\n+ operator*() const noexcept\n+ { return static_cast<_Node&>(*this->_M_node)._M_data; }\n+\n+ [[__nodiscard__]]\n+ constexpr pointer\n+ operator->() const noexcept\n+ { return static_cast<_Node&>(*this->_M_node)._M_valptr(); }\n+\n+ _GLIBCXX14_CONSTEXPR _Iterator&\n+ operator++() noexcept\n+ {\n+\t_M_node = _M_node->_M_next;\n+\treturn *this;\n+ }\n+\n+ _GLIBCXX14_CONSTEXPR _Iterator\n+ operator++(int) noexcept\n+ {\n+\t_Iterator __tmp(*this);\n+\t_M_node = _M_node->_M_next;\n+\treturn __tmp;\n+ }\n+\n+ /**\n+ * @brief Forward list iterator equality comparison.\n+ */\n+ [[__nodiscard__]]\n+ friend constexpr bool\n+ operator==(const _Iterator& __x, const _Iterator& __y) noexcept\n+ { return __x._M_node == __y._M_node; }\n+\n+#if __cpp_impl_three_way_comparison < 201907L\n+ /**\n+ * @brief Forward list iterator inequality comparison.\n+ */\n+ [[__nodiscard__]]\n+ friend constexpr bool\n+ operator!=(const _Iterator& __x, const _Iterator& __y) noexcept\n+ { return __x._M_node != __y._M_node; }\n+#endif\n+\n+ private:\n+ template<typename _Tp, typename _Allocator>\n+\tfriend class _GLIBCXX_STD_C::forward_list;\n+ template<typename _Tp, typename _Allocator>\n+\tfriend struct _GLIBCXX_STD_C::_Fwd_list_base;\n+\n+ constexpr _Iterator<false, _Ptr>\n+ _M_const_cast() const noexcept\n+ { return _Iterator<false, _Ptr>(_M_node); }\n+\n+ friend _Iterator<!_Const, _Ptr>;\n+\n+ constexpr _Iterator\n+ _M_next() const noexcept\n+ { return _Iterator(_M_node ? _M_node->_M_next : nullptr); }\n+\n+ _Base_ptr _M_node;\n+ };\n+#endif // USE_ALLOC_PTR_FOR_FWD_LIST\n+\n+ // Determine the node and iterator types used by std::forward_list.\n+ template<typename _Tp, typename _Ptr>\n+ struct _Node_traits;\n+\n+#if _GLIBCXX_USE_ALLOC_PTR_FOR_LIST <= 9000\n+ // Specialization for the simple case where the allocator's pointer type\n+ // is the same type as value_type*.\n+ // For ABI compatibility we can't change the types used for this case.\n+ template<typename _Tp>\n+ struct _Node_traits<_Tp, _Tp*>\n+ {\n+ using _Node_base\t = _Fwd_list_node_base;\n+ using _Node\t = _Fwd_list_node<_Tp>;\n+ using _Iterator\t = _Fwd_list_iterator<_Tp>;\n+ using _Const_iterator = _Fwd_list_const_iterator<_Tp>;\n+ };\n+#endif\n+\n+#if ! _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST\n+ // Always use the T* specialization.\n+ template<typename _Tp, typename _Ptr>\n+ struct _Node_traits\n+ : _Node_traits<_Tp, _Tp*>\n+ { };\n+#else\n+ // Primary template used when the allocator uses fancy pointers.\n+ template<typename _Tp, typename _Ptr>\n+ struct _Node_traits\n+ {\n+ private:\n+ using _VoidPtr = __ptr_rebind<_Ptr, void>;\n+ using _ValPtr = __ptr_rebind<_Ptr, _Tp>;\n+\n+ public:\n+ using _Node_base = __fwdlist::_Node_base<_VoidPtr>;\n+ using _Node = __fwdlist::_Node<_ValPtr>;\n+ using _Iterator = __fwdlist::_Iterator<false, _ValPtr>;\n+ using _Const_iterator = __fwdlist::_Iterator<true, _ValPtr>;\n+ };\n+#endif // USE_ALLOC_PTR_FOR_FWD_LIST\n+} // namespace __fwdlist\n+\n /**\n * @brief Base class for %forward_list.\n */\n template<typename _Tp, typename _Alloc>\n struct _Fwd_list_base\n {\n+#if __cplusplus > 201703L || defined __STRICT_ANSI__\n+ // The static_assert in forward_list ensures _Alloc::value_type is _Tp.\n+ using pointer = typename allocator_traits<_Alloc>::pointer;\n+#else\n+ using _Tp_alloc_traits\n+\t= typename allocator_traits<_Alloc>::template rebind_traits<_Tp>;\n+ using pointer = typename _Tp_alloc_traits::pointer;\n+#endif\n+\n protected:\n- typedef __alloc_rebind<_Alloc, _Fwd_list_node<_Tp>> _Node_alloc_type;\n- typedef __gnu_cxx::__alloc_traits<_Node_alloc_type> _Node_alloc_traits;\n+ using _Node_traits = __fwdlist::_Node_traits<_Tp, pointer>;\n+ using _Node = typename _Node_traits::_Node;\n+ using _Node_alloc_type = __alloc_rebind<_Alloc, _Node>;\n+ using _Node_alloc_traits = __gnu_cxx::__alloc_traits<_Node_alloc_type>;\n+ using _Node_ptr = typename _Node_alloc_traits::pointer;\n+ using _Base_ptr = typename _Node_traits::_Node_base::_Base_ptr;\n \n struct _Fwd_list_impl\n : public _Node_alloc_type\n {\n-\t_Fwd_list_node_base _M_head;\n+\ttypename _Node_traits::_Node_base _M_head;\n \n \t_Fwd_list_impl()\n \t noexcept(is_nothrow_default_constructible<_Node_alloc_type>::value)\n@@ -328,9 +634,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n _Fwd_list_impl _M_impl;\n \n public:\n- typedef _Fwd_list_iterator<_Tp>\t\titerator;\n- typedef _Fwd_list_const_iterator<_Tp>\tconst_iterator;\n- typedef _Fwd_list_node<_Tp>\t\t_Node;\n+ using iterator = typename _Node_traits::_Iterator;\n+ using const_iterator = typename _Node_traits::_Const_iterator;\n \n _Node_alloc_type&\n _M_get_Node_allocator() noexcept\n@@ -357,54 +662,71 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n _Fwd_list_base(_Fwd_list_base&&) = default;\n \n ~_Fwd_list_base()\n- { _M_erase_after(&_M_impl._M_head, nullptr); }\n+ { _M_erase_after(_M_impl._M_head._M_base_ptr(), nullptr); }\n \n protected:\n+#if ! _GLIBCXX_INLINE_VERSION\n+ // XXX GLIBCXX_ABI Deprecated\n _Node*\n _M_get_node()\n {\n \tauto __ptr = _Node_alloc_traits::allocate(_M_get_Node_allocator(), 1);\n \treturn std::__to_address(__ptr);\n }\n+#endif\n+\n+ void\n+ _M_put_node(_Node_ptr __p)\n+ {\n+#if _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST\n+\t_Node_alloc_traits::deallocate(_M_get_Node_allocator(), __p, 1);\n+#else\n+\ttypedef typename _Node_alloc_traits::pointer _Ptr;\n+\tauto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__p);\n+\t_Node_alloc_traits::deallocate(_M_get_Node_allocator(), __ptr, 1);\n+#endif\n+ }\n \n template<typename... _Args>\n-\t_Node*\n+\t_Node_ptr\n \t_M_create_node(_Args&&... __args)\n \t{\n-\t _Node* __node = this->_M_get_node();\n-\t __try\n-\t {\n-\t ::new ((void*)__node) _Node;\n-\t _Node_alloc_traits::construct(_M_get_Node_allocator(),\n-\t\t\t\t\t __node->_M_valptr(),\n-\t\t\t\t\t std::forward<_Args>(__args)...);\n-\t }\n-\t __catch(...)\n-\t {\n-\t this->_M_put_node(__node);\n-\t __throw_exception_again;\n-\t }\n-\t return __node;\n+\t auto& __alloc = _M_get_Node_allocator();\n+\t auto __guard = std::__allocate_guarded_obj(__alloc);\n+\t _Node_alloc_traits::construct(__alloc, __guard->_M_valptr(),\n+\t\t\t\t\tstd::forward<_Args>(__args)...);\n+\t auto __p = __guard.release();\n+#if _GLIBCXX_USE_ALLOC_PTR_FOR_FWD_LIST\n+\t return __p;\n+#else\n+\t return std::__to_address(__p);\n+#endif\n \t}\n \n- template<typename... _Args>\n-\t_Fwd_list_node_base*\n-\t_M_insert_after(const_iterator __pos, _Args&&... __args);\n-\n+#pragma GCC diagnostic push\n+#pragma GCC diagnostic ignored \"-Wc++17-extensions\" // if constexpr\n void\n- _M_put_node(_Node* __p)\n+ _M_destroy_node(_Node_ptr __p)\n {\n-\ttypedef typename _Node_alloc_traits::pointer _Ptr;\n-\tauto __ptr = std::pointer_traits<_Ptr>::pointer_to(*__p);\n-\t_Node_alloc_traits::deallocate(_M_get_Node_allocator(), __ptr, 1);\n+\tauto& __alloc = _M_get_Node_allocator();\n+\t// Destroy the element\n+\t_Node_alloc_traits::destroy(__alloc, __p->_M_valptr());\n+\t// Only destroy the node if the pointers require it.\n+\tif constexpr (!is_trivially_destructible<_Base_ptr>::value)\n+\t __p->~_Node();\n+\t_M_put_node(__p);\n }\n+#pragma GCC diagnostic pop\n+\n+ template<typename... _Args>\n+\t_Base_ptr\n+\t_M_insert_after(const_iterator __pos, _Args&&... __args);\n \n- _Fwd_list_node_base*\n- _M_erase_after(_Fwd_list_node_base* __pos);\n+ _Base_ptr\n+ _M_erase_after(_Base_ptr __pos);\n \n- _Fwd_list_node_base*\n- _M_erase_after(_Fwd_list_node_base* __pos,\n-\t\t _Fwd_list_node_base* __last);\n+ _Base_ptr\n+ _M_erase_after(_Base_ptr __pos, _Base_ptr __last);\n };\n \n /**\n@@ -581,12 +903,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \tforward_list(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())\n \t: _Base(_Node_alloc_type(__a))\n \t{\n-\t _Node_base* __to = &this->_M_impl._M_head;\n+\t auto __to = this->_M_impl._M_head._M_base_ptr();\n \t auto __first = ranges::begin(__rg);\n \t const auto __last = ranges::end(__rg);\n \t for (; __first != __last; ++__first)\n \t {\n-\t __to->_M_next = this->_M_create_node(*__first);\n+\t __to->_M_next = this->_M_create_node(*__first)->_M_base_ptr();\n \t __to = __to->_M_next;\n \t }\n \t}\n@@ -776,7 +1098,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n [[__nodiscard__]]\n iterator\n before_begin() noexcept\n- { return iterator(&this->_M_impl._M_head); }\n+ { return iterator(this->_M_impl._M_head._M_base_ptr()); }\n \n /**\n * Returns a read-only (constant) iterator that points before the\n@@ -786,7 +1108,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n [[__nodiscard__]]\n const_iterator\n before_begin() const noexcept\n- { return const_iterator(&this->_M_impl._M_head); }\n+ { return const_iterator(this->_M_impl._M_head._M_base_ptr()); }\n \n /**\n * Returns a read/write iterator that points to the first element\n@@ -845,7 +1167,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n [[__nodiscard__]]\n const_iterator\n cbefore_begin() const noexcept\n- { return const_iterator(&this->_M_impl._M_head); }\n+ { return const_iterator(this->_M_impl._M_head._M_base_ptr()); }\n \n /**\n * Returns a read-only (constant) iterator that points one past\n@@ -884,8 +1206,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n reference\n front()\n {\n-\t_Node* __front = static_cast<_Node*>(this->_M_impl._M_head._M_next);\n-\treturn *__front->_M_valptr();\n+\t_Node& __front = static_cast<_Node&>(*this->_M_impl._M_head._M_next);\n+\treturn *__front._M_valptr();\n }\n \n /**\n@@ -896,8 +1218,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n const_reference\n front() const\n {\n-\t_Node* __front = static_cast<_Node*>(this->_M_impl._M_head._M_next);\n-\treturn *__front->_M_valptr();\n+\t_Node& __front = static_cast<_Node&>(*this->_M_impl._M_head._M_next);\n+\treturn *__front._M_valptr();\n }\n \n // 23.3.4.5 modifiers:\n@@ -990,7 +1312,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n */\n void\n pop_front()\n- { this->_M_erase_after(&this->_M_impl._M_head); }\n+ {\n+\t__glibcxx_requires_nonempty();\n+\tthis->_M_erase_after(this->_M_impl._M_head._M_base_ptr());\n+ }\n \n /**\n * @brief Constructs object in %forward_list after the specified\n@@ -1137,8 +1462,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n */\n iterator\n erase_after(const_iterator __pos)\n- { return iterator(this->_M_erase_after(const_cast<_Node_base*>\n-\t\t\t\t\t (__pos._M_node))); }\n+ { return iterator(this->_M_erase_after(__pos._M_const_cast()._M_node)); }\n \n /**\n * @brief Remove a range of elements.\n@@ -1160,10 +1484,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n */\n iterator\n erase_after(const_iterator __pos, const_iterator __last)\n- { return iterator(this->_M_erase_after(const_cast<_Node_base*>\n-\t\t\t\t\t (__pos._M_node),\n-\t\t\t\t\t const_cast<_Node_base*>\n-\t\t\t\t\t (__last._M_node))); }\n+ {\n+\treturn iterator(this->_M_erase_after(__pos._M_const_cast()._M_node,\n+\t\t\t\t\t __last._M_const_cast()._M_node));\n+ }\n \n /**\n * @brief Swaps data with another %forward_list.\n@@ -1225,7 +1549,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n */\n void\n clear() noexcept\n- { this->_M_erase_after(&this->_M_impl._M_head, nullptr); }\n+ { this->_M_erase_after(this->_M_impl._M_head._M_base_ptr(), nullptr); }\n \n // 23.3.4.6 forward_list operations:\n \ndiff --git a/libstdc++-v3/include/bits/forward_list.tcc b/libstdc++-v3/include/bits/forward_list.tcc\nindex 9750c7c0502b..140e9955714e 100644\n--- a/libstdc++-v3/include/bits/forward_list.tcc\n+++ b/libstdc++-v3/include/bits/forward_list.tcc\n@@ -46,47 +46,42 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \n template<typename _Tp, typename _Alloc>\n template<typename... _Args>\n- _Fwd_list_node_base*\n+ auto\n _Fwd_list_base<_Tp, _Alloc>::\n _M_insert_after(const_iterator __pos, _Args&&... __args)\n+ -> _Base_ptr\n {\n-\t_Fwd_list_node_base* __to\n-\t = const_cast<_Fwd_list_node_base*>(__pos._M_node);\n-\t_Node* __thing = _M_create_node(std::forward<_Args>(__args)...);\n+\tauto __to = __pos._M_const_cast()._M_node;\n+\t_Node_ptr __thing = _M_create_node(std::forward<_Args>(__args)...);\n \t__thing->_M_next = __to->_M_next;\n-\t__to->_M_next = __thing;\n+\t__to->_M_next = __thing->_M_base_ptr();\n \treturn __to->_M_next;\n }\n \n template<typename _Tp, typename _Alloc>\n- _Fwd_list_node_base*\n+ auto\n _Fwd_list_base<_Tp, _Alloc>::\n- _M_erase_after(_Fwd_list_node_base* __pos)\n+ _M_erase_after(_Base_ptr __pos)\n+ -> _Base_ptr\n {\n- _Node* __curr = static_cast<_Node*>(__pos->_M_next);\n- __pos->_M_next = __curr->_M_next;\n- _Node_alloc_traits::destroy(_M_get_Node_allocator(),\n-\t\t\t\t __curr->_M_valptr());\n- __curr->~_Node();\n- _M_put_node(__curr);\n+ auto& __curr = static_cast<_Node&>(*__pos->_M_next);\n+ __pos->_M_next = __curr._M_next;\n+ _M_destroy_node(__curr._M_node_ptr());\n return __pos->_M_next;\n }\n \n template<typename _Tp, typename _Alloc>\n- _Fwd_list_node_base*\n+ auto\n _Fwd_list_base<_Tp, _Alloc>::\n- _M_erase_after(_Fwd_list_node_base* __pos,\n-\t\t _Fwd_list_node_base* __last)\n+ _M_erase_after(_Base_ptr __pos, _Base_ptr __last)\n+ -> _Base_ptr\n {\n- _Node* __curr = static_cast<_Node*>(__pos->_M_next);\n+ _Base_ptr __curr = __pos->_M_next;\n while (__curr != __last)\n \t{\n-\t _Node* __temp = __curr;\n-\t __curr = static_cast<_Node*>(__curr->_M_next);\n-\t _Node_alloc_traits::destroy(_M_get_Node_allocator(),\n-\t\t\t\t __temp->_M_valptr());\n-\t __temp->~_Node();\n-\t _M_put_node(__temp);\n+\t auto& __node = static_cast<_Node&>(*__curr);\n+\t __curr = __curr->_M_next;\n+\t _M_destroy_node(__node._M_node_ptr());\n \t}\n __pos->_M_next = __last;\n return __last;\n@@ -99,10 +94,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n forward_list<_Tp, _Alloc>::\n _M_range_initialize(_InputIterator __first, _InputIterator __last)\n {\n-\t_Node_base* __to = &this->_M_impl._M_head;\n+\tauto __to = this->_M_impl._M_head._M_base_ptr();\n \tfor (; __first != __last; ++__first)\n \t {\n-\t __to->_M_next = this->_M_create_node(*__first);\n+\t __to->_M_next = this->_M_create_node(*__first)->_M_base_ptr();\n \t __to = __to->_M_next;\n \t }\n }\n@@ -113,10 +108,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n forward_list<_Tp, _Alloc>::\n _M_fill_initialize(size_type __n, const value_type& __value)\n {\n- _Node_base* __to = &this->_M_impl._M_head;\n+ auto __to = this->_M_impl._M_head._M_base_ptr();\n for (; __n; --__n)\n \t{\n-\t __to->_M_next = this->_M_create_node(__value);\n+\t __to->_M_next = this->_M_create_node(__value)->_M_base_ptr();\n \t __to = __to->_M_next;\n \t}\n }\n@@ -126,10 +121,10 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n forward_list<_Tp, _Alloc>::\n _M_default_initialize(size_type __n)\n {\n- _Node_base* __to = &this->_M_impl._M_head;\n+ auto __to = this->_M_impl._M_head._M_base_ptr();\n for (; __n; --__n)\n \t{\n-\t __to->_M_next = this->_M_create_node();\n+\t __to->_M_next = this->_M_create_node()->_M_base_ptr();\n \t __to = __to->_M_next;\n \t}\n }\n@@ -220,9 +215,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n _M_splice_after(const_iterator __pos,\n \t\t const_iterator __before, const_iterator __last)\n {\n- _Node_base* __tmp = const_cast<_Node_base*>(__pos._M_node);\n- _Node_base* __b = const_cast<_Node_base*>(__before._M_node);\n- _Node_base* __end = __b;\n+ auto __tmp = __pos._M_const_cast()._M_node;\n+ auto __b = __before._M_const_cast()._M_node;\n+ auto __end = __b;\n \n while (__end && __end->_M_next != __last._M_node)\n \t__end = __end->_M_next;\n@@ -245,9 +240,9 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n if (__pos == __i || __pos == __j)\n \treturn;\n \n- _Node_base* __tmp = const_cast<_Node_base*>(__pos._M_node);\n- __tmp->_M_transfer_after(const_cast<_Node_base*>(__i._M_node),\n-\t\t\t const_cast<_Node_base*>(__j._M_node));\n+ auto __tmp = __pos._M_const_cast()._M_node;\n+ __tmp->_M_transfer_after(__i._M_const_cast()._M_node,\n+\t\t\t __j._M_const_cast()._M_node);\n }\n \n template<typename _Tp, typename _Alloc>\n@@ -261,7 +256,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end());\n \t}\n else\n-\treturn iterator(const_cast<_Node_base*>(__pos._M_node));\n+\treturn __pos._M_const_cast();\n }\n \n template<typename _Tp, typename _Alloc>\n@@ -275,7 +270,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \tif (!__tmp.empty())\n \t return _M_splice_after(__pos, __tmp.before_begin(), __tmp.end());\n \telse\n-\t return iterator(const_cast<_Node_base*>(__pos._M_node));\n+\t return __pos._M_const_cast();\n }\n \n #if __cplusplus > 201703L\n@@ -293,8 +288,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n forward_list __to_destroy(get_allocator());\n \n auto __prev_it = cbefore_begin();\n- while (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next))\n-\tif (*__tmp->_M_valptr() == __val)\n+ while (auto __tmp = __prev_it._M_node->_M_next)\n+\tif (*static_cast<_Node&>(*__tmp)._M_valptr() == __val)\n \t {\n \t __to_destroy.splice_after(__to_destroy.cbefore_begin(),\n \t\t\t\t *this, __prev_it);\n@@ -316,8 +311,8 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \tforward_list __to_destroy(get_allocator());\n \n \tauto __prev_it = cbefore_begin();\n-\twhile (_Node* __tmp = static_cast<_Node*>(__prev_it._M_node->_M_next))\n-\t if (__pred(*__tmp->_M_valptr()))\n+\twhile (auto __tmp = __prev_it._M_node->_M_next)\n+\t if (__pred(*static_cast<_Node&>(*__tmp)._M_valptr()))\n \t {\n \t __to_destroy.splice_after(__to_destroy.cbefore_begin(),\n \t\t\t\t\t*this, __prev_it);\n@@ -372,15 +367,16 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \tif (std::__addressof(__list) == this)\n \t return;\n \n-\t_Node_base* __node = &this->_M_impl._M_head;\n-\twhile (__node->_M_next && __list._M_impl._M_head._M_next)\n+\tusing _Base_ptr = typename _Node::_Base_ptr;\n+\n+\t_Base_ptr __node = this->_M_impl._M_head._M_base_ptr();\n+\t_Base_ptr __other = __list._M_impl._M_head._M_base_ptr();\n+\twhile (__node->_M_next && __other->_M_next)\n \t {\n-\t if (__comp(*static_cast<_Node*>\n-\t\t (__list._M_impl._M_head._M_next)->_M_valptr(),\n-\t\t *static_cast<_Node*>\n-\t\t (__node->_M_next)->_M_valptr()))\n-\t __node->_M_transfer_after(&__list._M_impl._M_head,\n-\t\t\t\t\t__list._M_impl._M_head._M_next);\n+\t auto& __l = static_cast<_Node&>(*__other->_M_next);\n+\t auto& __r = static_cast<_Node&>(*__node->_M_next);\n+\t if (__comp(*__l._M_valptr(), *__r._M_valptr()))\n+\t __node->_M_transfer_after(__other, __other->_M_next);\n \t __node = __node->_M_next;\n \t }\n \n@@ -416,18 +412,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n forward_list<_Tp, _Alloc>::\n sort(_Comp __comp)\n {\n-\t// If `next' is nullptr, return immediately.\n-\t_Node* __list = static_cast<_Node*>(this->_M_impl._M_head._M_next);\n-\tif (!__list)\n+\tif (empty())\n \t return;\n \n+\tusing _Base_ptr = typename _Node::_Base_ptr;\n+\n+\t// If `next' is nullptr, return immediately.\n+\t_Base_ptr __list = this->_M_impl._M_head._M_next;\n+\n \tunsigned long __insize = 1;\n \n \twhile (1)\n \t {\n-\t _Node* __p = __list;\n+\t _Base_ptr __p = __list;\n \t __list = nullptr;\n-\t _Node* __tail = nullptr;\n+\t _Base_ptr __tail = nullptr;\n \n \t // Count number of merges we do in this pass.\n \t unsigned long __nmerges = 0;\n@@ -437,12 +436,12 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t\t++__nmerges;\n \t\t// There exists a merge to be done.\n \t\t// Step `insize' places along from p.\n-\t\t_Node* __q = __p;\n+\t\t_Base_ptr __q = __p;\n \t\tunsigned long __psize = 0;\n \t\tfor (unsigned long __i = 0; __i < __insize; ++__i)\n \t\t {\n \t\t ++__psize;\n-\t\t __q = static_cast<_Node*>(__q->_M_next);\n+\t\t __q = __q->_M_next;\n \t\t if (!__q)\n \t\t break;\n \t\t }\n@@ -454,33 +453,34 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t\twhile (__psize > 0 || (__qsize > 0 && __q))\n \t\t {\n \t\t // Decide whether next node of merge comes from p or q.\n-\t\t _Node* __e;\n+\t\t _Base_ptr __e;\n \t\t if (__psize == 0)\n \t\t {\n \t\t\t// p is empty; e must come from q.\n \t\t\t__e = __q;\n-\t\t\t__q = static_cast<_Node*>(__q->_M_next);\n+\t\t\t__q = __q->_M_next;\n \t\t\t--__qsize;\n \t\t }\n \t\t else if (__qsize == 0 || !__q)\n \t\t {\n \t\t\t// q is empty; e must come from p.\n \t\t\t__e = __p;\n-\t\t\t__p = static_cast<_Node*>(__p->_M_next);\n+\t\t\t__p = __p->_M_next;\n \t\t\t--__psize;\n \t\t }\n-\t\t else if (!__comp(*__q->_M_valptr(), *__p->_M_valptr()))\n+\t\t else if (!__comp(*static_cast<_Node&>(*__q)._M_valptr(),\n+\t\t\t\t *static_cast<_Node&>(*__p)._M_valptr()))\n \t\t {\n \t\t\t// First node of q is not lower; e must come from p.\n \t\t\t__e = __p;\n-\t\t\t__p = static_cast<_Node*>(__p->_M_next);\n+\t\t\t__p = __p->_M_next;\n \t\t\t--__psize;\n \t\t }\n \t\t else\n \t\t {\n \t\t\t// First node of q is lower; e must come from q.\n \t\t\t__e = __q;\n-\t\t\t__q = static_cast<_Node*>(__q->_M_next);\n+\t\t\t__q = __q->_M_next;\n \t\t\t--__qsize;\n \t\t }\n \ndiff --git a/libstdc++-v3/testsuite/23_containers/forward_list/capacity/1.cc b/libstdc++-v3/testsuite/23_containers/forward_list/capacity/1.cc\nindex 119bf6ca0274..590bba5bd254 100644\n--- a/libstdc++-v3/testsuite/23_containers/forward_list/capacity/1.cc\n+++ b/libstdc++-v3/testsuite/23_containers/forward_list/capacity/1.cc\n@@ -36,13 +36,18 @@ test01()\n VERIFY(fld.empty() == true);\n \n #ifdef _GLIBCXX_DEBUG\n- using std::_GLIBCXX_STD_C::_Fwd_list_node;\n+ namespace C = std::_GLIBCXX_STD_C;\n #else\n- using std::_Fwd_list_node;\n+ namespace C = std;\n #endif\n \n- std::allocator<_Fwd_list_node<double> > a;\n+ std::allocator<C::_Fwd_list_node<double>> a;\n VERIFY( fld.max_size() == __gnu_test::max_size(a) );\n+\n+#if _GLIBCXX_FWDLIST_USE_ALLOC_PTR\n+ std::allocator<C::__fwdlist::_Node<double*>> b;\n+ VERIFY( __gnu_test::max_size(b) == __gnu_test::max_size(a) );\n+#endif\n }\n \n int\ndiff --git a/libstdc++-v3/testsuite/23_containers/forward_list/capacity/node_sizes.cc b/libstdc++-v3/testsuite/23_containers/forward_list/capacity/node_sizes.cc\nnew file mode 100644\nindex 000000000000..a709031783b6\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/forward_list/capacity/node_sizes.cc\n@@ -0,0 +1,24 @@\n+// { dg-do compile { target c++11 } }\n+\n+#include <forward_list>\n+\n+#if _GLIBCXX_FWDLIST_USE_ALLOC_PTR\n+\n+#ifdef _GLIBCXX_DEBUG\n+namespace C = std::_GLIBCXX_STD_C;\n+#else\n+namespace C = std;\n+#endif\n+\n+// We use double here because for ADJUST_FIELD_ALIGN targets (like i386)\n+// its alignment differs when used as a data member or as a complete object.\n+static_assert(sizeof(C::_Fwd_list_node<double>)\n+\t == sizeof(C::__fwdlist::_Node<double*>),\n+\t \"node types have same size\");\n+static_assert(alignof(C::_Fwd_list_node<double>)\n+\t == alignof(C::__fwdlist::_Node<double*>),\n+\t \"node types have same alignment\");\n+static_assert(__alignof(C::_Fwd_list_node<double>)\n+\t == __alignof(C::__fwdlist::_Node<double*>),\n+\t \"node types have same preferred alignment\");\n+#endif\ndiff --git a/libstdc++-v3/testsuite/23_containers/forward_list/requirements/completeness.cc b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/completeness.cc\nnew file mode 100644\nindex 000000000000..abc9df504e23\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/completeness.cc\n@@ -0,0 +1,19 @@\n+// { dg-do compile {target c++11 } }\n+\n+// C++17 [forwardlist.overview]\n+// An incomplete type T may be used when instantiating forward_list if the\n+// allocator satisfies the allocator completeness requirements (20.5.3.5.1).\n+// T shall be complete before any member of the resulting specialization\n+// of forward_list is referenced.\n+\n+#include <forward_list>\n+\n+struct Incomplete;\n+\n+// This instantiates std::forward_list, but none of its members.\n+const int sz = sizeof(std::forward_list<Incomplete>);\n+\n+// Technically the following references a member of std::forward_list,\n+// but because our iterators are SCARY it doesn't instantiate any members\n+// of std::forward_list.\n+std::forward_list<Incomplete>::iterator i{};\ndiff --git a/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr.cc b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr.cc\nnew file mode 100644\nindex 000000000000..2f382649d92b\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr.cc\n@@ -0,0 +1,86 @@\n+// { dg-do compile { target c++11 } }\n+\n+#include <forward_list>\n+#include <testsuite_allocator.h>\n+\n+// An allocator that uses __gnu_cxx::_Pointer_adapter as its pointer type.\n+template class std::forward_list<int, __gnu_test::CustomPointerAlloc<int>>;\n+\n+// Unlike __gnu_cxx::_Pointer_adapter, this fancy pointer supports neither\n+// implicit nor explicit conversions from raw pointers. The constructor from\n+// a raw pointer is explicit and requires a second parameter. The only way for\n+// containers to construct one of these pointers is pointer_traits::pointer_to.\n+template<typename T>\n+struct Pointer : __gnu_test::PointerBase<Pointer<T>, T>\n+{\n+ using Base = __gnu_test::PointerBase<Pointer<T>, T>;\n+\n+ Pointer() = default;\n+ Pointer(std::nullptr_t) : Base() { }\n+ explicit Pointer(T* p, int) : Base(p) { }\n+\n+ // Allow conversions to const_pointer and to void_pointer\n+ template<typename U, typename = typename std::enable_if<\n+ (!std::is_const<U>::value && std::is_same<T, const U>::value)\n+ || (std::is_void<T>::value && std::is_convertible<U*, T*>::value)\n+ >::type>\n+ Pointer(const Pointer<U>& p) : Base(p.operator->()) { }\n+\n+ template<typename U>\n+ static typename std::enable_if<std::is_same<U, T>::value, Pointer>::type\n+ pointer_to(U& t)\n+ { return Pointer(std::addressof(t), 1); }\n+};\n+\n+// A minimal allocator that uses Pointer as its pointer type.\n+template<typename T>\n+struct Allocator\n+{\n+ using value_type = T;\n+ using pointer = Pointer<T>;\n+\n+ Allocator() = default;\n+ template<typename U>\n+ Allocator(const Allocator<U>&) { }\n+\n+ pointer allocate(std::size_t n)\n+ { return pointer(std::allocator<T>().allocate(n), 1); }\n+\n+ void deallocate(pointer p, std::size_t n)\n+ {\n+ std::allocator<T>().deallocate(p.operator->(), n);\n+ }\n+\n+ bool operator==(const Allocator&) const { return true; }\n+ bool operator!=(const Allocator&) const { return false; }\n+};\n+\n+template class std::forward_list<int, Allocator<int>>;\n+\n+#include <testsuite_iterators.h>\n+\n+void\n+test_template_members(__gnu_test::input_container<short>& c)\n+{\n+ // Use member functions that are not included in explicit instantiations.\n+ std::forward_list<int, Allocator<int>> l(c.begin(), c.end());\n+ l.assign(c.begin(), c.end());\n+ l.insert_after(l.before_begin(), c.begin(), c.end());\n+ l.emplace_front(1);\n+ l.emplace_after(l.before_begin(), 1);\n+ l.remove_if([](int) { return false; });\n+ l.unique([](int, int) { return false; });\n+ l.merge(l, [](int, int) { return false; });\n+ l.merge(std::move(l), [](int, int) { return false; });\n+ l.sort([](int, int) { return false; });\n+\n+#ifdef __glibcxx_ranges_to_container\n+ short arr[2];\n+ __gnu_test::test_input_range<short> r(arr);\n+ std::forward_list<int, Allocator<int>> l2(std::from_range, r);\n+ l2.assign_range(r);\n+ l2.prepend_range(r);\n+ l2.insert_range_after(l2.begin(), r);\n+#endif\n+}\n+\ndiff --git a/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr_ignored.cc b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr_ignored.cc\nnew file mode 100644\nindex 000000000000..6205a2ff3bf2\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/forward_list/requirements/explicit_instantiation/alloc_ptr_ignored.cc\n@@ -0,0 +1,4 @@\n+// { dg-options \"-D_GLIBCXX_FWDLIST_USE_ALLOC_PTR=0\" }\n+// { dg-do compile { target c++11 } }\n+\n+#include \"alloc_ptr.cc\"\n", "prefixes": [ "v1", "4/4" ] }