diff --git a/libcxx/include/vector b/libcxx/include/vector index aaf51d18fe30fb..45980043a3c157 100644 --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -1443,7 +1443,11 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE #endif // _LIBCPP_HAS_NO_EXCEPTIONS allocator_type& __a = this->__alloc(); __split_buffer __v(size(), size(), __a); - __swap_out_circular_buffer(__v); + // The Standard mandates shrink_to_fit() does not increase the capacity. + // With equal capacity keep the existing buffer. This avoids extra work + // due to swapping the elements. + if (__v.capacity() < capacity()) + __swap_out_circular_buffer(__v); #ifndef _LIBCPP_HAS_NO_EXCEPTIONS } catch (...) { } diff --git a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp index 8851e2a9ed0c7c..e39afb2d48f0a0 100644 --- a/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp +++ b/libcxx/test/std/containers/sequences/vector/vector.capacity/shrink_to_fit.pass.cpp @@ -71,11 +71,56 @@ TEST_CONSTEXPR_CXX20 bool tests() { return true; } +#if TEST_STD_VER >= 23 +template +struct increasing_allocator { + using value_type = T; + std::size_t min_elements = 1000; + increasing_allocator() = default; + + template + constexpr increasing_allocator(const increasing_allocator& other) noexcept : min_elements(other.min_elements) {} + + constexpr std::allocation_result allocate_at_least(std::size_t n) { + if (n < min_elements) + n = min_elements; + min_elements += 1000; + return std::allocator{}.allocate_at_least(n); + } + constexpr T* allocate(std::size_t n) { return allocate_at_least(n).ptr; } + constexpr void deallocate(T* p, std::size_t n) noexcept { std::allocator{}.deallocate(p, n); } +}; + +template +bool operator==(increasing_allocator, increasing_allocator) { + return true; +} + +// https://github.com/llvm/llvm-project/issues/95161 +constexpr bool test_increasing_allocator() { + std::vector> v; + v.push_back(1); + assert(is_contiguous_container_asan_correct(v)); + std::size_t capacity = v.capacity(); + v.shrink_to_fit(); + assert(v.capacity() <= capacity); + assert(v.size() == 1); + assert(is_contiguous_container_asan_correct(v)); + + return true; +} +#endif // TEST_STD_VER >= 23 + int main(int, char**) { - tests(); + tests(); #if TEST_STD_VER > 17 static_assert(tests()); #endif +#if TEST_STD_VER >= 23 + test_increasing_allocator(); + static_assert(test_increasing_allocator()); +#endif + return 0; }