Skip to content

Commit 962aa26

Browse files
authored
[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`.
1 parent 7e14161 commit 962aa26

File tree

3 files changed

+27
-4
lines changed

3 files changed

+27
-4
lines changed

libcxx/include/map

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -911,8 +911,7 @@ public:
911911
private:
912912
typedef std::__value_type<key_type, mapped_type> __value_type;
913913
typedef __map_value_compare<key_type, value_type, key_compare> __vc;
914-
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
915-
typedef __tree<__value_type, __vc, __allocator_type> __base;
914+
typedef __tree<__value_type, __vc, allocator_type> __base;
916915
typedef typename __base::__node_traits __node_traits;
917916
typedef allocator_traits<allocator_type> __alloc_traits;
918917

@@ -1596,8 +1595,7 @@ public:
15961595
private:
15971596
typedef std::__value_type<key_type, mapped_type> __value_type;
15981597
typedef __map_value_compare<key_type, value_type, key_compare> __vc;
1599-
typedef __rebind_alloc<allocator_traits<allocator_type>, __value_type> __allocator_type;
1600-
typedef __tree<__value_type, __vc, __allocator_type> __base;
1598+
typedef __tree<__value_type, __vc, allocator_type> __base;
16011599
typedef typename __base::__node_traits __node_traits;
16021600
typedef allocator_traits<allocator_type> __alloc_traits;
16031601

libcxx/test/std/containers/associative/map/incomplete_type.pass.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313

1414
#include <map>
1515

16+
#include "min_allocator.h"
1617
#include "test_macros.h"
1718

1819
struct A {
@@ -28,5 +29,8 @@ inline bool operator<(A const& L, A const& R) { return L.data < R.data; }
2829
int main(int, char**) {
2930
A a;
3031

32+
// Make sure that the allocator isn't rebound to and incomplete type
33+
std::map<int, int, std::less<int>, complete_type_allocator<std::pair<const int, int> > > m;
34+
3135
return 0;
3236
}

libcxx/test/support/min_allocator.h

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -402,6 +402,27 @@ class min_allocator
402402
TEST_CONSTEXPR_CXX20 friend bool operator!=(min_allocator x, min_allocator y) {return !(x == y);}
403403
};
404404

405+
template <class T>
406+
class complete_type_allocator {
407+
public:
408+
using value_type = T;
409+
410+
// Make sure that value_type is a complete when min_allocator is instantiated
411+
static_assert(TEST_ALIGNOF(value_type) != 0, "");
412+
413+
TEST_CONSTEXPR_CXX20 complete_type_allocator() TEST_NOEXCEPT {}
414+
415+
template <class U>
416+
TEST_CONSTEXPR_CXX20 explicit complete_type_allocator(complete_type_allocator<U>) TEST_NOEXCEPT {}
417+
418+
TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return static_cast<T*>(std::allocator<T>().allocate(n)); }
419+
420+
TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>().deallocate(p, n); }
421+
422+
TEST_CONSTEXPR_CXX20 friend bool operator==(complete_type_allocator, complete_type_allocator) { return true; }
423+
TEST_CONSTEXPR_CXX20 friend bool operator!=(complete_type_allocator, complete_type_allocator) { return false; }
424+
};
425+
405426
template <class T>
406427
class explicit_allocator
407428
{

0 commit comments

Comments
 (0)