[libcxx-commits] [libcxx] [libc++] Fix insertion into `deque` from prvalue ranges (PR #160022)
A. Jiang via libcxx-commits
libcxx-commits at lists.llvm.org
Mon Sep 22 10:13:03 PDT 2025
https://github.com/frederick-vs-ja updated https://github.com/llvm/llvm-project/pull/160022
>From 029fe7413c7bc42721db531c62130700fd36d853 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 22 Sep 2025 12:00:40 +0800
Subject: [PATCH 1/3] [libc++] Fix insertion into `deque` from prvalue ranges
When the iterator of the source range in `*_range` functions
dereferences to a prvalue, it should be at most _Cpp17InputIterator_
while possibly modeling `random_access_iterator`. When inserting such a
range into a container, we should use `ranges::prev`/`ranges::next`
instead of `std::prev`/`std::next` internally.
---
libcxx/include/deque | 11 +-
.../test/std/containers/from_range_helpers.h | 36 +++
.../deque.modifiers/append_range.pass.cpp | 3 +
.../deque.modifiers/assign_range.pass.cpp | 3 +
.../deque.modifiers/insert_range.pass.cpp | 3 +
.../deque.modifiers/prepend_range.pass.cpp | 3 +
.../insert_range_sequence_containers.h | 214 ++++++++++++++++++
7 files changed, 271 insertions(+), 2 deletions(-)
diff --git a/libcxx/include/deque b/libcxx/include/deque
index 98d1dbbddb7e8..ea83c50bceea0 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -185,6 +185,7 @@ template <class T, class Allocator, class Predicate>
# include <__algorithm/copy_n.h>
# include <__algorithm/equal.h>
# include <__algorithm/fill_n.h>
+# include <__algorithm/iterator_operations.h>
# include <__algorithm/lexicographical_compare.h>
# include <__algorithm/lexicographical_compare_three_way.h>
# include <__algorithm/max.h>
@@ -1916,6 +1917,12 @@ template <class _Tp, class _Allocator>
template <class _BiIter>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n) {
+# if _LIBCPP_STD_VER >= 20
+ using _Ops = _IterOps<
+ conditional_t<__has_bidirectional_iterator_category<_BiIter>::value, _ClassicAlgPolicy, _RangeAlgPolicy>>;
+# else
+ using _Ops = _IterOps<_ClassicAlgPolicy>;
+# endif
size_type __pos = __p - begin();
size_type __to_end = size() - __pos;
allocator_type& __a = __alloc();
@@ -1928,7 +1935,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
iterator __i = __old_begin;
_BiIter __m = __f;
if (__n > __pos) {
- __m = __pos < __n / 2 ? std::prev(__l, __pos) : std::next(__f, __n - __pos);
+ __m = __pos < __n / 2 ? _Ops::prev(__l, __pos) : _Ops::next(__f, __n - __pos);
for (_BiIter __j = __m; __j != __f; --__start_, ++__size())
__alloc_traits::construct(__a, std::addressof(*--__i), *--__j);
__n = __pos;
@@ -1955,7 +1962,7 @@ deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f,
_BiIter __m = __l;
size_type __de = size() - __pos;
if (__n > __de) {
- __m = __de < __n / 2 ? std::next(__f, __de) : std::prev(__l, __n - __de);
+ __m = __de < __n / 2 ? _Ops::next(__f, __de) : _Ops::prev(__l, __n - __de);
for (_BiIter __j = __m; __j != __l; ++__i, (void)++__j, ++__size())
__alloc_traits::construct(__a, std::addressof(*__i), *__j);
__n = __de;
diff --git a/libcxx/test/std/containers/from_range_helpers.h b/libcxx/test/std/containers/from_range_helpers.h
index edf1d6ce528d7..e1895a528efb2 100644
--- a/libcxx/test/std/containers/from_range_helpers.h
+++ b/libcxx/test/std/containers/from_range_helpers.h
@@ -10,9 +10,12 @@
#define SUPPORT_FROM_RANGE_HELPERS_H
#include <array>
+#include <concepts>
#include <cstddef>
#include <iterator>
+#include <ranges>
#include <type_traits>
+#include <utility>
#include <vector>
#include "min_allocator.h"
@@ -50,6 +53,39 @@ constexpr auto wrap_input(std::vector<T>& input) {
return std::ranges::subrange(std::move(b), std::move(e));
}
+// https://llvm.org/PR159943
+struct DecayCopy {
+ template <class T>
+ requires std::convertible_to<T, std::decay_t<T>>
+ static constexpr std::decay_t<T> operator()(T&& t) {
+ return std::forward<T>(t);
+ }
+};
+
+template <class Iter, class Sent, std::ranges::input_range Range>
+constexpr auto wrap_input_decay(Range&& input) {
+ auto b = Iter(std::ranges::begin(input));
+ auto e = Sent(Iter(std::ranges::end(input)));
+ if constexpr (std::is_reference_v<std::iter_reference_t<Iter>>)
+ return std::ranges::subrange(std::move(b), std::move(e)) | std::views::transform(DecayCopy{});
+ else
+ return std::ranges::subrange(std::move(b), std::move(e));
+}
+
+template <class Iter, class Sent, class T, std::size_t N>
+constexpr auto wrap_input_decay(std::array<T, N>& input) {
+ auto b = Iter(input.data());
+ auto e = Sent(Iter(input.data() + input.size()));
+ return std::ranges::subrange(std::move(b), std::move(e)) | std::views::transform(DecayCopy{});
+}
+
+template <class Iter, class Sent, class T>
+constexpr auto wrap_input_decay(std::vector<T>& input) {
+ auto b = Iter(input.data());
+ auto e = Sent(Iter(input.data() + input.size()));
+ return std::ranges::subrange(std::move(b), std::move(e)) | std::views::transform(DecayCopy{});
+}
+
struct KeyValue {
int key; // Only the key is considered for equality comparison.
char value; // Allows distinguishing equivalent instances.
diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/append_range.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/append_range.pass.cpp
index 56a1d226db46f..69f295264f107 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/append_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/append_range.pass.cpp
@@ -29,6 +29,9 @@ int main(int, char**) {
test_sequence_append_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
+ test_sequence_append_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
+ LIBCPP_ASSERT(c.__invariants());
+ });
});
test_sequence_append_range_move_only<std::deque>();
diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/assign_range.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/assign_range.pass.cpp
index 744e03a7b983e..6952133d30fd2 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/assign_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/assign_range.pass.cpp
@@ -28,6 +28,9 @@ int main(int, char**) {
test_sequence_assign_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
+ test_sequence_assign_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
+ LIBCPP_ASSERT(c.__invariants());
+ });
});
test_sequence_assign_range_move_only<std::deque>();
diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_range.pass.cpp
index 7681eb63b9076..9964f6432ea8b 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/insert_range.pass.cpp
@@ -33,6 +33,9 @@ int main(int, char**) {
test_sequence_insert_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
+ test_sequence_insert_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
+ LIBCPP_ASSERT(c.__invariants());
+ });
});
test_sequence_insert_range_move_only<std::deque>();
diff --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/prepend_range.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/prepend_range.pass.cpp
index 3154cd389d2f0..d6cb116a9c77f 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/prepend_range.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/prepend_range.pass.cpp
@@ -29,6 +29,9 @@ int main(int, char**) {
test_sequence_prepend_range<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
LIBCPP_ASSERT(c.__invariants());
});
+ test_sequence_prepend_range_decay<std::deque<int, Alloc>, Iter, Sent>([]([[maybe_unused]] auto&& c) {
+ LIBCPP_ASSERT(c.__invariants());
+ });
});
test_sequence_prepend_range_move_only<std::deque>();
diff --git a/libcxx/test/std/containers/sequences/insert_range_sequence_containers.h b/libcxx/test/std/containers/sequences/insert_range_sequence_containers.h
index 9f404c46df778..3a82e7049fcca 100644
--- a/libcxx/test/std/containers/sequences/insert_range_sequence_containers.h
+++ b/libcxx/test/std/containers/sequences/insert_range_sequence_containers.h
@@ -464,6 +464,76 @@ constexpr void test_sequence_insert_range(Validate validate) {
}
}
+// https://llvm.org/PR159943
+template <class Container, class Iter, class Sent, class Validate>
+constexpr void test_sequence_insert_range_decay(Validate validate) {
+ using T = Container::value_type;
+ using D = Container::difference_type;
+ auto get_pos = [](auto& c, auto& test_case) { return std::ranges::next(c.begin(), static_cast<D>(test_case.index)); };
+
+ auto test = [&](auto& test_case) {
+ Container c(test_case.initial.begin(), test_case.initial.end());
+ auto in = wrap_input_decay<Iter, Sent>(test_case.input);
+ auto pos = get_pos(c, test_case);
+
+ auto result = c.insert_range(pos, in);
+ assert(result == get_pos(c, test_case));
+ validate(c);
+ return std::ranges::equal(c, test_case.expected);
+ };
+
+ { // Empty container.
+ // empty_c.insert_range(end, empty_range)
+ assert(test(EmptyContainer_EmptyRange<T>));
+ // empty_c.insert_range(end, one_element_range)
+ assert(test(EmptyContainer_OneElementRange<T>));
+ // empty_c.insert_range(end, mid_range)
+ assert(test(EmptyContainer_MidRange<T>));
+ }
+
+ { // One-element container.
+ // one_element_c.insert_range(begin, empty_range)
+ assert(test(OneElementContainer_Begin_EmptyRange<T>));
+ // one_element_c.insert_range(end, empty_range)
+ assert(test(OneElementContainer_End_EmptyRange<T>));
+ // one_element_c.insert_range(begin, one_element_range)
+ assert(test(OneElementContainer_Begin_OneElementRange<T>));
+ // one_element_c.insert_range(end, one_element_range)
+ assert(test(OneElementContainer_End_OneElementRange<T>));
+ // one_element_c.insert_range(begin, mid_range)
+ assert(test(OneElementContainer_Begin_MidRange<T>));
+ // one_element_c.insert_range(end, mid_range)
+ assert(test(OneElementContainer_End_MidRange<T>));
+ }
+
+ { // Full container.
+ // full_container.insert_range(begin, empty_range)
+ assert(test(FullContainer_Begin_EmptyRange<T>));
+ // full_container.insert_range(mid, empty_range)
+ assert(test(FullContainer_Mid_EmptyRange<T>));
+ // full_container.insert_range(end, empty_range)
+ assert(test(FullContainer_End_EmptyRange<T>));
+ // full_container.insert_range(begin, one_element_range)
+ assert(test(FullContainer_Begin_OneElementRange<T>));
+ // full_container.insert_range(end, one_element_range)
+ assert(test(FullContainer_Mid_OneElementRange<T>));
+ // full_container.insert_range(end, one_element_range)
+ assert(test(FullContainer_End_OneElementRange<T>));
+ // full_container.insert_range(begin, mid_range)
+ assert(test(FullContainer_Begin_MidRange<T>));
+ // full_container.insert_range(mid, mid_range)
+ assert(test(FullContainer_Mid_MidRange<T>));
+ // full_container.insert_range(end, mid_range)
+ assert(test(FullContainer_End_MidRange<T>));
+ // full_container.insert_range(begin, long_range)
+ assert(test(FullContainer_Begin_LongRange<T>));
+ // full_container.insert_range(mid, long_range)
+ assert(test(FullContainer_Mid_LongRange<T>));
+ // full_container.insert_range(end, long_range)
+ assert(test(FullContainer_End_LongRange<T>));
+ }
+}
+
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_prepend_range(Validate validate) {
using T = typename Container::value_type;
@@ -507,6 +577,50 @@ constexpr void test_sequence_prepend_range(Validate validate) {
}
}
+// https://llvm.org/PR159943
+template <class Container, class Iter, class Sent, class Validate>
+constexpr void test_sequence_prepend_range_decay(Validate validate) {
+ using T = Container::value_type;
+
+ auto test = [&](auto& test_case) {
+ Container c(test_case.initial.begin(), test_case.initial.end());
+ auto in = wrap_input_decay<Iter, Sent>(test_case.input);
+
+ c.prepend_range(in);
+ validate(c);
+ return std::ranges::equal(c, test_case.expected);
+ };
+
+ { // Empty container.
+ // empty_c.prepend_range(empty_range)
+ assert(test(EmptyContainer_EmptyRange<T>));
+ // empty_c.prepend_range(one_element_range)
+ assert(test(EmptyContainer_OneElementRange<T>));
+ // empty_c.prepend_range(mid_range)
+ assert(test(EmptyContainer_MidRange<T>));
+ }
+
+ { // One-element container.
+ // one_element_c.prepend_range(empty_range)
+ assert(test(OneElementContainer_Begin_EmptyRange<T>));
+ // one_element_c.prepend_range(one_element_range)
+ assert(test(OneElementContainer_Begin_OneElementRange<T>));
+ // one_element_c.prepend_range(mid_range)
+ assert(test(OneElementContainer_Begin_MidRange<T>));
+ }
+
+ { // Full container.
+ // full_container.prepend_range(empty_range)
+ assert(test(FullContainer_Begin_EmptyRange<T>));
+ // full_container.prepend_range(one_element_range)
+ assert(test(FullContainer_Begin_OneElementRange<T>));
+ // full_container.prepend_range(mid_range)
+ assert(test(FullContainer_Begin_MidRange<T>));
+ // full_container.prepend_range(long_range)
+ assert(test(FullContainer_Begin_LongRange<T>));
+ }
+}
+
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_append_range(Validate validate) {
using T = typename Container::value_type;
@@ -550,6 +664,50 @@ constexpr void test_sequence_append_range(Validate validate) {
}
}
+// https://llvm.org/PR159943
+template <class Container, class Iter, class Sent, class Validate>
+constexpr void test_sequence_append_range_decay(Validate validate) {
+ using T = Container::value_type;
+
+ auto test = [&](auto& test_case) {
+ Container c(test_case.initial.begin(), test_case.initial.end());
+ auto in = wrap_input_decay<Iter, Sent>(test_case.input);
+
+ c.append_range(in);
+ validate(c);
+ return std::ranges::equal(c, test_case.expected);
+ };
+
+ { // Empty container.
+ // empty_c.append_range(empty_range)
+ assert(test(EmptyContainer_EmptyRange<T>));
+ // empty_c.append_range(one_element_range)
+ assert(test(EmptyContainer_OneElementRange<T>));
+ // empty_c.append_range(mid_range)
+ assert(test(EmptyContainer_MidRange<T>));
+ }
+
+ { // One-element container.
+ // one_element_c.append_range(empty_range)
+ assert(test(OneElementContainer_End_EmptyRange<T>));
+ // one_element_c.append_range(one_element_range)
+ assert(test(OneElementContainer_End_OneElementRange<T>));
+ // one_element_c.append_range(mid_range)
+ assert(test(OneElementContainer_End_MidRange<T>));
+ }
+
+ { // Full container.
+ // full_container.append_range(empty_range)
+ assert(test(FullContainer_End_EmptyRange<T>));
+ // full_container.append_range(one_element_range)
+ assert(test(FullContainer_End_OneElementRange<T>));
+ // full_container.append_range(mid_range)
+ assert(test(FullContainer_End_MidRange<T>));
+ // full_container.append_range(long_range)
+ assert(test(FullContainer_End_LongRange<T>));
+ }
+}
+
template <class Container, class Iter, class Sent, class Validate>
constexpr void test_sequence_assign_range(Validate validate) {
using T = typename Container::value_type;
@@ -605,6 +763,62 @@ constexpr void test_sequence_assign_range(Validate validate) {
}
}
+// https://llvm.org/PR159943
+template <class Container, class Iter, class Sent, class Validate>
+constexpr void test_sequence_assign_range_decay(Validate validate) {
+ using T = Container::value_type;
+
+ auto& initial_empty = EmptyContainer_EmptyRange<T>.initial;
+ auto& initial_one_element = OneElementContainer_Begin_EmptyRange<T>.initial;
+ auto& initial_full = FullContainer_Begin_EmptyRange<T>.initial;
+ auto& input_empty = FullContainer_Begin_EmptyRange<T>.input;
+ auto& input_one_element = FullContainer_Begin_OneElementRange<T>.input;
+ auto& input_mid_range = FullContainer_Begin_MidRange<T>.input;
+ auto& input_long_range = FullContainer_Begin_LongRange<T>.input;
+
+ auto test = [&](auto& initial, auto& input) {
+ Container c(initial.begin(), initial.end());
+ auto in = wrap_input_decay<Iter, Sent>(input);
+
+ c.assign_range(in);
+ validate(c);
+ return std::ranges::equal(c, input);
+ };
+
+ { // Empty container.
+ // empty_container.assign_range(empty_range)
+ assert(test(initial_empty, input_empty));
+ // empty_container.assign_range(one_element_range)
+ assert(test(initial_empty, input_one_element));
+ // empty_container.assign_range(mid_range)
+ assert(test(initial_empty, input_mid_range));
+ // empty_container.assign_range(long_range)
+ assert(test(initial_empty, input_long_range));
+ }
+
+ { // One-element container.
+ // one_element_container.assign_range(empty_range)
+ assert(test(initial_one_element, input_empty));
+ // one_element_container.assign_range(one_element_range)
+ assert(test(initial_one_element, input_one_element));
+ // one_element_container.assign_range(mid_range)
+ assert(test(initial_one_element, input_mid_range));
+ // one_element_container.assign_range(long_range)
+ assert(test(initial_one_element, input_long_range));
+ }
+
+ { // Full container.
+ // full_container.assign_range(empty_range)
+ assert(test(initial_full, input_empty));
+ // full_container.assign_range(one_element_range)
+ assert(test(initial_full, input_one_element));
+ // full_container.assign_range(mid_range)
+ assert(test(initial_full, input_mid_range));
+ // full_container.assign_range(long_range)
+ assert(test(initial_full, input_long_range));
+ }
+}
+
// Move-only types.
template <template <class...> class Container>
>From bf74931328b6f2625da532b07f0b42e071b30378 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Mon, 22 Sep 2025 15:31:48 +0800
Subject: [PATCH 2/3] Pass policy tags via template parameters/arguments
---
libcxx/include/deque | 21 ++++++++-------------
1 file changed, 8 insertions(+), 13 deletions(-)
diff --git a/libcxx/include/deque b/libcxx/include/deque
index ea83c50bceea0..da137964d6f8e 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -833,7 +833,7 @@ public:
_LIBCPP_HIDE_FROM_ABI iterator insert_range(const_iterator __position, _Range&& __range) {
if constexpr (ranges::bidirectional_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
- return __insert_bidirectional(__position, ranges::begin(__range), ranges::end(__range), __n);
+ return __insert_bidirectional<_RangeAlgPolicy>(__position, ranges::begin(__range), ranges::end(__range), __n);
} else if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) {
auto __n = static_cast<size_type>(ranges::distance(__range));
@@ -1203,10 +1203,10 @@ private:
template <class _Iterator>
_LIBCPP_HIDE_FROM_ABI iterator __insert_with_size(const_iterator __p, _Iterator __f, size_type __n);
- template <class _BiIter, class _Sentinel>
+ template <class _IterOpsPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI iterator
__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel __sent, size_type __n);
- template <class _BiIter>
+ template <class _IterOpsPolicy, class _BiIter>
_LIBCPP_HIDE_FROM_ABI iterator __insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n);
template <class _InpIter, __enable_if_t<__has_exactly_input_iterator_category<_InpIter>::value, int> = 0>
@@ -1903,26 +1903,21 @@ deque<_Tp, _Allocator>::__insert_with_size(const_iterator __p, _Iterator __f, si
template <class _Tp, class _Allocator>
template <class _BiIter, __enable_if_t<__has_bidirectional_iterator_category<_BiIter>::value, int> >
typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_iterator __p, _BiIter __f, _BiIter __l) {
- return __insert_bidirectional(__p, __f, __l, std::distance(__f, __l));
+ return __insert_bidirectional<_ClassicAlgPolicy>(__p, __f, __l, std::distance(__f, __l));
}
template <class _Tp, class _Allocator>
-template <class _BiIter, class _Sentinel>
+template <class _IterOpsPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel, size_type __n) {
- return __insert_bidirectional(__p, __f, std::next(__f, __n), __n);
+ return __insert_bidirectional<_IterOpsPolicy>(__p, __f, _IterOps<_IterOpsPolicy>::next(__f, __n), __n);
}
template <class _Tp, class _Allocator>
-template <class _BiIter>
+template <class _IterOpsPolicy, class _BiIter>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n) {
-# if _LIBCPP_STD_VER >= 20
- using _Ops = _IterOps<
- conditional_t<__has_bidirectional_iterator_category<_BiIter>::value, _ClassicAlgPolicy, _RangeAlgPolicy>>;
-# else
- using _Ops = _IterOps<_ClassicAlgPolicy>;
-# endif
+ using _Ops = _IterOps<_IterOpsPolicy>;
size_type __pos = __p - begin();
size_type __to_end = size() - __pos;
allocator_type& __a = __alloc();
>From 45a26008841562000633700e8f4cfd6cbb3f8df9 Mon Sep 17 00:00:00 2001
From: "A. Jiang" <de34 at live.cn>
Date: Tue, 23 Sep 2025 01:12:26 +0800
Subject: [PATCH 3/3] Change policy template parameter name; add issue
description
---
libcxx/include/deque | 12 ++++++------
libcxx/test/std/containers/from_range_helpers.h | 2 ++
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/libcxx/include/deque b/libcxx/include/deque
index da137964d6f8e..e7f58a43b78a0 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -1203,10 +1203,10 @@ private:
template <class _Iterator>
_LIBCPP_HIDE_FROM_ABI iterator __insert_with_size(const_iterator __p, _Iterator __f, size_type __n);
- template <class _IterOpsPolicy, class _BiIter, class _Sentinel>
+ template <class _AlgPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI iterator
__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel __sent, size_type __n);
- template <class _IterOpsPolicy, class _BiIter>
+ template <class _AlgPolicy, class _BiIter>
_LIBCPP_HIDE_FROM_ABI iterator __insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n);
template <class _InpIter, __enable_if_t<__has_exactly_input_iterator_category<_InpIter>::value, int> = 0>
@@ -1907,17 +1907,17 @@ typename deque<_Tp, _Allocator>::iterator deque<_Tp, _Allocator>::insert(const_i
}
template <class _Tp, class _Allocator>
-template <class _IterOpsPolicy, class _BiIter, class _Sentinel>
+template <class _AlgPolicy, class _BiIter, class _Sentinel>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _Sentinel, size_type __n) {
- return __insert_bidirectional<_IterOpsPolicy>(__p, __f, _IterOps<_IterOpsPolicy>::next(__f, __n), __n);
+ return __insert_bidirectional<_AlgPolicy>(__p, __f, _IterOps<_AlgPolicy>::next(__f, __n), __n);
}
template <class _Tp, class _Allocator>
-template <class _IterOpsPolicy, class _BiIter>
+template <class _AlgPolicy, class _BiIter>
_LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
deque<_Tp, _Allocator>::__insert_bidirectional(const_iterator __p, _BiIter __f, _BiIter __l, size_type __n) {
- using _Ops = _IterOps<_IterOpsPolicy>;
+ using _Ops = _IterOps<_AlgPolicy>;
size_type __pos = __p - begin();
size_type __to_end = size() - __pos;
allocator_type& __a = __alloc();
diff --git a/libcxx/test/std/containers/from_range_helpers.h b/libcxx/test/std/containers/from_range_helpers.h
index e1895a528efb2..1ef0d1ccde191 100644
--- a/libcxx/test/std/containers/from_range_helpers.h
+++ b/libcxx/test/std/containers/from_range_helpers.h
@@ -54,6 +54,8 @@ constexpr auto wrap_input(std::vector<T>& input) {
}
// https://llvm.org/PR159943
+// Verify container insertion/assignment from ranges whose iterators dereference to prvalues.
+// Especially, `std::prev` should be avoided when inserting such a `bidirectional_range`.
struct DecayCopy {
template <class T>
requires std::convertible_to<T, std::decay_t<T>>
More information about the libcxx-commits
mailing list