diff options
author | Tomasz Kamiński <tkaminsk@redhat.com> | 2025-08-14 15:20:36 +0200 |
---|---|---|
committer | Tomasz Kamiński <tkaminsk@redhat.com> | 2025-08-18 10:32:01 +0200 |
commit | cc54f2f47e63c9d404a44f618cf114ae63e81b40 (patch) | |
tree | 592192764f6ea9410faab77d7bcf61f8d86d865b | |
parent | 534276f1e5889f2ce5b5238e68b395a92a79761b (diff) | |
download | gcc-cc54f2f47e63c9d404a44f618cf114ae63e81b40.zip gcc-cc54f2f47e63c9d404a44f618cf114ae63e81b40.tar.gz gcc-cc54f2f47e63c9d404a44f618cf114ae63e81b40.tar.bz2 |
libstdc++: Fix-self element self-assigments when inserting an empty range [PR121313]
For __n == 0, the elements were self move-assigned by
std::move_backward(__ins, __old_finish - __n, __old_finish).
PR libstdc++/121313
libstdc++-v3/ChangeLog:
* include/bits/vector.tcc (vector::insert_range): Add check for
empty size.
* testsuite/23_containers/vector/modifiers/insert/insert_range.cc:
New tests.
-rw-r--r-- | libstdc++-v3/include/bits/vector.tcc | 9 | ||||
-rw-r--r-- | libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc | 50 |
2 files changed, 56 insertions, 3 deletions
diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc index 70ead1d..dd3d3c6 100644 --- a/libstdc++-v3/include/bits/vector.tcc +++ b/libstdc++-v3/include/bits/vector.tcc @@ -1007,15 +1007,18 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER if constexpr (ranges::forward_range<_Rg>) { + const auto __ins_idx = __pos - cbegin(); + // Number of new elements to insert: + const auto __n = size_type(ranges::distance(__rg)); + if (__n == 0) + return begin() + __ins_idx; + // Start of existing elements: pointer __old_start = this->_M_impl._M_start; // End of existing elements: pointer __old_finish = this->_M_impl._M_finish; // Insertion point: - const auto __ins_idx = __pos - cbegin(); pointer __ins = __old_start + __ins_idx; - // Number of new elements to insert: - const auto __n = size_type(ranges::distance(__rg)); // Number of elements that can fit in unused capacity: const auto __cap = this->_M_impl._M_end_of_storage - __old_finish; if (__cap >= __n) diff --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 index 506bebb..e4b5982 100644 --- a/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc +++ b/libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc @@ -99,8 +99,58 @@ test_ranges() return true; } +struct SelfAssignChecker { + static int moveCounter; + static int copyCounter; + + SelfAssignChecker() = default; + constexpr SelfAssignChecker(int v) : val(v) { } + SelfAssignChecker(const SelfAssignChecker&) = default; + SelfAssignChecker(SelfAssignChecker&&) = default; + + SelfAssignChecker operator=(const SelfAssignChecker& rhs) + { + if (this == &rhs) + ++copyCounter; + this->val = rhs.val; + return *this; + } + + SelfAssignChecker operator=(SelfAssignChecker&& rhs) + { + if (this == &rhs) + ++moveCounter; + this->val = rhs.val; + return *this; + } + + int val; + + friend bool operator==(SelfAssignChecker, SelfAssignChecker) = default; +}; + +int SelfAssignChecker::moveCounter = 0; +int SelfAssignChecker::copyCounter = 0; + +void +test_pr121313() +{ + using namespace __gnu_test; + + SelfAssignChecker::copyCounter = SelfAssignChecker::moveCounter = 0; + do_test<test_forward_range<int>, std::allocator<SelfAssignChecker>>(); + VERIFY( SelfAssignChecker::moveCounter == 0 ); + VERIFY( SelfAssignChecker::copyCounter == 0 ); + + SelfAssignChecker::copyCounter = SelfAssignChecker::moveCounter = 0; + do_test<test_input_range<int>, std::allocator<SelfAssignChecker>>(); + VERIFY( SelfAssignChecker::moveCounter == 0 ); + VERIFY( SelfAssignChecker::copyCounter == 0 ); +} + int main() { test_ranges(); + test_pr121313(); static_assert( test_ranges() ); } |