[libcxx-commits] [libcxx] aab67db - [libc++] Fix shared_ptr rebinding allocators to incomplete types (#206145)

via libcxx-commits libcxx-commits at lists.llvm.org
Fri Jun 26 23:12:24 PDT 2026


Author: Nikolas Klauser
Date: 2026-06-27T08:12:19+02:00
New Revision: aab67db385c2f4b7ac93adf616a52dbd943cfae5

URL: https://github.com/llvm/llvm-project/commit/aab67db385c2f4b7ac93adf616a52dbd943cfae5
DIFF: https://github.com/llvm/llvm-project/commit/aab67db385c2f4b7ac93adf616a52dbd943cfae5.diff

LOG: [libc++] Fix shared_ptr rebinding allocators to incomplete types (#206145)

https://github.com/llvm/llvm-project/pull/200401 caused various ways to
create a `shared_ptr` control block to reject any allocators which
required a complete type. This patch allows allocators to again require
a complete type.

Added: 
    

Modified: 
    libcxx/include/__memory/shared_ptr.h
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
    libcxx/test/support/min_allocator.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/__memory/shared_ptr.h b/libcxx/include/__memory/shared_ptr.h
index 76a52c35bdf12..750d253912ab1 100644
--- a/libcxx/include/__memory/shared_ptr.h
+++ b/libcxx/include/__memory/shared_ptr.h
@@ -90,9 +90,7 @@ class weak_ptr;
 
 template <class _Tp, class _Dp, class _Alloc>
 class _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_pointer final : public __shared_weak_count {
-  using __alloc_t _LIBCPP_NODEBUG = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>;
-
-  _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
   _LIBCPP_NO_UNIQUE_ADDRESS _Dp __deleter_;
   _LIBCPP_NO_UNIQUE_ADDRESS _Tp __ptr_;
 
@@ -114,8 +112,10 @@ class _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_pointer final : public __shared_
   }
 
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
+    using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_pointer>;
+
     __alloc_t __a(__alloc_);
-    __alloc_.~__alloc_t();
+    __alloc_.~_Alloc();
     __a.deallocate(pointer_traits<typename allocator_traits<__alloc_t>::pointer>::pointer_to(*this), 1);
   }
 };
@@ -127,51 +127,52 @@ struct __for_overwrite_tag {};
 
 template <class _Tp, class _Alloc>
 struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace : __shared_weak_count {
-  using __alloc_t _LIBCPP_NODEBUG      = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace>;
-  using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<__alloc_t>;
+  using __alloc_traits _LIBCPP_NODEBUG = allocator_traits<_Alloc>;
   using __value_type _LIBCPP_NODEBUG   = __remove_cv_t<_Tp>;
 
   template <class... _Args>
   _LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace(_Alloc __a, _Args&&... __args) : __alloc_(std::move(__a)) {
-    __alloc_traits::construct(__alloc_, __get_elem(), std::forward<_Args>(__args)...);
+    allocator_traits<_Alloc>::construct(__alloc_, __get_elem(), std::forward<_Args>(__args)...);
   }
 
   _LIBCPP_HIDE_FROM_ABI __value_type* __get_elem() _NOEXCEPT { return reinterpret_cast<__value_type*>(__buffer_); }
 
 private:
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override {
-    __alloc_traits::destroy(__alloc_, __get_elem());
+    allocator_traits<_Alloc>::destroy(__alloc_, __get_elem());
   }
 
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
+    using __alloc_t = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace>;
     __alloc_t __tmp(__alloc_);
-    __alloc_.~__alloc_t();
-    __alloc_traits::deallocate(__tmp, pointer_traits<typename __alloc_traits::pointer>::pointer_to(*this), 1);
+    __alloc_.~_Alloc();
+    allocator_traits<__alloc_t>::deallocate(
+        __tmp, pointer_traits<typename allocator_traits<__alloc_t>::pointer>::pointer_to(*this), 1);
   }
 
-  _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
   _ALIGNAS_TYPE(__value_type) char __buffer_[sizeof(__value_type)];
 };
 
 template <class _Tp, class _Alloc>
 struct _LIBCPP_HIDE_STRUCT_FROM_ABI __shared_ptr_emplace_for_overwrite : __shared_weak_count {
-  using __alloc_t _LIBCPP_NODEBUG    = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace_for_overwrite>;
   using __value_type _LIBCPP_NODEBUG = __remove_cv_t<_Tp>;
 
   _LIBCPP_HIDE_FROM_ABI explicit __shared_ptr_emplace_for_overwrite(_Alloc __a) : __alloc_(std::move(__a)) {}
 
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared() _NOEXCEPT override { __value_.~__value_type(); }
   _LIBCPP_HIDE_FROM_ABI_VIRTUAL void __on_zero_shared_weak() _NOEXCEPT override {
-    __alloc_t __tmp(__alloc_);
-    __alloc_.~__alloc_t();
+    using __alloc_t      = __allocator_traits_rebind_t<_Alloc, __shared_ptr_emplace_for_overwrite>;
     using __alloc_traits = allocator_traits<__alloc_t>;
+    __alloc_t __tmp(__alloc_);
+    __alloc_.~_Alloc();
     __alloc_traits::deallocate(__tmp, pointer_traits<typename __alloc_traits::pointer>::pointer_to(*this), 1);
   }
 
   _LIBCPP_HIDE_FROM_ABI __value_type* __get_elem() _NOEXCEPT { return std::addressof(__value_); }
 
 private:
-  _LIBCPP_NO_UNIQUE_ADDRESS __alloc_t __alloc_;
+  _LIBCPP_NO_UNIQUE_ADDRESS _Alloc __alloc_;
   _LIBCPP_NO_UNIQUE_ADDRESS __value_type __value_;
 };
 

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
index 074ef44a1f76b..787a108a000e1 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp
@@ -165,5 +165,9 @@ int main(int, char**)
                                              test_allocator<derived[4]> >::value, "");
     }
 
+    { // Make sure that the allocator isn't instantiated with an incomplete type
+        std::shared_ptr<int> ptr(new int, std::default_delete<int>(), complete_type_allocator<int>());
+    }
+
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
index 341a442c90a16..2fb89f8e22be8 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp
@@ -126,6 +126,7 @@ int main(int, char**)
 {
     test<bare_allocator<void> >();
     test<test_allocator<void> >();
+    test<complete_type_allocator<int> >();
 
     test_allocator_statistics alloc_stats;
     {

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
index e6e063304453a..63cfd8c5ae1a5 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_for_overwrite.pass.cpp
@@ -206,6 +206,12 @@ void test() {
   testTypeWithDefaultCtor();
   testAllocatorOperationsCalled();
   testNotValueInitialized();
+
+  { // Make sure that the allocator isn't instantiated with an incomplete type
+    (void)std::allocate_shared_for_overwrite<int>(complete_type_allocator<int>{});
+    (void)std::allocate_shared_for_overwrite<int[]>(complete_type_allocator<int>{}, 1);
+    (void)std::allocate_shared_for_overwrite<int[1]>(complete_type_allocator<int>{});
+  }
 }
 
 int main(int, char**) {

diff  --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h
index 16775649f55cf..6beffc1d2eb10 100644
--- a/libcxx/test/support/min_allocator.h
+++ b/libcxx/test/support/min_allocator.h
@@ -410,7 +410,7 @@ class complete_type_allocator {
   TEST_CONSTEXPR_CXX20 complete_type_allocator() TEST_NOEXCEPT {}
 
   template <class U>
-  TEST_CONSTEXPR_CXX20 explicit complete_type_allocator(complete_type_allocator<U>) TEST_NOEXCEPT {}
+  TEST_CONSTEXPR_CXX20 complete_type_allocator(complete_type_allocator<U>) TEST_NOEXCEPT {}
 
   TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return static_cast<T*>(std::allocator<T>().allocate(n)); }
 


        


More information about the libcxx-commits mailing list