Skip to content

Conversation

@ldionne
Copy link
Member

@ldionne ldionne commented Dec 10, 2025

Allocators should be extremely cheap, if not free, to copy. Furthermore, we have requirements on allocator types that copies must compare equal, and that move and copy must be the same.

Hence, taking an allocator by reference should not provide benefits beyond making a copy of it. However, taking the allocator by reference leads to complexity in __split_buffer, which can be removed if we stop using that pattern.

Allocators should be extremely cheap, if not free, to copy. Furthermore,
we have requirements on allocator types that copies must compare equal,
and that move and copy must be the same.

Hence, taking an allocator by reference should not provide benefits
beyond making a copy of it. However, taking the allocator by reference
leads to complexity in __split_buffer, which can be removed if we stop
using that pattern.
@ldionne ldionne requested a review from a team as a code owner December 10, 2025 16:58
@llvmbot llvmbot added the libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi. label Dec 10, 2025
@llvmbot
Copy link
Member

llvmbot commented Dec 10, 2025

@llvm/pr-subscribers-libcxx

Author: Louis Dionne (ldionne)

Changes

Allocators should be extremely cheap, if not free, to copy. Furthermore, we have requirements on allocator types that copies must compare equal, and that move and copy must be the same.

Hence, taking an allocator by reference should not provide benefits beyond making a copy of it. However, taking the allocator by reference leads to complexity in __split_buffer, which can be removed if we stop using that pattern.


Patch is 21.79 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/171651.diff

3 Files Affected:

  • (modified) libcxx/include/__split_buffer (+20-25)
  • (modified) libcxx/include/__vector/vector.h (+17-17)
  • (modified) libcxx/include/deque (+8-8)
diff --git a/libcxx/include/__split_buffer b/libcxx/include/__split_buffer
index 1e05e4df8ba0f..d6176f8ca2749 100644
--- a/libcxx/include/__split_buffer
+++ b/libcxx/include/__split_buffer
@@ -33,7 +33,6 @@
 #include <__type_traits/is_swappable.h>
 #include <__type_traits/is_trivially_destructible.h>
 #include <__type_traits/is_trivially_relocatable.h>
-#include <__type_traits/remove_reference.h>
 #include <__utility/forward.h>
 #include <__utility/move.h>
 
@@ -54,8 +53,7 @@ class __split_buffer_pointer_layout {
 protected:
   using value_type                      = _Tp;
   using allocator_type                  = _Allocator;
-  using __alloc_rr _LIBCPP_NODEBUG      = __libcpp_remove_reference_t<allocator_type>;
-  using __alloc_traits _LIBCPP_NODEBUG  = allocator_traits<__alloc_rr>;
+  using __alloc_traits _LIBCPP_NODEBUG  = allocator_traits<allocator_type>;
   using reference                       = value_type&;
   using const_reference                 = const value_type&;
   using size_type                       = typename __alloc_traits::size_type;
@@ -159,9 +157,9 @@ public:
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { return *(__end_ - 1); }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
-      __split_buffer_pointer_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_pointer_layout>,
+      __split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>,
                                     value_type,
-                                    __alloc_rr&>& __other) _NOEXCEPT {
+                                    allocator_type>& __other) _NOEXCEPT {
     std::swap(__front_cap_, __other.__front_cap_);
     std::swap(__begin_, __other.__begin_);
     std::swap(__back_cap_, __other.__back_cap_);
@@ -207,8 +205,7 @@ class __split_buffer_size_layout {
 protected:
   using value_type                      = _Tp;
   using allocator_type                  = _Allocator;
-  using __alloc_rr _LIBCPP_NODEBUG      = __libcpp_remove_reference_t<allocator_type>;
-  using __alloc_traits _LIBCPP_NODEBUG  = allocator_traits<__alloc_rr>;
+  using __alloc_traits _LIBCPP_NODEBUG  = allocator_traits<allocator_type>;
   using reference                       = value_type&;
   using const_reference                 = const value_type&;
   using size_type                       = typename __alloc_traits::size_type;
@@ -316,9 +313,9 @@ public:
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_without_allocator(
-      __split_buffer_pointer_layout<__split_buffer<value_type, __alloc_rr&, __split_buffer_pointer_layout>,
+      __split_buffer_pointer_layout<__split_buffer<value_type, allocator_type, __split_buffer_pointer_layout>,
                                     value_type,
-                                    __alloc_rr&>& __other) _NOEXCEPT {
+                                    allocator_type>& __other) _NOEXCEPT {
     std::swap(__front_cap_, __other.__front_cap_);
     std::swap(__begin_, __other.__begin_);
     std::swap(__cap_, __other.__cap_);
@@ -386,8 +383,7 @@ private:
 //    protected:
 //      using value_type                     = _Tp;
 //      using allocator_type                 = _Allocator;
-//      using __alloc_rr                     = __libcpp_remove_reference_t<allocator_type>;
-//      using __alloc_traits                 = allocator_traits<__alloc_rr>;
+//      using __alloc_traits                 = allocator_traits<allocator_type>;
 //      using reference                      = value_type&;
 //      using const_reference                = const value_type&;
 //      using size_type                      = typename __alloc_traits::size_type;
@@ -462,7 +458,6 @@ public:
   using __base_type::__set_sentinel;
   using __base_type::__set_valid_range;
 
-  using typename __base_type::__alloc_rr;
   using typename __base_type::__alloc_traits;
   using typename __base_type::allocator_type;
   using typename __base_type::const_iterator;
@@ -489,18 +484,18 @@ public:
 
   _LIBCPP_HIDE_FROM_ABI __split_buffer() = default;
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(__alloc_rr& __a) : __base_type(__a) {}
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(allocator_type& __a) : __base_type(__a) {}
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const __alloc_rr& __a)
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI explicit __split_buffer(const allocator_type& __a)
       : __base_type(__a) {}
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI
-  __split_buffer(size_type __cap, size_type __start, __alloc_rr& __a);
+  __split_buffer(size_type __cap, size_type __start, allocator_type& __a);
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c)
       _NOEXCEPT_(is_nothrow_move_constructible<allocator_type>::value);
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const __alloc_rr& __a);
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer(__split_buffer&& __c, const allocator_type& __a);
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI __split_buffer& operator=(__split_buffer&& __c)
       _NOEXCEPT_((__alloc_traits::propagate_on_container_move_assignment::value &&
@@ -560,7 +555,7 @@ public:
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __destruct_at_end(pointer __new_last, true_type) _NOEXCEPT;
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void swap(__split_buffer& __x)
-      _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>);
+      _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>);
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI bool __invariants() const {
     if (__front_cap() == nullptr) {
@@ -589,7 +584,7 @@ public:
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
-  __swap_without_allocator(__split_buffer<value_type, __alloc_rr&, _Layout>& __other) _NOEXCEPT {
+  __swap_without_allocator(__split_buffer<value_type, allocator_type, _Layout>& __other) _NOEXCEPT {
     __base_type::__swap_without_allocator(__other);
   }
 
@@ -653,7 +648,7 @@ template <class _Tp, class _Allocator, template <class, class, class> class _Lay
 template <class _Iterator, class _Sentinel>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
 __split_buffer<_Tp, _Allocator, _Layout>::__construct_at_end_with_sentinel(_Iterator __first, _Sentinel __last) {
-  __alloc_rr& __a = __get_allocator();
+  allocator_type& __a = __get_allocator();
   for (; __first != __last; ++__first) {
     if (__back_spare() == 0) {
       size_type __old_cap = capacity();
@@ -718,7 +713,7 @@ __split_buffer<_Tp, _Allocator, _Layout>::__destruct_at_end(pointer __new_last,
 
 template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
-__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, __alloc_rr& __a)
+__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(size_type __cap, size_type __start, allocator_type& __a)
     : __base_type(__a) {
   _LIBCPP_ASSERT_INTERNAL(__cap >= __start, "can't have a start point outside the capacity");
   if (__cap > 0) {
@@ -748,7 +743,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 __split_buffer<_Tp, _Allocator, _Layout>::__split_
 
 template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
 _LIBCPP_CONSTEXPR_SINCE_CXX20
-__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const __alloc_rr& __a)
+__split_buffer<_Tp, _Allocator, _Layout>::__split_buffer(__split_buffer&& __c, const allocator_type& __a)
     : __base_type(__a) {
   if (__a == __c.__get_allocator()) {
     __set_data(__c.__front_cap());
@@ -781,7 +776,7 @@ __split_buffer<_Tp, _Allocator, _Layout>::operator=(__split_buffer&& __c)
 
 template <class _Tp, class _Allocator, template <class, class, class> class _Layout>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::swap(__split_buffer& __x)
-    _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<__alloc_rr>) {
+    _NOEXCEPT_(!__alloc_traits::propagate_on_container_swap::value || __is_nothrow_swappable_v<allocator_type>) {
   __base_type::swap(__x);
 }
 
@@ -791,7 +786,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::shr
 #if _LIBCPP_HAS_EXCEPTIONS
     try {
 #endif // _LIBCPP_HAS_EXCEPTIONS
-      __split_buffer<value_type, __alloc_rr&, _Layout> __t(size(), 0, __get_allocator());
+      __split_buffer<value_type, allocator_type, _Layout> __t(size(), 0, __get_allocator());
       if (__t.capacity() < capacity()) {
         __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(end()));
         __t.__set_sentinel(size());
@@ -818,7 +813,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emp
       __set_valid_range(std::move_backward(begin(), __end, __new_end), __new_end);
     } else {
       size_type __c = std::max<size_type>(2 * capacity(), 1);
-      __split_buffer<value_type, __alloc_rr&, _Layout> __t(__c, (__c + 3) / 4, __get_allocator());
+      __split_buffer<value_type, allocator_type, _Layout> __t(__c, (__c + 3) / 4, __get_allocator());
       __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end));
       __base_type::__swap_without_allocator(__t);
     }
@@ -840,7 +835,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void __split_buffer<_Tp, _Allocator, _Layout>::emp
       __set_valid_range(begin() - __d, __end);
     } else {
       size_type __c = std::max<size_type>(2 * capacity(), 1);
-      __split_buffer<value_type, __alloc_rr&, _Layout> __t(__c, __c / 4, __get_allocator());
+      __split_buffer<value_type, allocator_type, _Layout> __t(__c, __c / 4, __get_allocator());
       __t.__construct_at_end(move_iterator<pointer>(begin()), move_iterator<pointer>(__end));
       __base_type::__swap_without_allocator(__t);
     }
diff --git a/libcxx/include/__vector/vector.h b/libcxx/include/__vector/vector.h
index 4961a5fcb2067..93358d863492e 100644
--- a/libcxx/include/__vector/vector.h
+++ b/libcxx/include/__vector/vector.h
@@ -687,9 +687,9 @@ class vector {
   }
 
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
-  __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v);
+  __swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI pointer
-  __swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p);
+  __swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void
   __move_range(pointer __from_s, pointer __from_e, pointer __to);
   _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __move_assign(vector& __c, true_type)
@@ -810,7 +810,7 @@ class vector {
     return __p;
   }
 
-  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type&>& __sb) {
+  _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI void __swap_layouts(__split_buffer<_Tp, allocator_type>& __sb) {
     auto __vector_begin    = __begin_;
     auto __vector_sentinel = __end_;
     auto __vector_cap      = __cap_;
@@ -855,7 +855,7 @@ vector(from_range_t, _Range&&, _Alloc = _Alloc()) -> vector<ranges::range_value_
 // function has a strong exception guarantee.
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 void
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v) {
+vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v) {
   __annotate_delete();
   auto __new_begin = __v.begin() - size();
   std::__uninitialized_allocator_relocate(
@@ -874,7 +874,7 @@ vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, a
 // function has a strong exception guarantee if __begin_ == __p || __end_ == __p.
 template <class _Tp, class _Allocator>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
-vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type&>& __v, pointer __p) {
+vector<_Tp, _Allocator>::__swap_out_circular_buffer(__split_buffer<value_type, allocator_type>& __v, pointer __p) {
   __annotate_delete();
   pointer __ret = __v.begin();
 
@@ -1074,7 +1074,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::reserve(size_type __
   if (__n > capacity()) {
     if (__n > max_size())
       this->__throw_length_error();
-    __split_buffer<value_type, allocator_type&> __v(__n, size(), this->__alloc_);
+    __split_buffer<value_type, allocator_type> __v(__n, size(), this->__alloc_);
     __swap_out_circular_buffer(__v);
   }
 }
@@ -1085,7 +1085,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::shrink_to_fit() _NOE
 #if _LIBCPP_HAS_EXCEPTIONS
     try {
 #endif // _LIBCPP_HAS_EXCEPTIONS
-      __split_buffer<value_type, allocator_type&> __v(size(), size(), this->__alloc_);
+      __split_buffer<value_type, allocator_type> __v(size(), size(), this->__alloc_);
       // 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.
@@ -1102,7 +1102,7 @@ template <class _Tp, class _Allocator>
 template <class... _Args>
 _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::pointer
 vector<_Tp, _Allocator>::__emplace_back_slow_path(_Args&&... __args) {
-  __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), size(), this->__alloc_);
+  __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), size(), this->__alloc_);
   //    __v.emplace_back(std::forward<_Args>(__args)...);
   pointer __end = __v.end();
   __alloc_traits::construct(this->__alloc_, std::__to_address(__end), std::forward<_Args>(__args)...);
@@ -1205,7 +1205,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, const_reference __x)
       *__p = *__xr;
     }
   } else {
-    __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+    __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
     __v.emplace_back(__x);
     __p = __swap_out_circular_buffer(__v, __p);
   }
@@ -1224,7 +1224,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, value_type&& __x) {
       *__p = std::move(__x);
     }
   } else {
-    __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+    __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
     __v.emplace_back(std::move(__x));
     __p = __swap_out_circular_buffer(__v, __p);
   }
@@ -1245,7 +1245,7 @@ vector<_Tp, _Allocator>::emplace(const_iterator __position, _Args&&... __args) {
       *__p = std::move(__tmp.get());
     }
   } else {
-    __split_buffer<value_type, allocator_type&> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
+    __split_buffer<value_type, allocator_type> __v(__recommend(size() + 1), __p - this->__begin_, this->__alloc_);
     __v.emplace_back(std::forward<_Args>(__args)...);
     __p = __swap_out_circular_buffer(__v, __p);
   }
@@ -1273,7 +1273,7 @@ vector<_Tp, _Allocator>::insert(const_iterator __position, size_type __n, const_
         std::fill_n(__p, __n, *__xr);
       }
     } else {
-      __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
+      __split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
       __v.__construct_at_end(__n, __x);
       __p = __swap_out_circular_buffer(__v, __p);
     }
@@ -1294,11 +1294,11 @@ vector<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __position, _Inpu
   if (__first == __last)
     (void)std::rotate(__p, __old_last, this->__end_);
   else {
-    __split_buffer<value_type, allocator_type&> __v(__alloc_);
+    __split_buffer<value_type, allocator_type> __v(__alloc_);
     auto __guard = std::__make_exception_guard(
         _AllocatorDestroyRangeReverse<allocator_type, pointer>(__alloc_, __old_last, this->__end_));
     __v.__construct_at_end_with_sentinel(std::move(__first), std::move(__last));
-    __split_buffer<value_type, allocator_type&> __merged(
+    __split_buffer<value_type, allocator_type> __merged(
         __recommend(size() + __v.size()), __off, __alloc_); // has `__off` positions available at the front
     std::__uninitialized_allocator_relocate(
         __alloc_, std::__to_address(__old_last), std::__to_address(this->__end_), std::__to_address(__merged.end()));
@@ -1344,7 +1344,7 @@ vector<_Tp, _Allocator>::__insert_with_size(
         __insert_assign_n_unchecked<_AlgPolicy>(std::move(__first), __n, __p);
       }
     } else {
-      __split_buffer<value_type, allocator_type&> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
+      __split_buffer<value_type, allocator_type> __v(__recommend(size() + __n), __p - this->__begin_, this->__alloc_);
       __v.__construct_at_end_with_size(std::move(__first), __n);
       __p = __swap_out_circular_buffer(__v, __p);
     }
@@ -1359,7 +1359,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
     if (__new_size <= capacity()) {
       __construct_at_end(__new_size - __current_size);
     } else {
-      __split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
+      __split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_);
       __v.__construct_at_end(__new_size - __current_size);
       __swap_out_circular_buffer(__v);
     }
@@ -1375,7 +1375,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::resize(size_type __n
     if (__new_size <= capacity())
       __construct_at_end(__new_size - __current_size, __x);
     else {
-      __split_buffer<value_type, allocator_type&> __v(__recommend(__new_size), __current_size, __alloc_);
+      __split_buffer<value_type, allocator_type> __v(__recommend(__new_size), __current_size, __alloc_);
       __v.__construct_at_end(__new_size - __current_size, __x);
       __swap_out_circular_buffer(__v);
     }
diff --git a/libcxx/include/deque b/libcxx/include/deque
index ad2d759e1fcac..befe27bb4282d 100644
--- a/libcxx/include/deque
+++ b/libcxx/include/deque
@@ -1785,9 +1785,9 @@ template <class _Tp, class _Allocator>
 template <class _Iterator, class _Sentinel>
 _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
 deque<_Tp, _Allocator>::__insert_with_sentinel(const_iterator __p, _Iterator __f, _Sentinel __l) {
-  __split_buffer<value_type, allocator_type&> __buf(__alloc());
+  __split_buffer<value_type, allocator_type> __buf(__alloc());
   __buf.__construct_at_end_with_sentinel(std::move(__f), std::move(__l));
-  typedef typename __split_buffer<value_type, allocator_type&>::iterator __bi;
+  typedef typename __split_buffer<value_type, allocator_type>::iterator __bi;
   return insert(__p, move_iterator<__bi>(__buf.begin()), move_iterator<__bi>(__buf.end()));
 }
 
@@ -1802,9 +1802,9 @@ template <class _Tp, class _Allocator>
 template <class _Iterator>
 _LIBCPP_HIDE_FROM_ABI typename deque<_Tp, _Allocator>::iterator
 deque<_Tp, _Allocator>::__insert_with_size(const_iterator __p, _Iterator __f, size_type __n) {
-  __split_buffer<value_type, allocator_type&> __buf(__n, 0, __alloc());
+  __split_buffer<value_type, allocator_type> __buf(__n, 0, __alloc());
   __buf.__construct_at_end_with_size(__f, __n);
-  typedef typename __split_buffer<value_type, allocator_type&>::iterator __fwd;
+  typedef typename __split_buffer<value_type, allocator_type>::iterator __fwd;
   return insert(__p, move_iterator<__fwd>(__buf.begin()), move_iterator<__fwd>(__buf.end()));
 }
 
@@ -1982,7 +1982,7 @@ void deque<_Tp, _Allocator>::__add_front_capacity() {
  ...
[truncated]

@ldionne
Copy link
Member Author

ldionne commented Dec 10, 2025

@junov-google Are you able to verify whether this indeed fixes your issue with Swift interop?

@ldionne
Copy link
Member Author

ldionne commented Dec 10, 2025

@junov-google Are you able to verify whether this indeed fixes your issue with Swift interop?

Actually, I was able to reproduce your issue myself and I can confirm it solves it! Note that I had to remove -explicit-module-build from the build flags in your repro in swiftlang/swift#85820 to make anything work, I'm not sure why. But after I remove that, I can reproduce the same issue you saw and this patch does fix it.

@junov-google
Copy link

@junov-google Are you able to verify whether this indeed fixes your issue with Swift interop?

Confirmed. I applied the change on top of my WIP tests for swift/C++ interop in the Chromium project, and I can confirm that this PR fixes the issue. This probably also unblocks apple-llvm's next update.

@ldionne
Copy link
Member Author

ldionne commented Dec 10, 2025

Just for awareness, this is the test I am checking in downstream:

commit 678dff31fc3aa4cca8af265a0205b6392027480d
Author: Louis Dionne <[email protected]>
Date:   Wed Dec 10 14:26:41 2025 -0500

    [libc++] Add reproducer for swiftlang/swift#85820

diff --git a/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/foo.h b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/foo.h
new file mode 100644
index 000000000000..58a15627ea18
--- /dev/null
+++ b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/foo.h
@@ -0,0 +1,11 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include <vector>
+
+inline std::vector<int> GetOneTwoThree() { return {1, 2, 3}; }
diff --git a/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/main.swift b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/main.swift
new file mode 100644
index 000000000000..b88674cf2c1b
--- /dev/null
+++ b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/main.swift
@@ -0,0 +1,14 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+import Foo
+
+public func testingOneTwoThree() {
+  let v = GetOneTwoThree()
+  print(v.size())
+}
diff --git a/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/module.modulemap b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/module.modulemap
new file mode 100644
index 000000000000..57c5884f0437
--- /dev/null
+++ b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/module.modulemap
@@ -0,0 +1,4 @@
+module Foo {
+  header "foo.h"
+  export *
+}
diff --git a/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/repro.sh.cpp b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/repro.sh.cpp
new file mode 100644
index 000000000000..109655663fd6
--- /dev/null
+++ b/libcxx/test/libcxx/vendor/apple/swift-interop/swiftlang-85820/repro.sh.cpp
@@ -0,0 +1,15 @@
+//===----------------------------------------------------------------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+// This test requires access to the Swift compiler, which we assume is only available on Apple platforms for now.
+// REQUIRES: buildhost=darwin
+
+// Reproducer for https://github.com/swiftlang/swift/issues/85820
+//
+// RUN: swiftc -cxx-interoperability-mode=default -Xcc -nostdinc++ -Xcc -isystem -Xcc "%{include-dir}" \
+// RUN:     -Xcc -fmodule-map-file=%S/module.modulemap -Xcc -std=c++20 %S/main.swift

I'm not upstreaming that because we don't currently have a policy for officially supporting any interop with other languages, so for now I am building up a downstream suite to track these issues.

@cjdb
Copy link
Contributor

cjdb commented Dec 11, 2025

This is going to create a fair amount of churn for #155330. Could you please tag me in vector PRs until #155330 lands (or comment that it will affect #155330), so that I'm able to integrate the changes into both #155330 and the local patch that we're forced to carry while #155330 remains open?

@philnik777 philnik777 merged commit 2c1decb into llvm:main Dec 11, 2025
77 of 81 checks passed
@ldionne ldionne deleted the review/no-reference-split-buffer branch December 11, 2025 13:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

libc++ libc++ C++ Standard Library. Not GNU libstdc++. Not libc++abi.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants