Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/patches/2226104/?format=api
{ "id": 2226104, "url": "http://patchwork.ozlabs.org/api/patches/2226104/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/patch/bmm.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.1@forge-stage.sourceware.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": "<bmm.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.1@forge-stage.sourceware.org>", "list_archive_url": null, "date": "2026-04-22T09:01:30", "name": "[v1,1/1] libstdc++: Add P1206R7 from_range members to std::vector [PR111055]", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "a249703a54442613684d3707087e79b9015c5ceb", "submitter": { "id": 93210, "url": "http://patchwork.ozlabs.org/api/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.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.1@forge-stage.sourceware.org/mbox/", "series": [ { "id": 500951, "url": "http://patchwork.ozlabs.org/api/series/500951/?format=api", "web_url": "http://patchwork.ozlabs.org/project/gcc/list/?series=500951", "date": "2026-04-22T09:01:29", "name": "libstdc++: Add P1206R7 from_range members to std::vector [PR111055]", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/500951/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2226104/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2226104/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=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 4g0tct3V8Vz1yCv\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 19:06:21 +1000 (AEST)", "from vm01.sourceware.org (localhost [127.0.0.1])\n\tby sourceware.org (Postfix) with ESMTP id 8AB824B9DB7E\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 22 Apr 2026 09:06:19 +0000 (GMT)", "from forge-stage.sourceware.org (vm08.sourceware.org [38.145.34.39])\n by sourceware.org (Postfix) with ESMTPS id 1186B4B9DB7A\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 09:02:28 +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 D88CF40539\n for <gcc-patches@gcc.gnu.org>; Wed, 22 Apr 2026 09:02:27 +0000 (UTC)" ], "DKIM-Filter": [ "OpenDKIM Filter v2.11.0 sourceware.org 8AB824B9DB7E", "OpenDKIM Filter v2.11.0 sourceware.org 1186B4B9DB7A" ], "DMARC-Filter": "OpenDMARC Filter v1.4.2 sourceware.org 1186B4B9DB7A", "ARC-Filter": "OpenARC Filter v1.0.0 sourceware.org 1186B4B9DB7A", "ARC-Seal": "i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1776848548; cv=none;\n b=Wajt/vs32E+5+VNsiOJqN6VfeYd9v3Lwm6vbpOecM0AHQiHlr+MrAiysu2tcxHENzMOw+N6OpEBgXO/hIeJKJNwk5iMVGg0ywyI1qZz1/qoLKHQo3qMQ1cNVcwTRFY2WFh6UFqtCj+ZJSczdcl1AkMKVXBxVzNv1vT34tKRmD+0=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=sourceware.org; s=key;\n t=1776848548; c=relaxed/simple;\n bh=rcJf4vVvVYdY9tVrQvS2r3c92PTbnol6zkmQlvxxij0=;\n h=From:Date:Subject:To:Message-ID;\n b=S2JWy7/yrEmyVomJalu4ComqAtrDhUMqJmqEJXMGZXf37uGmitOnjr1PF+lo0umvK6ymFVAuRBQf7hNKFtAI65BEMOreY5MqmXL22XFeipITLX9IJA4j2Zd+3eFwKOaNdSZgo4xGIfiOreucQgGnPcF7xjSqmFg9Ygcm3etacSI=", "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 09:01:30 +0000", "Subject": "[PATCH v1 1/1] libstdc++: Add P1206R7 from_range members to\n std::vector [PR111055]", "To": "gcc-patches mailing list <gcc-patches@gcc.gnu.org>", "Message-ID": "\n <bmm.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.1@forge-stage.sourceware.org>", "X-Mailer": "batrachomyomachia", "X-Requested-Reviewer": "ppalka", "X-Pull-Request-Organization": "gcc", "X-Pull-Request-Repository": "gcc-TEST", "X-Pull-Request": "https://forge.sourceware.org/gcc/gcc-TEST/pulls/5", "References": "\n <bmm.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.0@forge-stage.sourceware.org>", "In-Reply-To": "\n <bmm.hhu8xfp4me.gcc.gcc-TEST.redi.5.1.0@forge-stage.sourceware.org>", "X-Patch-URL": "\n https://forge.sourceware.org/redi/gcc/commit/f53e3738a0f3b46f76d2c169a24fe65d3c862667", "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 is another piece of P1206R7, adding new members to std::vector and\nstd::vector<bool>.\n\nThe new tests revealed a latent bug in std::vector<bool>::emplace_back,\nwhich this fixes.\n\nThe __uninitialized_copy_a extension needs to be enhanced to support\npassing non-common ranges (i.e. a sentinel that is a different type from\nthe iterator) and move-only input iterators.\n\nlibstdc++-v3/ChangeLog:\n\n\tPR libstdc++/111055\n\t* include/bits/ranges_base.h (__container_compatible_range): New\n\tconcept.\n\t* include/bits/stl_bvector.h (vector(from_range, R&&, const Alloc&))\n\t(assign_range, insert_range, append_range): Define.\n\t(emplace_back): Forward parameter pack.\n\t* include/bits/stl_uninitialized.h (__do_uninit_copy): Support\n\tnon-common ranges.\n\t(__uninitialized_copy_a): Likewise.\n\t* include/bits/stl_vector.h (_Vector_base::_M_append_range_to):\n\tNew function.\n\t(_Vector_base::_M_append_range): Likewise.\n\t(vector(from_range, R&&, const Alloc&), assign_range): Define.\n\t(append_range): Define.\n\t(insert_range): Declare.\n\t* include/debug/vector (vector(from_range, R&&, const Alloc&))\n\t(assign_range, insert_range, append_range): Define.\n\t* include/bits/vector.tcc (insert_range): Define.\n\t* testsuite/util/testsuite_iterators.h (input_iterator_wrapper_rval):\n\tNew class template.\n\t* testsuite/23_containers/vector/bool/cons/from_range.cc: New test.\n\t* testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc:\n\tNew test.\n\t* testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc:\n\tNew test.\n\t* testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc:\n\tNew test.\n\t* testsuite/23_containers/vector/cons/from_range.cc: New test.\n\t* testsuite/23_containers/vector/modifiers/append_range.cc: New test.\n\t* testsuite/23_containers/vector/modifiers/assign/assign_range.cc:\n\tNew test.\n\t* testsuite/23_containers/vector/modifiers/insert/insert_range.cc:\n\tNew test.\n---\n libstdc++-v3/include/bits/ranges_base.h | 10 ++\n libstdc++-v3/include/bits/stl_bvector.h | 122 ++++++++++++-\n libstdc++-v3/include/bits/stl_uninitialized.h | 37 +++-\n libstdc++-v3/include/bits/stl_vector.h | 166 ++++++++++++++++++\n libstdc++-v3/include/bits/vector.tcc | 123 +++++++++++++\n libstdc++-v3/include/debug/vector | 70 ++++++++\n .../vector/bool/cons/from_range.cc | 91 ++++++++++\n .../bool/modifiers/assign/assign_range.cc | 106 +++++++++++\n .../bool/modifiers/insert/append_range.cc | 93 ++++++++++\n .../bool/modifiers/insert/insert_range.cc | 104 +++++++++++\n .../23_containers/vector/cons/from_range.cc | 108 ++++++++++++\n .../vector/modifiers/append_range.cc | 97 ++++++++++\n .../vector/modifiers/assign/assign_range.cc | 121 +++++++++++++\n .../vector/modifiers/insert/insert_range.cc | 108 ++++++++++++\n .../testsuite/util/testsuite_iterators.h | 20 +++\n 15 files changed, 1367 insertions(+), 9 deletions(-)\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc\n create mode 100644 libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc", "diff": "diff --git a/libstdc++-v3/include/bits/ranges_base.h b/libstdc++-v3/include/bits/ranges_base.h\nindex cb2eba1f841a..a2c743ff56bc 100644\n--- a/libstdc++-v3/include/bits/ranges_base.h\n+++ b/libstdc++-v3/include/bits/ranges_base.h\n@@ -1079,6 +1079,16 @@ namespace ranges\n #if __glibcxx_ranges_to_container // C++ >= 23\n struct from_range_t { explicit from_range_t() = default; };\n inline constexpr from_range_t from_range{};\n+\n+/// @cond undocumented\n+namespace __detail\n+{\n+ template<typename _Rg, typename _Tp>\n+ concept __container_compatible_range\n+ = ranges::input_range<_Rg>\n+\t && convertible_to<ranges::range_reference_t<_Rg>, _Tp>;\n+}\n+/// @endcond\n #endif\n \n _GLIBCXX_END_NAMESPACE_VERSION\ndiff --git a/libstdc++-v3/include/bits/stl_bvector.h b/libstdc++-v3/include/bits/stl_bvector.h\nindex 42261ac5915f..8cf91f26dca7 100644\n--- a/libstdc++-v3/include/bits/stl_bvector.h\n+++ b/libstdc++-v3/include/bits/stl_bvector.h\n@@ -892,6 +892,31 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t}\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Construct a vector from a range.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<bool> _Rg>\n+\tconstexpr\n+\tvector(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())\n+\t: _Base(__a)\n+\t{\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t _M_initialize(size_type(ranges::distance(__rg)));\n+\t ranges::copy(__rg, begin());\n+\t }\n+\t else\n+\t {\n+\t auto __first = ranges::begin(__rg);\n+\t const auto __last = ranges::end(__rg);\n+\t for (; __first != __last; ++__first)\n+\t\templace_back(*__first);\n+\t }\n+\t}\n+#endif\n+\n _GLIBCXX20_CONSTEXPR\n ~vector() _GLIBCXX_NOEXCEPT { }\n \n@@ -996,6 +1021,21 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n { _M_assign_aux(__l.begin(), __l.end(), random_access_iterator_tag()); }\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Assign a range to the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<bool> _Rg>\n+\tconstexpr void\n+\tassign_range(_Rg&& __rg)\n+\t{\n+\t static_assert(assignable_from<bool&, ranges::range_reference_t<_Rg>>);\n+\t clear();\n+\t append_range(std::forward<_Rg>(__rg));\n+\t}\n+#endif\n+\n _GLIBCXX_NODISCARD _GLIBCXX20_CONSTEXPR\n iterator\n begin() _GLIBCXX_NOEXCEPT\n@@ -1279,6 +1319,86 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n { return this->insert(__p, __l.begin(), __l.end()); }\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Insert a range into the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<bool> _Rg>\n+\tconstexpr iterator\n+\tinsert_range(const_iterator __pos, _Rg&& __rg)\n+\t{\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t if (auto __n = size_type(ranges::distance(__rg)))\n+\t\t{\n+\t\t if (capacity() - size() >= __n)\n+\t\t {\n+\t\t std::copy_backward(__pos._M_const_cast(), end(),\n+\t\t\t\t\t this->_M_impl._M_finish\n+\t\t\t\t\t + difference_type(__n));\n+\t\t auto __i = ranges::copy(__rg, __pos._M_const_cast()).out;\n+\t\t this->_M_impl._M_finish += difference_type(__n);\n+\t\t return __i;\n+\t\t }\n+\t\t else\n+\t\t {\n+\t\t const size_type __len =\n+\t\t\t_M_check_len(__n, \"vector<bool>::insert_range\");\n+\t\t const iterator __begin = begin(), __end = end();\n+\t\t _Bit_pointer __q = this->_M_allocate(__len);\n+\t\t iterator __start(std::__addressof(*__q), 0);\n+\t\t iterator __i = _M_copy_aligned(__begin,\n+\t\t\t\t\t\t __pos._M_const_cast(),\n+\t\t\t\t\t\t __start);\n+\t\t __i = ranges::copy(__rg, __i).out;\n+\t\t iterator __finish = std::copy(__pos._M_const_cast(),\n+\t\t\t\t\t\t __end, __i);\n+\t\t this->_M_deallocate();\n+\t\t this->_M_impl._M_end_of_storage = __q + _S_nword(__len);\n+\t\t this->_M_impl._M_start = __start;\n+\t\t this->_M_impl._M_finish = __finish;\n+\t\t return __i;\n+\t\t }\n+\t\t}\n+\t else\n+\t\treturn __pos._M_const_cast();\n+\t }\n+\t else\n+\t return insert_range(__pos,\n+\t\t\t\tvector(from_range, __rg, get_allocator()));\n+\t}\n+\n+ /**\n+ * @brief Append a range at the end of the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<bool> _Rg>\n+\tconstexpr void\n+\tappend_range(_Rg&& __rg)\n+\t{\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t reserve(size() + size_type(ranges::distance(__rg)));\n+\t this->_M_impl._M_finish = ranges::copy(__rg, end()).out;\n+\t }\n+\t else\n+\t {\n+\t auto __first = ranges::begin(__rg);\n+\t const auto __last = ranges::end(__rg);\n+\t size_type __n = size();\n+\t const size_type __cap = capacity();\n+\t for (; __first != __last && __n < __cap; ++__first, (void)++__n)\n+\t\templace_back(*__first);\n+\t if (__first != __last)\n+\t\t{\n+\t\t ranges::subrange __rest(std::move(__first), __last);\n+\t\t append_range(vector(from_range, __rest, get_allocator()));\n+\t\t}\n+\t }\n+\t}\n+#endif // ranges_to_container\n+\n _GLIBCXX20_CONSTEXPR\n void\n pop_back()\n@@ -1343,7 +1463,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n #endif\n \templace_back(_Args&&... __args)\n \t{\n-\t push_back(bool(__args...));\n+\t push_back(bool(std::forward<_Args>(__args)...));\n #if __cplusplus > 201402L\n \t return back();\n #endif\ndiff --git a/libstdc++-v3/include/bits/stl_uninitialized.h b/libstdc++-v3/include/bits/stl_uninitialized.h\nindex de3e8cbeaf58..2190261134e0 100644\n--- a/libstdc++-v3/include/bits/stl_uninitialized.h\n+++ b/libstdc++-v3/include/bits/stl_uninitialized.h\n@@ -132,10 +132,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n };\n \n // This is the default implementation of std::uninitialized_copy.\n- template<typename _InputIterator, typename _ForwardIterator>\n+ // This can be used with C++20 iterators and non-common ranges.\n+ template<typename _InputIterator, typename _Sentinel,\n+\t typename _ForwardIterator>\n _GLIBCXX20_CONSTEXPR\n _ForwardIterator\n- __do_uninit_copy(_InputIterator __first, _InputIterator __last,\n+ __do_uninit_copy(_InputIterator __first, _Sentinel __last,\n \t\t _ForwardIterator __result)\n {\n _UninitDestroyGuard<_ForwardIterator> __guard(__result);\n@@ -568,11 +570,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n // default allocator. For nondefault allocators we do not use\n // any of the POD optimizations.\n \n- template<typename _InputIterator, typename _ForwardIterator,\n-\t typename _Allocator>\n+ template<typename _InputIterator, typename _Sentinel,\n+\t typename _ForwardIterator, typename _Allocator>\n _GLIBCXX20_CONSTEXPR\n _ForwardIterator\n- __uninitialized_copy_a(_InputIterator __first, _InputIterator __last,\n+ __uninitialized_copy_a(_InputIterator __first, _Sentinel __last,\n \t\t\t _ForwardIterator __result, _Allocator& __alloc)\n {\n _UninitDestroyGuard<_ForwardIterator, _Allocator>\n@@ -586,17 +588,36 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION\n }\n \n #if _GLIBCXX_HOSTED\n- template<typename _InputIterator, typename _ForwardIterator, typename _Tp>\n+ template<typename _InputIterator, typename _Sentinel,\n+\t typename _ForwardIterator, typename _Tp>\n _GLIBCXX20_CONSTEXPR\n inline _ForwardIterator\n- __uninitialized_copy_a(_InputIterator __first, _InputIterator __last,\n+ __uninitialized_copy_a(_InputIterator __first, _Sentinel __last,\n \t\t\t _ForwardIterator __result, allocator<_Tp>&)\n {\n #ifdef __cpp_lib_is_constant_evaluated\n if (std::is_constant_evaluated())\n-\treturn std::__do_uninit_copy(__first, __last, __result);\n+\treturn std::__do_uninit_copy(std::move(__first), __last, __result);\n #endif\n+\n+#ifdef __glibcxx_ranges\n+ if constexpr (!is_same_v<_InputIterator, _Sentinel>)\n+\t{\n+\t // Convert to a common range if possible, to benefit from memcpy\n+\t // optimizations that std::uninitialized_copy might use.\n+\t if constexpr (sized_sentinel_for<_Sentinel, _InputIterator>\n+\t\t\t && random_access_iterator<_InputIterator>)\n+\t return std::uninitialized_copy(__first,\n+\t\t\t\t\t __first + (__last - __first),\n+\t\t\t\t\t __result);\n+\t else // Just use default implementation.\n+\t return std::__do_uninit_copy(std::move(__first), __last, __result);\n+\t}\n+ else\n+\treturn std::uninitialized_copy(std::move(__first), __last, __result);\n+#else\n return std::uninitialized_copy(__first, __last, __result);\n+#endif\n }\n #endif\n \ndiff --git a/libstdc++-v3/include/bits/stl_vector.h b/libstdc++-v3/include/bits/stl_vector.h\nindex 8982ca2b9eee..df48ba3377fa 100644\n--- a/libstdc++-v3/include/bits/stl_vector.h\n+++ b/libstdc++-v3/include/bits/stl_vector.h\n@@ -65,6 +65,10 @@\n #if __cplusplus >= 202002L\n # include <compare>\n #endif\n+#if __cplusplus > 202002L\n+# include <bits/ranges_algobase.h> // ranges::copy\n+# include <bits/ranges_util.h> // ranges::subrange\n+#endif\n \n #include <debug/assertions.h>\n \n@@ -399,6 +403,29 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\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 }\n+\n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ // Called by insert_range, and indirectly by assign_range, append_range.\n+ // Initializes new elements in storage at __ptr and updates __ptr to\n+ // point after the last new element.\n+ // Provides strong exception safety guarantee.\n+ // Requires [ptr, ptr+distance(rg)) is a valid range.\n+ template<ranges::input_range _Rg>\n+\tconstexpr void\n+\t_M_append_range_to(_Rg&& __rg, pointer& __ptr)\n+\t{\n+\t __ptr = std::__uninitialized_copy_a(ranges::begin(__rg),\n+\t\t\t\t\t ranges::end(__rg),\n+\t\t\t\t\t __ptr, _M_get_Tp_allocator());\n+\t}\n+\n+ // Called by assign_range, append_range, insert_range.\n+ // Requires capacity() >= size()+distance(rg).\n+ template<ranges::input_range _Rg>\n+\tconstexpr void\n+\t_M_append_range(_Rg&& __rg)\n+\t{ _M_append_range_to(std::forward<_Rg>(__rg), _M_impl._M_finish); }\n+#endif\n };\n \n /**\n@@ -723,6 +750,47 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t}\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Construct a vector from a range.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr\n+\tvector(from_range_t, _Rg&& __rg, const _Alloc& __a = _Alloc())\n+\t: _Base(__a)\n+\t{\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t const auto __n = size_type(ranges::distance(__rg));\n+\t pointer __start =\n+\t\tthis->_M_allocate(_S_check_init_len(__n,\n+\t\t\t\t\t\t _M_get_Tp_allocator()));\n+\t _Guard_alloc __guard(__start, __n, *this);\n+\t this->_M_impl._M_finish = this->_M_impl._M_start = __start;\n+\t this->_M_impl._M_end_of_storage = __start + __n;\n+\t _Base::_M_append_range(__rg);\n+\t (void) __guard._M_release();\n+\t }\n+\t else\n+\t {\n+\t // If an exception is thrown ~_Base() will deallocate storage,\n+\t // but will not destroy elements. This RAII type destroys them.\n+\t struct _Clear\n+\t {\n+\t\t~_Clear() { if (_M_this) _M_this->clear(); }\n+\t\tvector* _M_this;\n+\t } __guard{this};\n+\n+\t auto __first = ranges::begin(__rg);\n+\t const auto __last = ranges::end(__rg);\n+\t for (; __first != __last; ++__first)\n+\t\templace_back(*__first);\n+\t __guard._M_this = nullptr;\n+\t }\n+\t}\n+#endif\n+\n /**\n * The dtor only erases the elements, and note that if the\n * elements themselves are pointers, the pointed-to memory is\n@@ -859,6 +927,62 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n }\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Assign a range to the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr void\n+\tassign_range(_Rg&& __rg)\n+\t{\n+\t static_assert(assignable_from<_Tp&, ranges::range_reference_t<_Rg>>);\n+\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t const auto __n = size_type(ranges::distance(__rg));\n+\t if (__n <= size())\n+\t\t{\n+\t\t auto __res = ranges::copy(__rg, this->_M_impl._M_start);\n+\t\t _M_erase_at_end(__res.out);\n+\t\t return;\n+\t\t}\n+\n+\t reserve(__n);\n+\t auto __first = ranges::copy_n(ranges::begin(__rg), size(),\n+\t\t\t\t\t this->_M_impl._M_start).in;\n+\t [[maybe_unused]] const auto __diff = __n - size();\n+\t _GLIBCXX_ASAN_ANNOTATE_GROW(__diff);\n+\t _Base::_M_append_range(ranges::subrange(std::move(__first),\n+\t\t\t\t\t\t ranges::end(__rg)));\n+\t _GLIBCXX_ASAN_ANNOTATE_GREW(__diff);\n+\t }\n+\t else // input_range<_Rg> && !sized_range<_Rg>\n+\t {\n+\t auto __first = ranges::begin(__rg);\n+\t const auto __last = ranges::end(__rg);\n+\t pointer __ptr = this->_M_impl._M_start;\n+\t pointer const __end = this->_M_impl._M_finish;\n+\n+\t while (__ptr < __end && __first != __last)\n+\t\t{\n+\t\t *__ptr = *__first;\n+\t\t ++__ptr;\n+\t\t ++__first;\n+\t\t}\n+\n+\t if (__first == __last)\n+\t\t_M_erase_at_end(__ptr);\n+\t else\n+\t\t{\n+\t\t do\n+\t\t emplace_back(*__first);\n+\t\t while (++__first != __last);\n+\t\t}\n+\t }\n+\t}\n+#endif // ranges_to_container\n+\n /// Get a copy of the memory allocation object.\n using _Base::get_allocator;\n \n@@ -1515,6 +1639,41 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t}\n #endif\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Insert a range into the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr iterator\n+\tinsert_range(const_iterator __pos, _Rg&& __rg);\n+\n+ /**\n+ * @brief Append a range at the end of the vector.\n+ * @since C++23\n+ */\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr void\n+\tappend_range(_Rg&& __rg)\n+\t{\n+\t if constexpr (ranges::forward_range<_Rg> || ranges::sized_range<_Rg>)\n+\t {\n+\t const auto __n = size_type(ranges::distance(__rg));\n+\t reserve(size() + __n);\n+\t _GLIBCXX_ASAN_ANNOTATE_GROW(__n);\n+\t _Base::_M_append_range(__rg);\n+\t _GLIBCXX_ASAN_ANNOTATE_GREW(__n);\n+\t }\n+\t else\n+\t {\n+\t auto __first = ranges::begin(__rg);\n+\t const auto __last = ranges::end(__rg);\n+\t for (; __first != __last; ++__first)\n+\t\templace_back(*__first);\n+\t }\n+\t}\n+#endif // ranges_to_container\n+\n /**\n * @brief Remove element at given position.\n * @param __position Iterator pointing to element to be erased.\n@@ -2049,6 +2208,13 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t typename = _RequireAllocator<_Allocator>>\n vector(_InputIterator, _InputIterator, _Allocator = _Allocator())\n -> vector<_ValT, _Allocator>;\n+\n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ template<ranges::input_range _Rg,\n+\t typename _Alloc = allocator<ranges::range_value_t<_Rg>>>\n+ vector(from_range_t, _Rg&&, _Alloc = _Alloc())\n+ -> vector<ranges::range_value_t<_Rg>, _Alloc>;\n+#endif\n #endif\n \n /**\ndiff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc\nindex a99a5b56b77a..542a66173a37 100644\n--- a/libstdc++-v3/include/bits/vector.tcc\n+++ b/libstdc++-v3/include/bits/vector.tcc\n@@ -974,6 +974,129 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER\n \t }\n }\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ template<typename _Tp, typename _Alloc>\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+ constexpr auto\n+ vector<_Tp, _Alloc>::\n+ insert_range(const_iterator __pos, _Rg&& __rg)\n+ -> iterator\n+ {\n+\tif (__pos == cend())\n+\t {\n+\t append_range(std::forward<_Rg>(__rg));\n+\t return end();\n+\t }\n+\n+\tif constexpr (ranges::forward_range<_Rg>)\n+\t {\n+\t // Start of existing elements:\n+\t pointer __old_start = this->_M_impl._M_start;\n+\t // End of existing elements:\n+\t pointer __old_finish = this->_M_impl._M_finish;\n+\t // Insertion point:\n+\t const auto __ins_idx = __pos - cbegin();\n+\t pointer __ins = __old_start + __ins_idx;\n+\t // Number of new elements to insert:\n+\t const auto __n = size_type(ranges::distance(__rg));\n+\t // Number of elements that can fit in unused capacity:\n+\t const auto __cap = this->_M_impl._M_end_of_storage - __old_finish;\n+\t if (__cap >= __n)\n+\t {\n+\t\t// Number of existing elements after insertion point:\n+\t\tconst size_type __elems_after = cend() - __pos;\n+\t\tif (__elems_after > __n)\n+\t\t {\n+\t\t _GLIBCXX_ASAN_ANNOTATE_GROW(__n);\n+\t\t std::__uninitialized_move_a(__old_finish - __n,\n+\t\t\t\t\t\t__old_finish,\n+\t\t\t\t\t\t__old_finish,\n+\t\t\t\t\t\t_M_get_Tp_allocator());\n+\t\t this->_M_impl._M_finish += __n;\n+\t\t _GLIBCXX_ASAN_ANNOTATE_GREW(__n);\n+\t\t std::move_backward(__ins, __old_finish - __n, __old_finish);\n+\t\t ranges::copy(__rg, __ins);\n+\t\t }\n+\t\telse\n+\t\t {\n+\t\t auto __first = ranges::begin(__rg);\n+\t\t const auto __last = ranges::end(__rg);\n+\t\t auto __mid = ranges::next(__first, __elems_after);\n+\t\t _GLIBCXX_ASAN_ANNOTATE_GROW(__n);\n+\t\t _Base::_M_append_range(ranges::subrange(__mid, __last));\n+\t\t _GLIBCXX_ASAN_ANNOTATE_GREW(__n - __elems_after);\n+\t\t std::__uninitialized_move_a(__ins, __old_finish,\n+\t\t\t\t\t\tthis->_M_impl._M_finish,\n+\t\t\t\t\t\t_M_get_Tp_allocator());\n+\t\t this->_M_impl._M_finish += __elems_after;\n+\t\t _GLIBCXX_ASAN_ANNOTATE_GREW(__elems_after);\n+\t\t ranges::copy(__first, __mid, __ins);\n+\t\t }\n+\t }\n+\t else // Reallocate\n+\t {\n+\t\tconst size_type __len\n+\t\t = _M_check_len(__n, \"vector::insert_range\");\n+\n+\t\tstruct _Guard : _Guard_alloc\n+\t\t{\n+\t\t // End of elements to destroy:\n+\t\t pointer _M_finish = _Guard_alloc::_M_storage;\n+\n+\t\t using _Guard_alloc::_Guard_alloc;\n+\n+\t\t constexpr\n+\t\t ~_Guard()\n+\t\t {\n+\t\t std::_Destroy(this->_M_storage, _M_finish,\n+\t\t\t\t this->_M_vect._M_get_Tp_allocator());\n+\t\t }\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+\n+\t\tauto& __alloc = _M_get_Tp_allocator();\n+\n+\t\t// Populate the new storage in three steps. After each step,\n+\t\t// __guard owns the new storage and any elements that have\n+\t\t// been constructed there.\n+\n+\t\t// Move elements from before insertion point to new storage:\n+\t\t__guard._M_finish\n+\t\t = std::__uninitialized_move_if_noexcept_a(\n+\t\t __old_start, __ins, __new_start, __alloc);\n+\n+\t\t// Append new elements to new storage:\n+\t\t_Base::_M_append_range_to(__rg, __guard._M_finish);\n+\n+\t\t// Move elements from after insertion point to new storage:\n+\t\t__guard._M_finish\n+\t\t = std::__uninitialized_move_if_noexcept_a(\n+\t\t\t__ins, __old_finish, __guard._M_finish, __alloc);\n+\n+\t\t_GLIBCXX_ASAN_ANNOTATE_REINIT; // Creates _Asan::_Reinit.\n+\n+\t\t// All elements are in the new storage, exchange ownership\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\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 }\n+\t return begin() + __ins_idx;\n+\t }\n+\telse\n+\t return insert_range(__pos, vector(from_range, std::move(__rg),\n+\t\t\t\t\t _M_get_Tp_allocator()));\n+ }\n+#endif // ranges_to_container\n \n // vector<bool>\n template<typename _Alloc>\ndiff --git a/libstdc++-v3/include/debug/vector b/libstdc++-v3/include/debug/vector\nindex fe43a372485d..f2ab4f737644 100644\n--- a/libstdc++-v3/include/debug/vector\n+++ b/libstdc++-v3/include/debug/vector\n@@ -244,6 +244,19 @@ namespace __debug\n \t const allocator_type& __a = allocator_type())\n : _Base(__l, __a) { }\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ /**\n+ * @brief Construct a vector from a range.\n+ * @since C++23\n+ */\n+ template<std::__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr\n+\tvector(std::from_range_t __t, _Rg&& __rg,\n+\t const allocator_type& __a = allocator_type())\n+\t: _Base(__t, std::forward<_Rg>(__rg), __a)\n+\t{ }\n+#endif\n+\n ~vector() = default;\n #endif\n \n@@ -858,6 +871,56 @@ namespace __debug\n const _Base&\n _M_base() const _GLIBCXX_NOEXCEPT { return *this; }\n \n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ template<std::__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr void\n+\tassign_range(_Rg&& __rg)\n+\t{\n+\t auto __old_begin = _Base::begin();\n+\t auto __old_size = _Base::size();\n+\t _Base::assign_range(__rg);\n+\t if (!std::__is_constant_evaluated())\n+\t {\n+\t if (_Base::begin() != __old_begin)\n+\t\tthis->_M_invalidate_all();\n+\t else if (_Base::size() < __old_size)\n+\t\tthis->_M_invalidate_after_nth(_Base::size());\n+\t this->_M_update_guaranteed_capacity();\n+\t }\n+\t}\n+\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr iterator\n+\tinsert_range(const_iterator __pos, _Rg&& __rg)\n+\t{\n+\t auto __old_begin = _Base::begin();\n+\t auto __old_size = _Base::size();\n+\t auto __res = _Base::insert_range(__pos.base(), __rg);\n+\t if (!std::__is_constant_evaluated())\n+\t {\n+\t if (_Base::begin() != __old_begin)\n+\t\tthis->_M_invalidate_all();\n+\t this->_M_update_guaranteed_capacity();\n+\t }\n+\t return iterator(__res, this);\n+\t}\n+\n+ template<__detail::__container_compatible_range<_Tp> _Rg>\n+\tconstexpr void\n+\tappend_range(_Rg&& __rg)\n+\t{\n+\t auto __old_begin = _Base::begin();\n+\t auto __old_size = _Base::size();\n+\t _Base::append_range(__rg);\n+\t if (!std::__is_constant_evaluated())\n+\t {\n+\t if (_Base::begin() != __old_begin)\n+\t\tthis->_M_invalidate_all();\n+\t this->_M_update_guaranteed_capacity();\n+\t }\n+\t}\n+#endif\n+\n private:\n void\n _M_invalidate_after_nth(difference_type __n) _GLIBCXX_NOEXCEPT\n@@ -937,6 +1000,13 @@ namespace __debug\n \t typename = _RequireAllocator<_Allocator>>\n vector(size_t, _Tp, _Allocator = _Allocator())\n -> vector<_Tp, _Allocator>;\n+\n+#if __glibcxx_ranges_to_container // C++ >= 23\n+ template<ranges::input_range _Rg,\n+\t typename _Alloc = allocator<ranges::range_value_t<_Rg>>>\n+ vector(from_range_t, _Rg&&, _Alloc = _Alloc())\n+ -> vector<ranges::range_value_t<_Rg>, _Alloc>;\n+#endif\n #endif\n \n } // namespace __debug\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc\nnew file mode 100644\nindex 000000000000..f5180e5a2433\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/cons/from_range.cc\n@@ -0,0 +1,91 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test(Alloc alloc)\n+{\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,1,0,1,0,0,1,0,0};\n+\n+ auto eq = [](const std::vector<bool, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ std::vector<bool, Alloc> v0(std::from_range, Range(a, a+0));\n+ VERIFY( v0.empty() );\n+ VERIFY( v0.get_allocator() == Alloc() );\n+\n+ std::vector<bool, Alloc> v4(std::from_range, Range(a, a+4));\n+ VERIFY( eq(v4, {a, 4}) );\n+ VERIFY( v4.get_allocator() == Alloc() );\n+\n+ std::vector<bool, Alloc> v9(std::from_range, Range(a, a+9), alloc);\n+ VERIFY( eq(v9, {a, 9}) );\n+ VERIFY( v9.get_allocator() == alloc );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range>(std::allocator<bool>());\n+ do_test<Range>(__gnu_test::uneq_allocator<bool>(42));\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<bool>>();\n+ do_test_a<test_forward_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<bool>>();\n+ do_test_a<test_input_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(bool v) : val(v) { }\n+ operator bool() && { return val; }\n+ bool operator==(bool b) const { return b == val; }\n+ bool val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test_a<rvalue_input_range>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<bool>, std::allocator<bool>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc\nnew file mode 100644\nindex 000000000000..a014dfe90de7\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/assign/assign_range.cc\n@@ -0,0 +1,106 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,1,0,1,0,0,1,0,0};\n+\n+ auto eq = [](const std::vector<bool, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ Range r4(a, a+4);\n+ Range r9(a);\n+\n+ std::vector<bool, Alloc> v;\n+ v.assign_range(Range(a, a));\n+ VERIFY( v.empty() );\n+ VERIFY( v.capacity() == 0 );\n+ v.assign_range(r4);\n+ VERIFY( eq(v, {a, 4}) );\n+ v.clear();\n+ v.assign_range(r9); // larger than v.capacity()\n+ VERIFY( eq(v, a) );\n+ v.assign_range(r9); // equal to size() and equal to capacity()\n+ VERIFY( eq(v, a) );\n+ v.resize(1);\n+ v.assign_range(r4); // larger than size(), smaller than capacity()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.clear();\n+ v.resize(4);\n+ v.assign_range(r4); // equal to size(), smaller than capacity()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.shrink_to_fit();\n+ v.assign_range(r9); // larger than capacity()\n+ VERIFY( eq(v, a) );\n+ v.assign_range(Range(a, a));\n+ VERIFY( v.empty() );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<bool>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<bool>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<bool>>();\n+ do_test_a<test_forward_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<bool>>();\n+ do_test_a<test_input_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(bool v) : val(v) { }\n+ operator bool() && { return val; }\n+ bool operator==(bool b) const { return b == val; }\n+ bool val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test_a<rvalue_input_range>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<bool>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc\nnew file mode 100644\nindex 000000000000..e811a1697e02\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/append_range.cc\n@@ -0,0 +1,93 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,1,0,1,0,0,1,0,0};\n+\n+ auto eq = [](const std::vector<bool, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ Range r4(a, a+4);\n+ Range r5(a+4, a+9);\n+\n+ std::vector<bool, Alloc> v;\n+ v.append_range(r4);\n+ VERIFY( eq(v, {a, 4}) );\n+ v.append_range(r5); // larger than v.capacity()\n+ VERIFY( eq(v, a) );\n+ v.append_range(Range(a, a));\n+ VERIFY( eq(v, a) );\n+ v.clear();\n+ v.append_range(Range(a, a));\n+ VERIFY( v.empty() );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<bool>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<bool>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<bool>>();\n+ do_test_a<test_forward_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<bool>>();\n+ do_test_a<test_input_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(bool v) : val(v) { }\n+ operator bool() && { return val; }\n+ bool operator==(bool b) const { return b == val; }\n+ bool val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test_a<rvalue_input_range>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<bool>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc\nnew file mode 100644\nindex 000000000000..82b67cdb8b9b\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/bool/modifiers/insert/insert_range.cc\n@@ -0,0 +1,104 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,1,0,1,0,0,1,0,0};\n+\n+ auto eq = [](const std::vector<bool, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ std::vector<bool, Alloc> v;\n+ v.insert_range(v.begin(), Range(a, a+0));\n+ VERIFY( v.empty() );\n+ VERIFY( v.capacity() == 0 );\n+ v.insert_range(v.begin(), Range(a, a+4));\n+ VERIFY( eq(v, {a, a+4}) );\n+ v.clear();\n+ v.insert_range(v.begin(), Range(a, a+5));\n+ VERIFY( eq(v, {a+4, a+9}) );\n+ v.insert_range(v.begin(), Range(a, a+4));\n+ VERIFY( eq(v, a) );\n+ v.clear();\n+ v.shrink_to_fit();\n+ v.insert_range(v.begin(), Range(a, a+3));\n+ v.insert_range(v.end(), Range(a+6, a+9));\n+ v.insert_range(v.begin()+3, Range(a+3, a+6));\n+ VERIFY( eq(v, a) );\n+ v.resize(3);\n+ v.insert_range(v.begin()+1, Range(a+4, a+9));\n+ v.insert_range(v.begin()+1, Range(a+1, a+3));\n+ v.resize(9);\n+ VERIFY( eq(v, a) );\n+ v.insert_range(v.begin(), Range(a, a));\n+ VERIFY( eq(v, a) );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<bool>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<bool>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<bool>>();\n+ do_test_a<test_forward_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<bool>>();\n+ do_test_a<test_input_sized_range<bool>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<bool, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<bool, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(bool v) : val(v) { }\n+ operator bool() && { return val; }\n+ bool operator==(bool b) const { return b == val; }\n+ bool val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test_a<rvalue_input_range>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<bool>, std::allocator<bool>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc\nnew file mode 100644\nindex 000000000000..d709c77720d2\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/cons/from_range.cc\n@@ -0,0 +1,108 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+void\n+test_deduction_guide(long* p)\n+{\n+ __gnu_test::test_input_range<long> r(p, p);\n+ std::vector v(std::from_range, r);\n+ static_assert(std::is_same_v<decltype(v), std::vector<long>>);\n+\n+ using Alloc = __gnu_test::SimpleAllocator<long>;\n+ Alloc alloc;\n+ std::vector v2(std::from_range, r, alloc);\n+ static_assert(std::is_same_v<decltype(v2), std::vector<long, Alloc>>);\n+}\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test(Alloc alloc)\n+{\n+ // The vector's value_type.\n+ using V = typename std::allocator_traits<Alloc>::value_type;\n+\n+ // The range's value_type.\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,2,3,4,5,6,7,8,9};\n+\n+ auto eq = [](const std::vector<V, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ std::vector<V, Alloc> v0(std::from_range, Range(a, a+0));\n+ VERIFY( v0.empty() );\n+ VERIFY( v0.get_allocator() == Alloc() );\n+\n+ std::vector<V, Alloc> v4(std::from_range, Range(a, a+4));\n+ VERIFY( eq(v4, {a, 4}) );\n+ VERIFY( v4.get_allocator() == Alloc() );\n+\n+ std::vector<V, Alloc> v9(std::from_range, Range(a, a+9), alloc);\n+ VERIFY( eq(v9, {a, 9}) );\n+ VERIFY( v9.get_allocator() == alloc );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range>(std::allocator<int>());\n+ do_test<Range>(__gnu_test::uneq_allocator<int>(42));\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<int>>();\n+ do_test_a<test_forward_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<int>>();\n+ do_test_a<test_input_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(int v) : val(v) { }\n+ operator int() && { return val; }\n+ bool operator==(int b) const { return b == val; }\n+ int val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test<rvalue_input_range, std::allocator<int>>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<int>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc\nnew file mode 100644\nindex 000000000000..ff86cb745573\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/append_range.cc\n@@ -0,0 +1,97 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ // The vector's value_type.\n+ using V = typename std::allocator_traits<Alloc>::value_type;\n+\n+ // The range's value_type.\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,2,3,4,5,6,7,8,9};\n+\n+ auto eq = [](const std::vector<V, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ Range r4(a, a+4);\n+ Range r5(a+4, a+9);\n+\n+ std::vector<V, Alloc> v;\n+ v.append_range(r4);\n+ VERIFY( eq(v, {a, 4}) );\n+ v.append_range(r5); // larger than v.capacity()\n+ VERIFY( eq(v, a) );\n+ v.append_range(Range(a, a));\n+ VERIFY( eq(v, a) );\n+ v.clear();\n+ v.append_range(Range(a, a));\n+ VERIFY( v.empty() );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<int>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<int>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<int>>();\n+ do_test_a<test_forward_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<int>>();\n+ do_test_a<test_input_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(int v) : val(v) { }\n+ operator int() && { return val; }\n+ bool operator==(int b) const { return b == val; }\n+ int val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test<rvalue_input_range, std::allocator<int>>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<int>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc\nnew file mode 100644\nindex 000000000000..c3302e988495\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/assign/assign_range.cc\n@@ -0,0 +1,121 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ // The vector's value_type.\n+ using V = typename std::allocator_traits<Alloc>::value_type;\n+\n+ // The range's value_type.\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,2,3,4,5,6,7,8,9};\n+\n+ auto eq = [](const std::vector<V, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ Range r4(a, a+4);\n+ Range r9(a);\n+\n+ // assign to empty vector\n+ std::vector<V, Alloc> v;\n+ v.assign_range(Range(a, a));\n+ VERIFY( v.empty() );\n+ VERIFY( v.capacity() == 0 );\n+ v.assign_range(r4);\n+ VERIFY( eq(v, {a, 4}) );\n+ v.clear();\n+ v.assign_range(r9); // larger than v.capacity()\n+ VERIFY( eq(v, a) );\n+ v.clear();\n+ v.assign_range(r4); // smaller than v.capacity()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.clear();\n+ v.assign_range(r9); // equal to v.capacity()\n+ VERIFY( eq(v, a) );\n+\n+ // assign to non-empty vector\n+ v.assign_range(r4); // smaller than size()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.assign_range(r9); // larger than size(), equal to capacity()\n+ VERIFY( eq(v, a) );\n+ v.resize(1);\n+ v.assign_range(r4); // larger than size(), smaller than capacity()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.clear();\n+ v.resize(4);\n+ v.assign_range(r4); // equal to size(), smaller than capacity()\n+ VERIFY( eq(v, {a, 4}) );\n+ v.shrink_to_fit();\n+ v.assign_range(r9); // larger than capacity()\n+ VERIFY( eq(v, a) );\n+ v.assign_range(Range(a, a));\n+ VERIFY( v.empty() );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<int>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<int>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<int>>();\n+ do_test_a<test_forward_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<int>>();\n+ do_test_a<test_input_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(int v) : val(v) { }\n+ operator int() && { return val; }\n+ bool operator==(int b) const { return b == val; }\n+ int val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test<rvalue_input_range, std::allocator<int>>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<int>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc\nnew file mode 100644\nindex 000000000000..4cfab10eb4c9\n--- /dev/null\n+++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc\n@@ -0,0 +1,108 @@\n+// { dg-do compile { target c++23 } }\n+\n+#include <vector>\n+#include <span>\n+#include <testsuite_hooks.h>\n+#include <testsuite_iterators.h>\n+#include <testsuite_allocator.h>\n+\n+template<typename Range, typename Alloc>\n+constexpr void\n+do_test()\n+{\n+ // The vector's value_type.\n+ using V = typename std::allocator_traits<Alloc>::value_type;\n+\n+ // The range's value_type.\n+ using T = std::ranges::range_value_t<Range>;\n+ T a[]{1,2,3,4,5,6,7,8,9};\n+\n+ auto eq = [](const std::vector<V, Alloc>& l, std::span<T> r) {\n+ if (l.size() != r.size())\n+ return false;\n+ for (auto i = 0u; i < l.size(); ++i)\n+ if (l[i] != r[i])\n+\treturn false;\n+ return true;\n+ };\n+\n+ std::vector<V, Alloc> v;\n+ v.insert_range(v.begin(), Range(a, a));\n+ VERIFY( v.empty() );\n+ VERIFY( v.capacity() == 0 );\n+ v.insert_range(v.begin(), Range(a, a+4));\n+ VERIFY( eq(v, {a, a+4}) );\n+ v.clear();\n+ v.insert_range(v.begin(), Range(a, a+5));\n+ VERIFY( eq(v, {a+4, a+9}) );\n+ v.insert_range(v.begin(), Range(a, a+4));\n+ VERIFY( eq(v, a) );\n+ v.clear();\n+ v.shrink_to_fit();\n+ v.insert_range(v.begin(), Range(a, a+3));\n+ v.insert_range(v.end(), Range(a+6, a+9));\n+ v.insert_range(v.begin()+3, Range(a+3, a+6));\n+ VERIFY( eq(v, a) );\n+ v.resize(3);\n+ v.insert_range(v.begin()+1, Range(a+4, a+9));\n+ v.insert_range(v.begin()+1, Range(a+1, a+3));\n+ v.resize(9);\n+ VERIFY( eq(v, a) );\n+ v.insert_range(v.begin() + 6, Range(a, a));\n+ VERIFY( eq(v, a) );\n+}\n+\n+template<typename Range>\n+void\n+do_test_a()\n+{\n+ do_test<Range, std::allocator<int>>();\n+ do_test<Range, __gnu_test::SimpleAllocator<int>>();\n+}\n+\n+bool\n+test_ranges()\n+{\n+ using namespace __gnu_test;\n+\n+ do_test_a<test_forward_range<int>>();\n+ do_test_a<test_forward_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, forward_iterator_wrapper>>();\n+\n+ do_test_a<test_input_range<int>>();\n+ do_test_a<test_input_sized_range<int>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper>>();\n+\n+ do_test_a<test_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range<int, input_iterator_wrapper_nocopy>>();\n+ do_test_a<test_sized_range_sized_sent<int, input_iterator_wrapper_nocopy>>();\n+\n+ do_test_a<test_forward_range<short>>();\n+ do_test_a<test_input_range<short>>();\n+\n+ // Not lvalue-convertible to bool\n+ struct C {\n+ C(int v) : val(v) { }\n+ operator int() && { return val; }\n+ bool operator==(int b) const { return b == val; }\n+ int val;\n+ };\n+ using rvalue_input_range = test_range<C, input_iterator_wrapper_rval>;\n+ do_test<rvalue_input_range, std::allocator<int>>();\n+\n+ return true;\n+}\n+\n+constexpr bool\n+test_constexpr()\n+{\n+ // XXX: this doesn't test the non-forward_range code paths are constexpr.\n+ do_test<std::span<short>, std::allocator<int>>;\n+ return true;\n+}\n+\n+int main()\n+{\n+ test_ranges();\n+ static_assert( test_constexpr() );\n+}\ndiff --git a/libstdc++-v3/testsuite/util/testsuite_iterators.h b/libstdc++-v3/testsuite/util/testsuite_iterators.h\nindex e7f7abe222d5..aafafa710b7e 100644\n--- a/libstdc++-v3/testsuite/util/testsuite_iterators.h\n+++ b/libstdc++-v3/testsuite/util/testsuite_iterators.h\n@@ -783,6 +783,26 @@ namespace __gnu_test\n }\n };\n \n+ // An input iterator type with an rvalue reference type.\n+ template<typename T>\n+ struct input_iterator_wrapper_rval : input_iterator_wrapper<T>\n+ {\n+ using input_iterator_wrapper<T>::input_iterator_wrapper;\n+\n+ using input_iterator_wrapper<T>::operator++;\n+\n+ input_iterator_wrapper_rval&\n+ operator++()\n+ {\n+\tinput_iterator_wrapper<T>::operator++();\n+\treturn *this;\n+ }\n+\n+ T&&\n+ operator*() const\n+ { return std::move(input_iterator_wrapper<T>::operator*()); }\n+ };\n+\n // A type meeting the minimum std::range requirements\n template<typename T, template<typename> class Iter>\n class test_range\n", "prefixes": [ "v1", "1/1" ] }