Skip to content

Commit 24a2fe9

Browse files
committed
OPTIONAL: Remove the requirement of replaceability
This is an optional relaxation in case we are OK with changing the behavior for some users that had questionable assignment operators.
1 parent 2cd2f53 commit 24a2fe9

File tree

4 files changed

+2
-86
lines changed

4 files changed

+2
-86
lines changed

libcxx/include/__vector/vector.h

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -502,12 +502,7 @@ class _LIBCPP_TEMPLATE_VIS vector {
502502
// Otherwise, we have no choice but to shift everything to the right using move-assignments
503503
// and to move-assign the new element into its final location, to ensure that everything gets
504504
// properly destroyed in case of an exception.
505-
//
506-
// Note that we also require __is_replaceable here for backwards compatibility, because we used
507-
// to perform move-assignments unconditionally. If we didn't enforce that, we would no longer call
508-
// the assignment operator of types that have a funky operator= and expect it to be called in
509-
// vector::insert.
510-
if constexpr (__is_replaceable<value_type>::value && is_nothrow_constructible<value_type>::value) {
505+
if constexpr (is_nothrow_constructible<value_type>::value) {
511506
// Relocate all the elements in the vector to open up a gap.
512507
std::__uninitialized_allocator_relocate(this->__alloc_, __position, end(), __position + 1);
513508

@@ -601,12 +596,7 @@ class _LIBCPP_TEMPLATE_VIS vector {
601596
// If the value_type is nothrow move constructible, we destroy the range being erased and we
602597
// relocate the tail of the vector into the created gap. This is especially efficient if the
603598
// elements are trivially relocatable. Otherwise, we use the standard technique with move-assignments.
604-
//
605-
// Note that we also require __is_replaceable here for backwards compatibility, because we used
606-
// to perform move-assignments unconditionally. If we didn't enforce that, we would no longer call
607-
// the assignment operator of types that have a funky operator= and expect it to be called in
608-
// vector::erase.
609-
if constexpr (__is_replaceable<value_type>::value && is_nothrow_move_constructible<value_type>::value) {
599+
if constexpr (is_nothrow_move_constructible<value_type>::value) {
610600
std::__allocator_destroy(this->__alloc_, __first, __last);
611601
std::__uninitialized_allocator_relocate(this->__alloc_, __last, end(), __first);
612602
} else {

libcxx/test/std/containers/sequences/vector/vector.modifiers/common.h

Lines changed: 0 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -40,28 +40,6 @@ struct Throws {
4040
bool Throws::sThrows = false;
4141
#endif
4242

43-
struct Tracker {
44-
int copy_assignments = 0;
45-
int move_assignments = 0;
46-
};
47-
48-
struct TrackedAssignment {
49-
Tracker* tracker_;
50-
TEST_CONSTEXPR_CXX14 explicit TrackedAssignment(Tracker* tracker) : tracker_(tracker) {}
51-
52-
TrackedAssignment(TrackedAssignment const&) = default;
53-
TrackedAssignment(TrackedAssignment&&) = default;
54-
55-
TEST_CONSTEXPR_CXX14 TrackedAssignment& operator=(TrackedAssignment const&) {
56-
tracker_->copy_assignments++;
57-
return *this;
58-
}
59-
TEST_CONSTEXPR_CXX14 TrackedAssignment& operator=(TrackedAssignment&&) {
60-
tracker_->move_assignments++;
61-
return *this;
62-
}
63-
};
64-
6543
struct NonTriviallyRelocatable {
6644
int value_;
6745
TEST_CONSTEXPR NonTriviallyRelocatable() : value_(0) {}

libcxx/test/std/containers/sequences/vector/vector.modifiers/erase_iter.pass.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -107,31 +107,5 @@ int main(int, char**) {
107107
}
108108
#endif
109109

110-
// Make sure we satisfy the complexity requirement in terms of the number of times the assignment
111-
// operator is called.
112-
//
113-
// There is currently ambiguity as to whether this is truly mandated by the Standard, so we only
114-
// test it for libc++.
115-
#ifdef _LIBCPP_VERSION
116-
{
117-
Tracker tracker;
118-
std::vector<TrackedAssignment> v;
119-
120-
// Set up the vector with 5 elements.
121-
for (int i = 0; i != 5; ++i) {
122-
v.emplace_back(&tracker);
123-
}
124-
assert(tracker.copy_assignments == 0);
125-
assert(tracker.move_assignments == 0);
126-
127-
// Erase element [1] from it. Elements [2] [3] [4] should be shifted, so we should
128-
// see 3 move assignments (and nothing else).
129-
v.erase(v.begin() + 1);
130-
assert(v.size() == 4);
131-
assert(tracker.copy_assignments == 0);
132-
assert(tracker.move_assignments == 3);
133-
}
134-
#endif
135-
136110
return 0;
137111
}

libcxx/test/std/containers/sequences/vector/vector.modifiers/erase_iter_iter.pass.cpp

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -196,31 +196,5 @@ int main(int, char**) {
196196
assert(it == v.begin() + 2);
197197
}
198198

199-
// Make sure we satisfy the complexity requirement in terms of the number of times the assignment
200-
// operator is called.
201-
//
202-
// There is currently ambiguity as to whether this is truly mandated by the Standard, so we only
203-
// test it for libc++.
204-
#ifdef _LIBCPP_VERSION
205-
{
206-
Tracker tracker;
207-
std::vector<TrackedAssignment> v;
208-
209-
// Set up the vector with 5 elements.
210-
for (int i = 0; i != 5; ++i) {
211-
v.emplace_back(&tracker);
212-
}
213-
assert(tracker.copy_assignments == 0);
214-
assert(tracker.move_assignments == 0);
215-
216-
// Erase elements [1] and [2] from it. Elements [3] [4] should be shifted, so we should
217-
// see 2 move assignments (and nothing else).
218-
v.erase(v.begin() + 1, v.begin() + 3);
219-
assert(v.size() == 3);
220-
assert(tracker.copy_assignments == 0);
221-
assert(tracker.move_assignments == 2);
222-
}
223-
#endif
224-
225199
return 0;
226200
}

0 commit comments

Comments
 (0)