[libcxx-commits] [libcxx] 962aa26 - [libc++] Don't instantiate allocators in __tree on an incomplete type (#140225)

via libcxx-commits libcxx-commits at lists.llvm.org
Sun May 18 03:38:10 PDT 2025


Author: Nikolas Klauser
Date: 2025-05-18T12:38:06+02:00
New Revision: 962aa2666fe8aa99e25bb255a99d3ab02d8441b4

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

LOG: [libc++] Don't instantiate allocators in __tree on an incomplete type (#140225)

This causes a mismatch between `value_type` and
`allocator_type::value_type` in `__tree`, but I think that's acceptable.
`__tree` primarily gets a `__value_type` wrapper due to potential ABI
breaks and unwraps it to the same as `allocator_type::value_type` in the
end. A cleanup patch will also change `__tree::value_type` to be the
same as `allocator_type::value_type`, making the type mismatch only
visible where `__tree` is instantiated in `map`.

Added: 
    

Modified: 
    libcxx/include/map
    libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp
    libcxx/test/support/min_allocator.h

Removed: 
    


################################################################################
diff  --git a/libcxx/include/map b/libcxx/include/map
index 039ed86dc756f..24eadbd154220 100644
--- a/libcxx/include/map
+++ b/libcxx/include/map
@@ -911,8 +911,7 @@ public:
 private:
   typedef std::__value_type<key_type, mapped_type> __value_type;
   typedef __map_value_compare<key_type, value_type, key_compare> __vc;
-  typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
-  typedef __tree<__value_type, __vc, __allocator_type> __base;
+  typedef __tree<__value_type, __vc, allocator_type> __base;
   typedef typename __base::__node_traits __node_traits;
   typedef allocator_traits<allocator_type> __alloc_traits;
 
@@ -1596,8 +1595,7 @@ public:
 private:
   typedef std::__value_type<key_type, mapped_type> __value_type;
   typedef __map_value_compare<key_type, value_type, key_compare> __vc;
-  typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
-  typedef __tree<__value_type, __vc, __allocator_type> __base;
+  typedef __tree<__value_type, __vc, allocator_type> __base;
   typedef typename __base::__node_traits __node_traits;
   typedef allocator_traits<allocator_type> __alloc_traits;
 

diff  --git a/libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp b/libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp
index 99fc612698094..6f9e38cf35f5c 100644
--- a/libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp
@@ -13,6 +13,7 @@
 
 #include <map>
 
+#include "min_allocator.h"
 #include "test_macros.h"
 
 struct A {
@@ -28,5 +29,8 @@ inline bool operator<(A const& L, A const& R) { return L.data < R.data; }
 int main(int, char**) {
   A a;
 
+  // Make sure that the allocator isn't rebound to and incomplete type
+  std::map<int, int, std::less<int>, complete_type_allocator<std::pair<const int, int> > > m;
+
   return 0;
 }

diff  --git a/libcxx/test/support/min_allocator.h b/libcxx/test/support/min_allocator.h
index 24505bbb508d6..3b7d12af24ce0 100644
--- a/libcxx/test/support/min_allocator.h
+++ b/libcxx/test/support/min_allocator.h
@@ -402,6 +402,27 @@ class min_allocator
     TEST_CONSTEXPR_CXX20 friend bool operator!=(min_allocator x, min_allocator y) {return !(x == y);}
 };
 
+template <class T>
+class complete_type_allocator {
+public:
+  using value_type = T;
+
+  // Make sure that value_type is a complete when min_allocator is instantiated
+  static_assert(TEST_ALIGNOF(value_type) != 0, "");
+
+  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 T* allocate(std::size_t n) { return static_cast<T*>(std::allocator<T>().allocate(n)); }
+
+  TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>().deallocate(p, n); }
+
+  TEST_CONSTEXPR_CXX20 friend bool operator==(complete_type_allocator, complete_type_allocator) { return true; }
+  TEST_CONSTEXPR_CXX20 friend bool operator!=(complete_type_allocator, complete_type_allocator) { return false; }
+};
+
 template <class T>
 class explicit_allocator
 {


        


More information about the libcxx-commits mailing list