[libcxx-commits] [libcxx] 9a140a1 - [libc++] Make test_allocator constexpr-friendly for constexpr string/vector

Mark de Wever via libcxx-commits libcxx-commits at lists.llvm.org
Sun Nov 7 07:15:55 PST 2021


Author: Nikolas Klauser
Date: 2021-11-07T16:15:28+01:00
New Revision: 9a140a1586cc4d13ecc97a28065f9ed2f93c99de

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

LOG: [libc++] Make test_allocator constexpr-friendly for constexpr string/vector

Make test_allocator etc. constexpr-friendly so they can be used to test constexpr string and possibly constexpr vector

Reviewed By: Quuxplusone, #libc, ldionne

Differential Revision: https://reviews.llvm.org/D110994

Added: 
    

Modified: 
    libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp
    libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp
    libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
    libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
    libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
    libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
    libcxx/test/std/re/re.results/re.results.const/move.pass.cpp
    libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp
    libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp
    libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp
    libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp
    libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp
    libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp
    libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp
    libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp
    libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp
    libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp
    libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp
    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.const/pointer_deleter_allocator_throw.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.mod/reset_pointer_deleter_allocator.pass.cpp
    libcxx/test/support/test_allocator.h

Removed: 
    


################################################################################
diff  --git a/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp
index 824b362dca17e..a22d41e9760b9 100644
--- a/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/associative/map/map.cons/assign_initializer_list.pass.cpp
@@ -74,17 +74,18 @@ void test_basic() {
 
 
 void duplicate_keys_test() {
+  test_allocator_statistics alloc_stats;
   typedef std::map<int, int, std::less<int>, test_allocator<std::pair<const int, int> > > Map;
   {
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
-    Map s = {{1, 0}, {2, 0}, {3, 0}};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 3);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
+    Map s({{1, 0}, {2, 0}, {3, 0}}, std::less<int>(), test_allocator<std::pair<const int, int> >(&alloc_stats));
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 3);
     s = {{4, 0}, {4, 0}, {4, 0}, {4, 0}};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 1);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 1);
     assert(s.size() == 1);
     assert(s.begin()->first == 4);
   }
-  LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
+  LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
 }
 
 int main(int, char**)

diff  --git a/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp b/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp
index b04d7f576bac0..b096995513a94 100644
--- a/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp
+++ b/libcxx/test/std/containers/associative/set/set.cons/assign_initializer_list.pass.cpp
@@ -55,17 +55,18 @@ void basic_test() {
 }
 
 void duplicate_keys_test() {
+  test_allocator_statistics alloc_stats;
   typedef std::set<int, std::less<int>, test_allocator<int> > Set;
   {
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
-    Set s = {1, 2, 3};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 3);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
+    Set s({1, 2, 3}, std::less<int>(), test_allocator<int>(&alloc_stats));
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 3);
     s = {4, 4, 4, 4, 4};
-    LIBCPP_ASSERT(test_alloc_base::alloc_count == 1);
+    LIBCPP_ASSERT(alloc_stats.alloc_count == 1);
     assert(s.size() == 1);
     assert(*s.begin() == 4);
   }
-  LIBCPP_ASSERT(test_alloc_base::alloc_count == 0);
+  LIBCPP_ASSERT(alloc_stats.alloc_count == 0);
 }
 
 int main(int, char**) {

diff  --git a/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp b/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp
index 0cc573e8592d9..cc8949e751dd0 100644
--- a/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp
+++ b/libcxx/test/std/containers/container.requirements/container.requirements.general/allocator_move.pass.cpp
@@ -27,27 +27,28 @@
 
 template <class C>
 void test(int expected_num_allocs = 1) {
+  test_allocator_statistics alloc_stats;
   {
-    test_alloc_base::clear();
+    alloc_stats.clear();
     using AllocT = typename C::allocator_type;
-    C v(AllocT(42, 101));
+    C v(AllocT(42, 101, &alloc_stats));
 
-    assert(test_alloc_base::count == expected_num_allocs);
+    assert(alloc_stats.count == expected_num_allocs);
 
-    const int num_stored_allocs = test_alloc_base::count;
+    const int num_stored_allocs = alloc_stats.count;
     {
       const AllocT& a = v.get_allocator();
-      assert(test_alloc_base::count == 1 + num_stored_allocs);
+      assert(alloc_stats.count == 1 + num_stored_allocs);
       assert(a.get_data() == 42);
       assert(a.get_id() == 101);
     }
-    assert(test_alloc_base::count == num_stored_allocs);
-    test_alloc_base::clear_ctor_counters();
+    assert(alloc_stats.count == num_stored_allocs);
+    alloc_stats.clear_ctor_counters();
 
     C v2 = std::move(v);
-    assert(test_alloc_base::count == num_stored_allocs * 2);
-    assert(test_alloc_base::copied == 0);
-    assert(test_alloc_base::moved == num_stored_allocs);
+    assert(alloc_stats.count == num_stored_allocs * 2);
+    assert(alloc_stats.copied == 0);
+    assert(alloc_stats.moved == num_stored_allocs);
     {
       const AllocT& a = v.get_allocator();
       assert(a.get_id() == test_alloc_base::moved_value);

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
index b24fd0753770b..137129368b4ad 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_back_exception_safety.pass.cpp
@@ -86,11 +86,12 @@ int main(int, char**)
     }
 
     {
+    test_allocator_statistics alloc_stats;
     typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
-    C vec;
-    C vec2(vec);
+    C vec((test_allocator<CMyClass>(&alloc_stats)));
+    C vec2(vec, test_allocator<CMyClass>(&alloc_stats));
 
-    C::allocator_type::throw_after = 1;
+    alloc_stats.throw_after = 1;
     try {
         vec.push_back(instance);
         assert(false);

diff  --git a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
index 990f41f487266..79f9a14f23091 100644
--- a/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
+++ b/libcxx/test/std/containers/sequences/deque/deque.modifiers/push_front_exception_safety.pass.cpp
@@ -86,11 +86,12 @@ int main(int, char**)
     }
 
     {
+    test_allocator_statistics alloc_stats;
     typedef std::deque<CMyClass, test_allocator<CMyClass> > C;
-    C vec;
-    C vec2(vec);
+    C vec((test_allocator<CMyClass>(&alloc_stats)));
+    C vec2(vec, test_allocator<CMyClass>(&alloc_stats));
 
-    C::allocator_type::throw_after = 1;
+    alloc_stats.throw_after = 1;
     try {
         vec.push_front(instance);
         assert(false);

diff  --git a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
index 8da56e6aa2efa..a554ec8ab0162 100644
--- a/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector.bool/move.pass.cpp
@@ -20,9 +20,10 @@
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-        std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5));
-        std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5));
+        std::vector<bool, test_allocator<bool> > l(test_allocator<bool>(5, &alloc_stats));
+        std::vector<bool, test_allocator<bool> > lo(test_allocator<bool>(5, &alloc_stats));
         for (int i = 1; i <= 3; ++i)
         {
             l.push_back(true);
@@ -60,24 +61,24 @@ int main(int, char**)
         assert(l2.get_allocator() == lo.get_allocator());
     }
     {
-      test_alloc_base::clear();
+      alloc_stats.clear();
       using Vect = std::vector<bool, test_allocator<bool> >;
       using AllocT = Vect::allocator_type;
-      Vect v(test_allocator<bool>(42, 101));
-      assert(test_alloc_base::count == 1);
+      Vect v(test_allocator<bool>(42, 101, &alloc_stats));
+      assert(alloc_stats.count == 1);
       {
         const AllocT& a = v.get_allocator();
-        assert(test_alloc_base::count == 2);
+        assert(alloc_stats.count == 2);
         assert(a.get_data() == 42);
         assert(a.get_id() == 101);
       }
-      assert(test_alloc_base::count == 1);
-      test_alloc_base::clear_ctor_counters();
+      assert(alloc_stats.count == 1);
+      alloc_stats.clear_ctor_counters();
 
       Vect v2 = std::move(v);
-      assert(test_alloc_base::count == 2);
-      assert(test_alloc_base::copied == 0);
-      assert(test_alloc_base::moved == 1);
+      assert(alloc_stats.count == 2);
+      assert(alloc_stats.copied == 0);
+      assert(alloc_stats.moved == 1);
       {
         const AllocT& a = v.get_allocator();
         assert(a.get_id() == test_alloc_base::moved_value);

diff  --git a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
index 1c2126477ba05..8c797d1a7cbe0 100644
--- a/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
+++ b/libcxx/test/std/containers/sequences/vector/vector.cons/move.pass.cpp
@@ -23,9 +23,10 @@
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-        std::vector<MoveOnly, test_allocator<MoveOnly> > l(test_allocator<MoveOnly>(5));
-        std::vector<MoveOnly, test_allocator<MoveOnly> > lo(test_allocator<MoveOnly>(5));
+        std::vector<MoveOnly, test_allocator<MoveOnly> > l(test_allocator<MoveOnly>(5, &alloc_stats));
+        std::vector<MoveOnly, test_allocator<MoveOnly> > lo(test_allocator<MoveOnly>(5, &alloc_stats));
         assert(is_contiguous_container_asan_correct(l));
         assert(is_contiguous_container_asan_correct(lo));
         for (int i = 1; i <= 3; ++i)
@@ -100,24 +101,24 @@ int main(int, char**)
         assert(is_contiguous_container_asan_correct(c2));
     }
     {
-      test_alloc_base::clear();
+      alloc_stats.clear();
       using Vect = std::vector<int, test_allocator<int> >;
-      Vect v(test_allocator<int>(42, 101));
-      assert(test_alloc_base::count == 1);
-      assert(test_alloc_base::copied == 1);
-      assert(test_alloc_base::moved == 0);
+      Vect v(test_allocator<int>(42, 101, &alloc_stats));
+      assert(alloc_stats.count == 1);
+      assert(alloc_stats.copied == 1);
+      assert(alloc_stats.moved == 0);
       {
         const test_allocator<int>& a = v.get_allocator();
         assert(a.get_data() == 42);
         assert(a.get_id() == 101);
       }
-      assert(test_alloc_base::count == 1);
-      test_alloc_base::clear_ctor_counters();
+      assert(alloc_stats.count == 1);
+      alloc_stats.clear_ctor_counters();
 
       Vect v2 = std::move(v);
-      assert(test_alloc_base::count == 2);
-      assert(test_alloc_base::copied == 0);
-      assert(test_alloc_base::moved == 1);
+      assert(alloc_stats.count == 2);
+      assert(alloc_stats.copied == 0);
+      assert(alloc_stats.moved == 1);
       {
         const test_allocator<int>& a = v.get_allocator();
         assert(a.get_id() == test_alloc_base::moved_value);

diff  --git a/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp b/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp
index 82f2b3e655310..0806edef1429b 100644
--- a/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp
+++ b/libcxx/test/std/re/re.results/re.results.const/move.pass.cpp
@@ -37,16 +37,17 @@ test(const Allocator& a)
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     test<char>   (std::allocator<std::sub_match<const char *> >());
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
     test<wchar_t>(std::allocator<std::sub_match<const wchar_t *> >());
 #endif
 
-    test<char>   (test_allocator<std::sub_match<const char*> >(3));
-    assert(test_alloc_base::moved == 1);
+    test<char>   (test_allocator<std::sub_match<const char*> >(3, &alloc_stats));
+    assert(alloc_stats.moved == 1);
 #ifndef TEST_HAS_NO_WIDE_CHARACTERS
-    test<wchar_t>(test_allocator<std::sub_match<const wchar_t*> >(3));
-    assert(test_alloc_base::moved == 2);
+    test<wchar_t>(test_allocator<std::sub_match<const wchar_t*> >(3, &alloc_stats));
+    assert(alloc_stats.moved == 2);
 #endif
 
   return 0;

diff  --git a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp
index 02187c5193af9..c401384a23dc6 100644
--- a/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.capacity/capacity.pass.cpp
@@ -18,11 +18,13 @@
 
 #include "test_macros.h"
 
+test_allocator_statistics alloc_stats;
+
 template <class S>
 void
 test(S s)
 {
-    S::allocator_type::throw_after = 0;
+    alloc_stats.throw_after = 0;
 #ifndef TEST_HAS_NO_EXCEPTIONS
     try
 #endif
@@ -37,14 +39,14 @@ test(S s)
         assert(false);
     }
 #endif
-    S::allocator_type::throw_after = INT_MAX;
+    alloc_stats.throw_after = INT_MAX;
 }
 
 int main(int, char**)
 {
     {
     typedef std::basic_string<char, std::char_traits<char>, test_allocator<char> > S;
-    S s;
+    S s((test_allocator<char>(&alloc_stats)));
     test(s);
     s.assign(10, 'a');
     s.erase(5);

diff  --git a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp
index 00af31d0c18c0..d38e7c4116841 100644
--- a/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp
+++ b/libcxx/test/std/strings/basic.string/string.cons/move_alloc.pass.cpp
@@ -19,7 +19,6 @@
 #include "test_allocator.h"
 #include "min_allocator.h"
 
-
 template <class S>
 void
 test(S s0, const typename S::allocator_type& a)
@@ -33,9 +32,9 @@ test(S s0, const typename S::allocator_type& a)
     assert(s2.get_allocator() == a);
 }
 
-
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
     typedef test_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;
@@ -44,12 +43,12 @@ int main(int, char**)
 #elif TEST_STD_VER >= 11
     static_assert((noexcept(S()) == std::is_nothrow_move_constructible<A>::value), "" );
 #endif
-    test(S(), A(3));
-    test(S("1"), A(5));
-    test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A(7));
+    test(S(), A(3, &alloc_stats));
+    test(S("1"), A(5, &alloc_stats));
+    test(S("1234567890123456789012345678901234567890123456789012345678901234567890"), A(7, &alloc_stats));
     }
 
-    int alloc_count = test_alloc_base::alloc_count;
+    int alloc_count = alloc_stats.alloc_count;
     {
     typedef test_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;
@@ -58,10 +57,10 @@ int main(int, char**)
 #elif TEST_STD_VER >= 11
     static_assert((noexcept(S()) == std::is_nothrow_move_constructible<A>::value), "" );
 #endif
-    S s1 ( "Twas brillig, and the slivy toves did gyre and gymbal in the wabe" );
-    S s2 (std::move(s1), A(1));
+    S s1 ( "Twas brillig, and the slivy toves did gyre and gymbal in the wabe", A(&alloc_stats));
+    S s2 (std::move(s1), A(1, &alloc_stats));
     }
-    assert ( test_alloc_base::alloc_count == alloc_count );
+    assert ( alloc_stats.alloc_count == alloc_count );
     {
     typedef min_allocator<char> A;
     typedef std::basic_string<char, std::char_traits<char>, A> S;

diff  --git a/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp
index 150a277fe0aea..cbb2c2e7e25fe 100644
--- a/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/alloc_ctor.pass.cpp
@@ -25,31 +25,32 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p(std::allocator_arg, test_allocator<int>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p(std::allocator_arg, test_allocator<int>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<int&> p(std::allocator_arg, test_allocator<int>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p(std::allocator_arg, test_allocator<void>(42));
-        assert(test_alloc_base::alloc_count == 1);
+        std::promise<void> p(std::allocator_arg, test_allocator<void>(42, &alloc_stats));
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     // Test with a minimal allocator
     {
         std::promise<int> p(std::allocator_arg, bare_allocator<void>());

diff  --git a/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp
index f3978e79f47e1..ac504efbd6027 100644
--- a/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/move_assign.pass.cpp
@@ -23,15 +23,16 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -44,17 +45,17 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int&> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int&> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int&> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -67,17 +68,17 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p0(std::allocator_arg, test_allocator<void>());
-        std::promise<void> p(std::allocator_arg, test_allocator<void>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<void> p0(std::allocator_arg, test_allocator<void>(&alloc_stats));
+        std::promise<void> p(std::allocator_arg, test_allocator<void>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p = std::move(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -90,9 +91,9 @@ int main(int, char**)
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
 #endif
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp
index 1fdd61cc3bbee..9775e6655835c 100644
--- a/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/move_ctor.pass.cpp
@@ -23,13 +23,14 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -41,16 +42,16 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int&> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int&> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int&> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int&> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -62,16 +63,16 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<void> p0(std::allocator_arg, test_allocator<void>());
+        std::promise<void> p0(std::allocator_arg, test_allocator<void>(&alloc_stats));
         std::promise<void> p(std::move(p0));
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<void> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
 #ifndef TEST_HAS_NO_EXCEPTIONS
         try
@@ -83,10 +84,10 @@ int main(int, char**)
         {
             assert(e.code() == make_error_code(std::future_errc::no_state));
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
 #endif
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp b/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp
index bdb4595d62ab4..fbf77b121d474 100644
--- a/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.promise/swap.pass.cpp
@@ -25,63 +25,64 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         p.swap(p0);
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
-        std::promise<int> p(std::allocator_arg, test_allocator<int>());
-        assert(test_alloc_base::alloc_count == 2);
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        std::promise<int> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+        assert(alloc_stats.alloc_count == 2);
         swap(p, p0);
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 2);
+        assert(alloc_stats.alloc_count == 2);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p;
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         p.swap(p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
-        std::promise<int> p0(std::allocator_arg, test_allocator<int>());
+        std::promise<int> p0(std::allocator_arg, test_allocator<int>(&alloc_stats));
         std::promise<int> p;
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         swap(p, p0);
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         std::future<int> f = p.get_future();
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
         f = p0.get_future();
         assert(f.valid());
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp b/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp
index 3d72b983d6b05..027073fde8cc3 100644
--- a/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.shared_future/dtor.pass.cpp
@@ -24,49 +24,50 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int& T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<int>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef void T;
         std::shared_future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp
index 2255a4549534a..788afbdffdfe3 100644
--- a/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.task/futures.task.members/ctor_func_alloc.pass.cpp
@@ -47,10 +47,11 @@ int func(int i) { return i; }
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
         std::packaged_task<double(int, char)> p(std::allocator_arg,
-                                                test_allocator<A>(), A(5));
-        assert(test_alloc_base::alloc_count > 0);
+                                                test_allocator<A>(&alloc_stats), A(5));
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<double> f = p.get_future();
         p(3, 'a');
@@ -58,14 +59,14 @@ int main(int, char**)
         assert(A::n_copies == 0);
         assert(A::n_moves > 0);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
         std::packaged_task<double(int, char)> p(std::allocator_arg,
-                                                test_allocator<A>(), a);
-        assert(test_alloc_base::alloc_count > 0);
+                                                test_allocator<A>(&alloc_stats), a);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<double> f = p.get_future();
         p(3, 'a');
@@ -73,31 +74,31 @@ int main(int, char**)
         assert(A::n_copies > 0);
         assert(A::n_moves >= 0);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
-        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(), &func);
-        assert(test_alloc_base::alloc_count > 0);
+        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(&alloc_stats), &func);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<int> f = p.get_future();
         p(4);
         assert(f.get() == 4);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {
         A a(5);
-        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(), func);
-        assert(test_alloc_base::alloc_count > 0);
+        std::packaged_task<int(int)> p(std::allocator_arg, test_allocator<A>(&alloc_stats), func);
+        assert(alloc_stats.alloc_count > 0);
         assert(p.valid());
         std::future<int> f = p.get_future();
         p(4);
         assert(f.get() == 4);
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     A::n_copies = 0;
     A::n_moves  = 0;
     {

diff  --git a/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp b/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp
index 05bfe2bea7f4f..643fb6a4259a6 100644
--- a/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp
+++ b/libcxx/test/std/thread/futures/futures.unique_future/dtor.pass.cpp
@@ -24,49 +24,50 @@
 
 int main(int, char**)
 {
-    assert(test_alloc_base::alloc_count == 0);
+    test_allocator_statistics alloc_stats;
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef int& T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<int>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<int>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         typedef void T;
         std::future<T> f;
         {
-            std::promise<T> p(std::allocator_arg, test_allocator<T>());
-            assert(test_alloc_base::alloc_count == 1);
+            std::promise<T> p(std::allocator_arg, test_allocator<T>(&alloc_stats));
+            assert(alloc_stats.alloc_count == 1);
             f = p.get_future();
-            assert(test_alloc_base::alloc_count == 1);
+            assert(alloc_stats.alloc_count == 1);
             assert(f.valid());
         }
-        assert(test_alloc_base::alloc_count == 1);
+        assert(alloc_stats.alloc_count == 1);
         assert(f.valid());
     }
-    assert(test_alloc_base::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
   return 0;
 }

diff  --git a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
index b5821d861e866..e364e9eebc046 100644
--- a/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
+++ b/libcxx/test/std/utilities/function.objects/func.wrap/func.wrap.func/func.wrap.func.con/alloc_F.pass.cpp
@@ -25,7 +25,6 @@
 #include "count_new.h"
 #include "../function_types.h"
 
-
 #if TEST_STD_VER >= 11
 struct RValueCallable {
     template <class ...Args>
@@ -37,6 +36,8 @@ struct LValueCallable {
 };
 #endif
 
+test_allocator_statistics alloc_stats;
+
 class DummyClass {};
 
 template <class FuncType, class AllocType>
@@ -69,7 +70,7 @@ void test_FreeFunction(AllocType& alloc)
     std::function<FuncType> f2(std::allocator_arg, alloc, target);
     // The allocator may not fit in the small object buffer, if we allocated
     // check it was done via the allocator.
-    assert(globalMemCounter.checkOutstandingNewEq(test_alloc_base::alloc_count));
+    assert(globalMemCounter.checkOutstandingNewEq(alloc_stats.alloc_count));
     assert(f2.template target<FuncType*>());
     assert(*f2.template target<FuncType*>() == target);
     assert(f2.template target<FuncType>() == 0);
@@ -86,7 +87,7 @@ void test_MemFunClass(AllocType& alloc)
     TargetType target = &MemFunClass::foo;
     assert(globalMemCounter.checkOutstandingNewEq(0));
     std::function<FuncType> f2(std::allocator_arg, alloc, target);
-    assert(globalMemCounter.checkOutstandingNewEq(test_alloc_base::alloc_count));
+    assert(globalMemCounter.checkOutstandingNewEq(alloc_stats.alloc_count));
     assert(f2.template target<TargetType>());
     assert(*f2.template target<TargetType>() == target);
     assert(f2.template target<FuncType*>() == 0);
@@ -111,15 +112,14 @@ void test_for_alloc(Alloc& alloc) {
     test_MemFunClass<int(MemFunClass::*)(int, int) const, int(MemFunClass&, int, int)>(alloc);
 }
 
-int main(int, char**)
-{
+int main(int, char**) {
   globalMemCounter.reset();
   {
     bare_allocator<DummyClass> bare_alloc;
     test_for_alloc(bare_alloc);
   }
     {
-        non_default_test_allocator<DummyClass> non_default_alloc(42);
+        non_default_test_allocator<DummyClass> non_default_alloc(42, &alloc_stats);
         test_for_alloc(non_default_alloc);
     }
 #if TEST_STD_VER >= 11

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp
index fb5e4f4d8f2e6..4d59d7f5667f8 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp
@@ -30,8 +30,9 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
-    std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5));
+    std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
     assert(A::count == 0);
     assert(p.use_count() == 1);
     assert(p.get() == 0);
@@ -42,14 +43,14 @@ int main(int, char**)
     assert(d);
     assert(d->state() == 3);
 #endif
-    assert(test_allocator<A>::count == 1);
-    assert(test_allocator<A>::alloc_count == 1);
+    assert(alloc_stats.count == 1);
+    assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     test_deleter<A>::dealloc_count = 0;
     // Test an allocator with a minimal interface
     {

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp
index ce9c3e5875eb7..5864433105581 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator_throw.pass.cpp
@@ -30,10 +30,11 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     try
     {
-        test_allocator<A>::throw_after = 0;
-        std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5));
+        alloc_stats.throw_after = 0;
+        std::shared_ptr<A> p(nullptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
         assert(false);
     }
     catch (std::bad_alloc&)
@@ -41,8 +42,8 @@ int main(int, char**)
         assert(A::count == 0);
         assert(test_deleter<A>::count == 0);
         assert(test_deleter<A>::dealloc_count == 1);
-        assert(test_allocator<A>::count == 0);
-        assert(test_allocator<A>::alloc_count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.alloc_count == 0);
     }
 
   return 0;

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 d42ce342b790b..3b86b07d79234 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
@@ -62,9 +62,10 @@ class MoveDeleter
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
     A* ptr = new A;
-    std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5));
+    std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
     assert(A::count == 1);
     assert(p.use_count() == 1);
     assert(p.get() == ptr);
@@ -75,14 +76,14 @@ int main(int, char**)
     assert(d);
     assert(d->state() == 3);
 #endif
-    assert(test_allocator<A>::count == 1);
-    assert(test_allocator<A>::alloc_count == 1);
+    assert(alloc_stats.count == 1);
+    assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     test_deleter<A>::dealloc_count = 0;
     // Test an allocator with a minimal interface
     {

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp
index 240fd358e063f..6baf2debaa999 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator_throw.pass.cpp
@@ -30,20 +30,21 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     A* ptr = new A;
     try
     {
-        test_allocator<A>::throw_after = 0;
-        std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5));
+        alloc_stats.throw_after = 0;
+        std::shared_ptr<A> p(ptr, test_deleter<A>(3), test_allocator<A>(5, &alloc_stats));
         assert(false);
     }
     catch (std::bad_alloc&)
     {
-        assert(A::count == 0);
-        assert(test_deleter<A>::count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.count == 0);
         assert(test_deleter<A>::dealloc_count == 1);
-        assert(test_allocator<A>::count == 0);
-        assert(test_allocator<A>::alloc_count == 0);
+        assert(alloc_stats.count == 0);
+        assert(alloc_stats.alloc_count == 0);
     }
 
   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 b892fb4fd9b15..472cb3d0a7d7c 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
@@ -141,17 +141,18 @@ int main(int, char**)
     test<bare_allocator<void> >();
     test<test_allocator<void> >();
 
+    test_allocator_statistics alloc_stats;
     {
     int i = 67;
     char c = 'e';
-    std::shared_ptr<A> p = std::allocate_shared<A>(test_allocator<A>(54), i, c);
-    assert(test_allocator<A>::alloc_count == 1);
+    std::shared_ptr<A> p = std::allocate_shared<A>(test_allocator<A>(54, &alloc_stats), i, c);
+    assert(alloc_stats.alloc_count == 1);
     assert(A::count == 1);
     assert(p->get_int() == 67);
     assert(p->get_char() == 'e');
     }
     assert(A::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
     int i = 67;
     char c = 'e';

diff  --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
index 17afcca06e013..a6ea07ea37cee 100644
--- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
+++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.mod/reset_pointer_deleter_allocator.pass.cpp
@@ -43,10 +43,11 @@ int A::count = 0;
 
 int main(int, char**)
 {
+    test_allocator_statistics alloc_stats;
     {
         std::shared_ptr<B> p(new B);
         A* ptr = new A;
-        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4));
+        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4, &alloc_stats));
         assert(A::count == 1);
         assert(B::count == 1);
         assert(p.use_count() == 1);
@@ -58,18 +59,18 @@ int main(int, char**)
         assert(d);
         assert(d->state() == 3);
 #endif
-        assert(test_allocator<A>::count == 1);
-        assert(test_allocator<A>::alloc_count == 1);
+        assert(alloc_stats.count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 1);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
     {
         std::shared_ptr<B> p;
         A* ptr = new A;
-        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4));
+        p.reset(ptr, test_deleter<A>(3), test_allocator<A>(4, &alloc_stats));
         assert(A::count == 1);
         assert(B::count == 1);
         assert(p.use_count() == 1);
@@ -81,14 +82,14 @@ int main(int, char**)
         assert(d);
         assert(d->state() == 3);
 #endif
-        assert(test_allocator<A>::count == 1);
-        assert(test_allocator<A>::alloc_count == 1);
+        assert(alloc_stats.count == 1);
+        assert(alloc_stats.alloc_count == 1);
     }
     assert(A::count == 0);
     assert(test_deleter<A>::count == 0);
     assert(test_deleter<A>::dealloc_count == 2);
-    assert(test_allocator<A>::count == 0);
-    assert(test_allocator<A>::alloc_count == 0);
+    assert(alloc_stats.count == 0);
+    assert(alloc_stats.alloc_count == 0);
 
 #if TEST_STD_VER > 14
     {

diff  --git a/libcxx/test/support/test_allocator.h b/libcxx/test/support/test_allocator.h
index e0e402a87971c..b5320067ca04b 100644
--- a/libcxx/test/support/test_allocator.h
+++ b/libcxx/test/support/test_allocator.h
@@ -26,23 +26,16 @@ inline typename std::allocator_traits<Alloc>::size_type alloc_max_size(Alloc con
   return AT::max_size(a);
 }
 
-class test_alloc_base {
-protected:
-  static int time_to_throw;
-
-public:
-  static int throw_after;
-  static int count;
-  static int alloc_count;
-  static int copied;
-  static int moved;
-  static int converted;
-
-  const static int destructed_value = -1;
-  const static int default_value = 0;
-  const static int moved_value = INT_MAX;
-
-  static void clear() {
+struct test_allocator_statistics {
+  int time_to_throw = 0;
+  int throw_after = INT_MAX;
+  int count = 0;
+  int alloc_count = 0;
+  int copied = 0;
+  int moved = 0;
+  int converted = 0;
+
+  TEST_CONSTEXPR_CXX14 void clear() {
     assert(count == 0 && "clearing leaking allocator data?");
     count = 0;
     time_to_throw = 0;
@@ -51,25 +44,24 @@ class test_alloc_base {
     clear_ctor_counters();
   }
 
-  static void clear_ctor_counters() {
+  TEST_CONSTEXPR_CXX14 void clear_ctor_counters() {
     copied = 0;
     moved = 0;
     converted = 0;
   }
 };
 
-int test_alloc_base::count = 0;
-int test_alloc_base::time_to_throw = 0;
-int test_alloc_base::alloc_count = 0;
-int test_alloc_base::throw_after = INT_MAX;
-int test_alloc_base::copied = 0;
-int test_alloc_base::moved = 0;
-int test_alloc_base::converted = 0;
+struct test_alloc_base {
+  TEST_CONSTEXPR static const int destructed_value = -1;
+  TEST_CONSTEXPR static const int moved_value = INT_MAX;
+};
 
 template <class T>
-class test_allocator : public test_alloc_base {
-  int data_; // participates in equality
-  int id_;   // unique identifier, doesn't participate in equality
+class test_allocator {
+  int data_ = 0; // participates in equality
+  int id_ = 0;   // unique identifier, doesn't participate in equality
+  test_allocator_statistics* stats_ = nullptr;
+
   template <class U>
   friend class test_allocator;
 
@@ -87,74 +79,113 @@ class test_allocator : public test_alloc_base {
     typedef test_allocator<U> other;
   };
 
-  test_allocator() TEST_NOEXCEPT : data_(0), id_(0) { ++count; }
-  explicit test_allocator(int i, int id = 0) TEST_NOEXCEPT : data_(i), id_(id) { ++count; }
-  test_allocator(const test_allocator& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++copied;
-    assert(a.data_ != destructed_value && a.id_ != destructed_value && "copying from destroyed allocator");
+  TEST_CONSTEXPR test_allocator() TEST_NOEXCEPT = default;
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(test_allocator_statistics* stats) TEST_NOEXCEPT : stats_(stats) {
+    if (stats_ != nullptr)
+      ++stats_->count;
+  }
+
+  TEST_CONSTEXPR explicit test_allocator(int data) TEST_NOEXCEPT : data_(data) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), stats_(stats) {
+    if (stats != nullptr)
+      ++stats_->count;
+  }
+
+  TEST_CONSTEXPR explicit test_allocator(int data, int id) TEST_NOEXCEPT : data_(data), id_(id) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, int id, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), id_(id), stats_(stats) {
+    if (stats_ != nullptr)
+      ++stats_->count;
   }
+
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator& a) TEST_NOEXCEPT
+    : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    assert(a.data_ != test_alloc_base::destructed_value && a.id_ != test_alloc_base::destructed_value &&
+           "copying from destroyed allocator");
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->copied;
+    }
+  }
+
 #if TEST_STD_VER >= 11
-  test_allocator(test_allocator&& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++moved;
-    assert(a.data_ != destructed_value && a.id_ != destructed_value && "moving from destroyed allocator");
-    a.data_ = moved_value;
-    a.id_ = moved_value;
+  TEST_CONSTEXPR_CXX14 test_allocator(test_allocator&& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->moved;
+    }
+    assert(a.data_ != test_alloc_base::destructed_value && a.id_ != test_alloc_base::destructed_value &&
+           "moving from destroyed allocator");
+    a.data_ = test_alloc_base::moved_value;
+    a.id_ = test_alloc_base::moved_value;
   }
 #endif
+
   template <class U>
-  test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {
-    ++count;
-    ++converted;
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+      ++stats_->converted;
+    }
   }
-  ~test_allocator() TEST_NOEXCEPT {
-    assert(data_ >= 0);
-    assert(id_ >= 0);
-    --count;
-    data_ = destructed_value;
-    id_ = destructed_value;
+
+  TEST_CONSTEXPR_CXX20 ~test_allocator() TEST_NOEXCEPT {
+    assert(data_ != test_alloc_base::destructed_value);
+    assert(id_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->count;
+    data_ = test_alloc_base::destructed_value;
+    id_ = test_alloc_base::destructed_value;
   }
-  pointer address(reference x) const { return &x; }
-  const_pointer address(const_reference x) const { return &x; }
-  pointer allocate(size_type n, const void* = 0) {
-    assert(data_ >= 0);
-    if (time_to_throw >= throw_after) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-      throw std::bad_alloc();
-#else
-      std::terminate();
-#endif
+
+  TEST_CONSTEXPR pointer address(reference x) const { return &x; }
+  TEST_CONSTEXPR const_pointer address(const_reference x) const { return &x; }
+
+  TEST_CONSTEXPR_CXX14 pointer allocate(size_type n, const void* = 0) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr) {
+      if (stats_->time_to_throw >= stats_->throw_after)
+        TEST_THROW(std::bad_alloc());
+      ++stats_->time_to_throw;
+      ++stats_->alloc_count;
     }
-    ++time_to_throw;
-    ++alloc_count;
-    return (pointer)::operator new(n * sizeof(T));
+    return std::allocator<value_type>().allocate(n);
   }
-  void deallocate(pointer p, size_type) {
-    assert(data_ >= 0);
-    --alloc_count;
-    ::operator delete((void*)p);
+
+  TEST_CONSTEXPR_CXX14 void deallocate(pointer p, size_type s) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->alloc_count;
+    std::allocator<value_type>().deallocate(p, s);
   }
-  size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
+  TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
 #if TEST_STD_VER < 11
   void construct(pointer p, const T& val) { ::new (static_cast<void*>(p)) T(val); }
 #else
   template <class U>
-  void construct(pointer p, U&& val) {
+  TEST_CONSTEXPR_CXX14 void construct(pointer p, U&& val) {
     ::new (static_cast<void*>(p)) T(std::forward<U>(val));
   }
 #endif
-  void destroy(pointer p) { p->~T(); }
-  friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR_CXX14 void destroy(pointer p) { p->~T(); }
+  TEST_CONSTEXPR friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
+  TEST_CONSTEXPR friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
 
-  int get_data() const { return data_; }
-  int get_id() const { return id_; }
+  TEST_CONSTEXPR int get_data() const { return data_; }
+  TEST_CONSTEXPR int get_id() const { return id_; }
 };
 
 template <class T>
-class non_default_test_allocator : public test_alloc_base {
-  int data_;
+class non_default_test_allocator {
+  int data_ = 0;
+  test_allocator_statistics* stats_ = nullptr;
 
   template <class U>
   friend class non_default_test_allocator;
@@ -173,59 +204,71 @@ class non_default_test_allocator : public test_alloc_base {
     typedef non_default_test_allocator<U> other;
   };
 
-  //    non_default_test_allocator() TEST_NOEXCEPT : data_(0) {++count;}
-  explicit non_default_test_allocator(int i) TEST_NOEXCEPT : data_(i) { ++count; }
-  non_default_test_allocator(const non_default_test_allocator& a) TEST_NOEXCEPT : data_(a.data_) { ++count; }
+  TEST_CONSTEXPR_CXX14
+  explicit non_default_test_allocator(int i, test_allocator_statistics* stats = nullptr) TEST_NOEXCEPT
+      : data_(i), stats_(stats) {
+    if (stats_ != nullptr) {
+      ++stats_->count;
+    }
+  }
+
+  TEST_CONSTEXPR_CXX14
+  non_default_test_allocator(const non_default_test_allocator& a) TEST_NOEXCEPT : data_(a.data_), stats_(a.stats_) {
+    if (stats_ != nullptr)
+      ++stats_->count;
+  }
+
   template <class U>
-  non_default_test_allocator(const non_default_test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_) {
-    ++count;
+  TEST_CONSTEXPR_CXX14 non_default_test_allocator(const non_default_test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), stats_(a.stats_) {
+    if (stats_ != nullptr)
+      ++stats_->count;
   }
-  ~non_default_test_allocator() TEST_NOEXCEPT {
-    assert(data_ >= 0);
-    --count;
-    data_ = -1;
+
+  TEST_CONSTEXPR_CXX20 ~non_default_test_allocator() TEST_NOEXCEPT {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->count;
+    data_ = test_alloc_base::destructed_value;
   }
-  pointer address(reference x) const { return &x; }
-  const_pointer address(const_reference x) const { return &x; }
-  pointer allocate(size_type n, const void* = 0) {
-    assert(data_ >= 0);
-    if (time_to_throw >= throw_after) {
-#ifndef TEST_HAS_NO_EXCEPTIONS
-      throw std::bad_alloc();
-#else
-      std::terminate();
-#endif
+
+  TEST_CONSTEXPR pointer address(reference x) const { return &x; }
+  TEST_CONSTEXPR const_pointer address(const_reference x) const { return &x; }
+
+  TEST_CONSTEXPR_CXX20 pointer allocate(size_type n, const void* = nullptr) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr) {
+      if (stats_->time_to_throw >= stats_->throw_after)
+        TEST_THROW(std::bad_alloc());
+      ++stats_->time_to_throw;
+      ++stats_->alloc_count;
     }
-    ++time_to_throw;
-    ++alloc_count;
-    return (pointer)::operator new(n * sizeof(T));
-  }
-  void deallocate(pointer p, size_type) {
-    assert(data_ >= 0);
-    --alloc_count;
-    ::operator delete((void*)p);
+    return std::allocator<value_type>().allocate(n);
   }
-  size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
-#if TEST_STD_VER < 11
-  void construct(pointer p, const T& val) { ::new (static_cast<void*>(p)) T(val); }
-#else
-  template <class U>
-  void construct(pointer p, U&& val) {
-    ::new (static_cast<void*>(p)) T(std::forward<U>(val));
+
+  TEST_CONSTEXPR_CXX20 void deallocate(pointer p, size_type n) {
+    assert(data_ != test_alloc_base::destructed_value);
+    if (stats_ != nullptr)
+      --stats_->alloc_count;
+    std::allocator<value_type>().deallocate(p, n);
   }
-#endif
-  void destroy(pointer p) { p->~T(); }
 
-  friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {
+  TEST_CONSTEXPR size_type max_size() const TEST_NOEXCEPT { return UINT_MAX / sizeof(T); }
+
+  TEST_CONSTEXPR friend bool operator==(const non_default_test_allocator& x, const non_default_test_allocator& y) {
     return x.data_ == y.data_;
   }
-  friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y) { return !(x == y); }
+
+  TEST_CONSTEXPR friend bool operator!=(const non_default_test_allocator& x, const non_default_test_allocator& y) {
+    return !(x == y);
+  }
 };
 
 template <>
-class test_allocator<void> : public test_alloc_base {
-  int data_;
-  int id_;
+class test_allocator<void> {
+  int data_ = 0;
+  int id_ = 0;
+  test_allocator_statistics* stats_ = nullptr;
 
   template <class U>
   friend class test_allocator;
@@ -242,26 +285,46 @@ class test_allocator<void> : public test_alloc_base {
     typedef test_allocator<U> other;
   };
 
-  test_allocator() TEST_NOEXCEPT : data_(0), id_(0) {}
-  explicit test_allocator(int i, int id = 0) TEST_NOEXCEPT : data_(i), id_(id) {}
-  test_allocator(const test_allocator& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {}
+  TEST_CONSTEXPR test_allocator() TEST_NOEXCEPT = default;
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(test_allocator_statistics* stats) TEST_NOEXCEPT : stats_(stats) {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data) TEST_NOEXCEPT : data_(data) {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), stats_(stats)
+  {}
+
+  TEST_CONSTEXPR explicit test_allocator(int data, int id) : data_(data), id_(id) {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(int data, int id, test_allocator_statistics* stats) TEST_NOEXCEPT
+      : data_(data), id_(id), stats_(stats)
+  {}
+
+  TEST_CONSTEXPR_CXX14 explicit test_allocator(const test_allocator& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_)
+  {}
+
   template <class U>
-  test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT : data_(a.data_), id_(a.id_) {}
-  ~test_allocator() TEST_NOEXCEPT {
-    data_ = -1;
-    id_ = -1;
+  TEST_CONSTEXPR_CXX14 test_allocator(const test_allocator<U>& a) TEST_NOEXCEPT
+      : data_(a.data_), id_(a.id_), stats_(a.stats_)
+  {}
+
+  TEST_CONSTEXPR_CXX20 ~test_allocator() TEST_NOEXCEPT {
+    data_ = test_alloc_base::destructed_value;
+    id_ = test_alloc_base::destructed_value;
   }
 
-  int get_id() const { return id_; }
-  int get_data() const { return data_; }
+  TEST_CONSTEXPR int get_id() const { return id_; }
+  TEST_CONSTEXPR int get_data() const { return data_; }
 
-  friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR friend bool operator==(const test_allocator& x, const test_allocator& y) { return x.data_ == y.data_; }
+  TEST_CONSTEXPR friend bool operator!=(const test_allocator& x, const test_allocator& y) { return !(x == y); }
 };
 
 template <class T>
 class other_allocator {
-  int data_;
+  int data_ = -1;
 
   template <class U>
   friend class other_allocator;
@@ -269,17 +332,22 @@ class other_allocator {
 public:
   typedef T value_type;
 
-  other_allocator() : data_(-1) {}
-  explicit other_allocator(int i) : data_(i) {}
+  TEST_CONSTEXPR_CXX14 other_allocator() {}
+  TEST_CONSTEXPR_CXX14 explicit other_allocator(int i) : data_(i) {}
+
   template <class U>
-  other_allocator(const other_allocator<U>& a) : data_(a.data_) {}
-  T* allocate(std::size_t n) { return (T*)::operator new(n * sizeof(T)); }
-  void deallocate(T* p, std::size_t) { ::operator delete((void*)p); }
+  TEST_CONSTEXPR_CXX14 other_allocator(const other_allocator<U>& a) : data_(a.data_) {}
 
-  other_allocator select_on_container_copy_construction() const { return other_allocator(-2); }
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<value_type>().allocate(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t s) { std::allocator<value_type>().deallocate(p, s); }
 
-  friend bool operator==(const other_allocator& x, const other_allocator& y) { return x.data_ == y.data_; }
-  friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); }
+  TEST_CONSTEXPR_CXX14 other_allocator select_on_container_copy_construction() const { return other_allocator(-2); }
+
+  TEST_CONSTEXPR_CXX14 friend bool operator==(const other_allocator& x, const other_allocator& y) {
+    return x.data_ == y.data_;
+  }
+
+  TEST_CONSTEXPR_CXX14 friend bool operator!=(const other_allocator& x, const other_allocator& y) { return !(x == y); }
 
   typedef std::true_type propagate_on_container_copy_assignment;
   typedef std::true_type propagate_on_container_move_assignment;
@@ -301,15 +369,15 @@ struct Tag_X {
   // All constructors must be passed the Tag type.
 
   // DefaultInsertable into vector<X, TaggingAllocator<X>>,
-  Tag_X(Ctor_Tag) {}
+  constexpr Tag_X(Ctor_Tag) {}
   // CopyInsertable into vector<X, TaggingAllocator<X>>,
-  Tag_X(Ctor_Tag, const Tag_X&) {}
+  constexpr Tag_X(Ctor_Tag, const Tag_X&) {}
   // MoveInsertable into vector<X, TaggingAllocator<X>>, and
-  Tag_X(Ctor_Tag, Tag_X&&) {}
+  constexpr Tag_X(Ctor_Tag, Tag_X&&) {}
 
   // EmplaceConstructible into vector<X, TaggingAllocator<X>> from args.
   template <typename... Args>
-  Tag_X(Ctor_Tag, Args&&...) {}
+  constexpr Tag_X(Ctor_Tag, Args&&...) {}
 
   // not DefaultConstructible, CopyConstructible or MoveConstructible.
   Tag_X() = delete;
@@ -317,15 +385,13 @@ struct Tag_X {
   Tag_X(Tag_X&&) = delete;
 
   // CopyAssignable.
-  Tag_X& operator=(const Tag_X&) { return *this; }
+  TEST_CONSTEXPR_CXX14 Tag_X& operator=(const Tag_X&) { return *this; };
 
   // MoveAssignable.
-  Tag_X& operator=(Tag_X&&) { return *this; }
+  TEST_CONSTEXPR_CXX14 Tag_X& operator=(Tag_X&&) { return *this; };
 
 private:
-  // Not Destructible.
-  ~Tag_X() {}
-
+  ~Tag_X() = default;
   // Erasable from vector<X, TaggingAllocator<X>>.
   friend class TaggingAllocator<Tag_X>;
 };
@@ -337,71 +403,109 @@ class TaggingAllocator {
   TaggingAllocator() = default;
 
   template <typename U>
-  TaggingAllocator(const TaggingAllocator<U>&) {}
-
-  T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
-
-  void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+  constexpr TaggingAllocator(const TaggingAllocator<U>&){};
 
   template <typename... Args>
   void construct(Tag_X* p, Args&&... args) {
     ::new ((void*)p) Tag_X(Ctor_Tag{}, std::forward<Args>(args)...);
   }
 
-  template <typename U, typename... Args>
-  void construct(U* p, Args&&... args) {
-    ::new ((void*)p) U(std::forward<Args>(args)...);
-  }
-
-  template <typename U, typename... Args>
+  template <typename U>
   void destroy(U* p) {
     p->~U();
   }
-};
-
-template <typename T, typename U>
-bool operator==(const TaggingAllocator<T>&, const TaggingAllocator<U>&) {
-  return true;
-}
 
-template <typename T, typename U>
-bool operator!=(const TaggingAllocator<T>&, const TaggingAllocator<U>&) {
-  return false;
-}
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t n) { return std::allocator<T>{}.allocate(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(T* p, std::size_t n) { std::allocator<T>{}.deallocate(p, n); }
+};
 #endif
 
 template <std::size_t MaxAllocs>
 struct limited_alloc_handle {
-  std::size_t outstanding_;
-  void* last_alloc_;
-
-  limited_alloc_handle() : outstanding_(0), last_alloc_(nullptr) {}
+  std::size_t outstanding_ = 0;
+  void* last_alloc_ = nullptr;
 
   template <class T>
-  T* allocate(std::size_t N) {
+  TEST_CONSTEXPR_CXX20 T* allocate(std::size_t N) {
     if (N + outstanding_ > MaxAllocs)
       TEST_THROW(std::bad_alloc());
-    last_alloc_ = ::operator new(N * sizeof(T));
+    last_alloc_ = std::allocator<T>().allocate(N);
     outstanding_ += N;
     return static_cast<T*>(last_alloc_);
   }
 
-  void deallocate(void* ptr, std::size_t N) {
+  template <class T>
+  TEST_CONSTEXPR_CXX20 void deallocate(T* ptr, std::size_t N) {
     if (ptr == last_alloc_) {
       last_alloc_ = nullptr;
       assert(outstanding_ >= N);
       outstanding_ -= N;
     }
-    ::operator delete(ptr);
+    std::allocator<T>().deallocate(ptr, N);
   }
 };
 
+namespace detail {
+template <class T>
+class thread_unsafe_shared_ptr {
+public:
+  thread_unsafe_shared_ptr() = default;
+
+  TEST_CONSTEXPR_CXX14 thread_unsafe_shared_ptr(const thread_unsafe_shared_ptr& other) : block(other.block) {
+    ++block->ref_count;
+  }
+
+  TEST_CONSTEXPR_CXX20 ~thread_unsafe_shared_ptr() {
+    --block->ref_count;
+    if (block->ref_count != 0)
+      return;
+    typedef std::allocator_traits<std::allocator<control_block> > allocator_traits;
+    std::allocator<control_block> alloc;
+    allocator_traits::destroy(alloc, block);
+    allocator_traits::deallocate(alloc, block, 1);
+  }
+
+  TEST_CONSTEXPR const T& operator*() const { return block->content; }
+  TEST_CONSTEXPR const T* operator->() const { return &block->content; }
+  TEST_CONSTEXPR_CXX14 T& operator*() { return block->content; }
+  TEST_CONSTEXPR_CXX14 T* operator->() { return &block->content; }
+  TEST_CONSTEXPR_CXX14 T* get() { return &block->content; }
+  TEST_CONSTEXPR const T* get() const { return &block->content; }
+
+private:
+  struct control_block {
+    template <class... Args>
+    TEST_CONSTEXPR control_block(Args... args) : content(std::forward<Args>(args)...) {}
+    size_t ref_count = 1;
+    T content;
+  };
+
+  control_block* block = nullptr;
+
+  template <class U, class... Args>
+  friend TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr<U> make_thread_unsafe_shared(Args...);
+};
+
+template <class T, class... Args>
+TEST_CONSTEXPR_CXX20 thread_unsafe_shared_ptr<T> make_thread_unsafe_shared(Args... args) {
+  typedef typename thread_unsafe_shared_ptr<T>::control_block control_block_type;
+  typedef std::allocator_traits<std::allocator<control_block_type> > allocator_traits;
+
+  thread_unsafe_shared_ptr<T> ptr;
+  std::allocator<control_block_type> alloc;
+  ptr.block = allocator_traits::allocate(alloc, 1);
+  allocator_traits::construct(alloc, ptr.block, std::forward<Args>(args)...);
+
+  return ptr;
+}
+} // namespace detail
+
 template <class T, std::size_t N>
 class limited_allocator {
   template <class U, std::size_t UN>
   friend class limited_allocator;
   typedef limited_alloc_handle<N> BuffT;
-  std::shared_ptr<BuffT> handle_;
+  detail::thread_unsafe_shared_ptr<BuffT> handle_;
 
 public:
   typedef T value_type;
@@ -417,29 +521,28 @@ class limited_allocator {
     typedef limited_allocator<U, N> other;
   };
 
-  limited_allocator() : handle_(new BuffT) {}
+  TEST_CONSTEXPR_CXX20 limited_allocator() : handle_(detail::make_thread_unsafe_shared<BuffT>()) {}
 
-  limited_allocator(limited_allocator const& other) : handle_(other.handle_) {}
+  limited_allocator(limited_allocator const&) = default;
 
   template <class U>
-  explicit limited_allocator(limited_allocator<U, N> const& other) : handle_(other.handle_) {}
+  TEST_CONSTEXPR explicit limited_allocator(limited_allocator<U, N> const& other) : handle_(other.handle_) {}
 
   limited_allocator& operator=(const limited_allocator&) = delete;
 
-  pointer allocate(size_type n) { return handle_->template allocate<T>(n); }
-  void deallocate(pointer p, size_type n) { handle_->deallocate(p, n); }
-  size_type max_size() const { return N; }
-
-  BuffT* getHandle() const { return handle_.get(); }
+  TEST_CONSTEXPR_CXX20 pointer allocate(size_type n) { return handle_->template allocate<T>(n); }
+  TEST_CONSTEXPR_CXX20 void deallocate(pointer p, size_type n) { handle_->template deallocate<T>(p, n); }
+  TEST_CONSTEXPR size_type max_size() const { return N; }
+  TEST_CONSTEXPR BuffT* getHandle() const { return handle_.get(); }
 };
 
 template <class T, class U, std::size_t N>
-inline bool operator==(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
+TEST_CONSTEXPR inline bool operator==(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
   return LHS.getHandle() == RHS.getHandle();
 }
 
 template <class T, class U, std::size_t N>
-inline bool operator!=(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
+TEST_CONSTEXPR inline bool operator!=(limited_allocator<T, N> const& LHS, limited_allocator<U, N> const& RHS) {
   return !(LHS == RHS);
 }
 


        


More information about the libcxx-commits mailing list