diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h index ef796a8ed0a9e..9155fb52a69b1 100644 --- a/libcxx/include/__vector/vector.h +++ b/libcxx/include/__vector/vector.h @@ -58,6 +58,7 @@ #include <__type_traits/is_same.h> #include <__type_traits/is_trivially_relocatable.h> #include <__type_traits/type_identity.h> +#include <__utility/declval.h> #include <__utility/exception_guard.h> #include <__utility/forward.h> #include <__utility/is_pointer_in_range.h> @@ -602,6 +603,30 @@ class _LIBCPP_TEMPLATE_VIS vector { _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __assign_with_size(_Iterator __first, _Sentinel __last, difference_type __n); + template ())&&, value_type&&>::value, int> = 0> + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) { + for (pointer __end_position = __position + __n; __position != __end_position; ++__position, (void)++__first) { + __temp_value __tmp(this->__alloc_, *__first); + *__position = std::move(__tmp.get()); + } + } + + template ())&&, value_type&&>::value, int> = 0> + _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void + __insert_assign_n_unchecked(_Iterator __first, difference_type __n, pointer __position) { +#if _LIBCPP_STD_VER >= 23 + if constexpr (!forward_iterator<_Iterator>) { // Handles input-only sized ranges for insert_range + ranges::copy_n(std::move(__first), __n, __position); + } else +#endif + { + std::copy_n(__first, __n, __position); + } + } + template _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI iterator __insert_with_sentinel(const_iterator __position, _InputIterator __first, _Sentinel __last); @@ -1322,19 +1347,12 @@ vector<_Tp, _Allocator>::__insert_with_size( __construct_at_end(__m, __last, __n - __dx); if (__dx > 0) { __move_range(__p, __old_last, __p + __n); - std::copy(__first, __m, __p); + __insert_assign_n_unchecked(__first, __dx, __p); } } } else { __move_range(__p, __old_last, __p + __n); -#if _LIBCPP_STD_VER >= 23 - if constexpr (!forward_iterator<_Iterator>) { - ranges::copy_n(std::move(__first), __n, __p); - } else -#endif - { - std::copy_n(__first, __n, __p); - } + __insert_assign_n_unchecked(std::move(__first), __n, __p); } } else { __split_buffer __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_); diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp index e4625e4865c4d..f5c2ebf7531bf 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_iter_iter_iter.pass.cpp @@ -11,6 +11,8 @@ // template // iterator insert(const_iterator position, Iter first, Iter last); +// XFAIL: FROZEN-CXX03-HEADERS-FIXME + #include #include #include @@ -161,6 +163,24 @@ TEST_CONSTEXPR_CXX20 bool tests() { for (; j < 105; ++j) assert(v[j] == 0); } + { // Ensure that iterator-pair insert() doesn't use unexpected assignment. + struct Wrapper { + TEST_CONSTEXPR Wrapper(int n) : n_(n) {} + + int n_; + + private: + void operator=(int); + }; + + int a[] = {1, 2, 3, 4, 5}; + const std::size_t count = sizeof(a) / sizeof(a[0]); + std::vector v; + v.insert(v.end(), a, a + count); + assert(v.size() == count); + for (std::size_t i = 0; i != count; ++i) + assert(v[i].n_ == a[i]); + } #if TEST_STD_VER >= 11 { typedef std::vector > V; diff --git a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp index ea0573df73751..ef63db083a998 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.modifiers/insert_range.pass.cpp @@ -64,6 +64,22 @@ constexpr bool test() { } } + { // Ensure that insert_range doesn't use unexpected assignment. + struct Wrapper { + constexpr Wrapper(int n) : n_(n) {} + void operator=(int) = delete; + + int n_; + }; + + int a[]{1, 2, 3, 4, 5}; + std::vector v; + v.insert_range(v.end(), a); + assert(v.size() == std::size(a)); + for (std::size_t i = 0; i != std::size(a); ++i) + assert(v[i].n_ == a[i]); + } + return true; }