aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTomasz Kamiński <tkaminsk@redhat.com>2025-08-14 15:20:36 +0200
committerTomasz Kamiński <tkaminsk@redhat.com>2025-08-18 10:32:01 +0200
commitcc54f2f47e63c9d404a44f618cf114ae63e81b40 (patch)
tree592192764f6ea9410faab77d7bcf61f8d86d865b
parent534276f1e5889f2ce5b5238e68b395a92a79761b (diff)
downloadgcc-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.tcc9
-rw-r--r--libstdc++-v3/testsuite/23_containers/vector/modifiers/insert/insert_range.cc50
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() );
}