[PATCH] libstdc++: Fix-self element self-assigments when insertint an empty range [PR121313]
Patrick Palka
ppalka@redhat.com
Thu Aug 14 14:30:14 GMT 2025
On Thu, 14 Aug 2025, Tomasz Kamiński wrote:
Typo in subject line, "inserting"
> For __n == 0, the elements where self move-assigned by
> std::move_backward(__ins, __old_finish - __n, __old_finish).
s/where/were?
LGTM besides that.
>
> 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.
> ---
> Testing on x86_64-linux. Newly added test passed.
>
> OK for trunk and v15.
>
> libstdc++-v3/include/bits/vector.tcc | 10 ++--
> .../vector/modifiers/insert/insert_range.cc | 50 +++++++++++++++++++
> 2 files changed, 57 insertions(+), 3 deletions(-)
>
> diff --git a/libstdc++-v3/include/bits/vector.tcc b/libstdc++-v3/include/bits/vector.tcc
> index 70ead1d7083..1543ce9cd77 100644
> --- a/libstdc++-v3/include/bits/vector.tcc
> +++ b/libstdc++-v3/include/bits/vector.tcc
> @@ -1007,17 +1007,21 @@ _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)
> {
> // Number of existing elements after insertion point:
> 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 506bebbe519..e4b5982188f 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() );
> }
> --
> 2.49.0
>
>
More information about the Libstdc++
mailing list