Index: libcxx/include/__memory_resource/polymorphic_allocator.h =================================================================== --- libcxx/include/__memory_resource/polymorphic_allocator.h +++ libcxx/include/__memory_resource/polymorphic_allocator.h @@ -48,7 +48,9 @@ _LIBCPP_HIDE_FROM_ABI polymorphic_allocator() noexcept : __res_(std::pmr::get_default_resource()) {} - _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) {} + _LIBCPP_HIDE_FROM_ABI polymorphic_allocator(memory_resource* __r) noexcept : __res_(__r) { + _LIBCPP_ASSERT(__r != nullptr, "memory_resource pointer must be non-null"); + } polymorphic_allocator(const polymorphic_allocator&) = default; Index: libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp @@ -25,7 +25,6 @@ #include #include #include -#include #include "test_macros.h" #include "test_std_memory_resource.h" @@ -39,8 +38,8 @@ TestResource R; std::pmr::memory_resource* M = &R; std::pmr::polymorphic_allocator

A(M); - P* ptr = (P*)std::malloc(sizeof(P)); - P* ptr2 = (P*)std::malloc(sizeof(P)); + P* ptr = (P*)new char[sizeof(P)]; + P* ptr2 = (P*)new char[sizeof(P)]; // UNDER TEST // A.construct(ptr, p); @@ -55,9 +54,9 @@ checkConstructionEquiv(ptr->second, ptr2->second); A.destroy(ptr); - std::free(ptr); + delete[] ptr; A.destroy(ptr2); - std::free(ptr2); + delete[] ptr2; return tres && ures; } Index: libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_values.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_values.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/construct_pair_values.pass.cpp @@ -39,8 +39,8 @@ TestResource R; std::pmr::memory_resource* M = &R; std::pmr::polymorphic_allocator

A(M); - P* ptr = (P*)std::malloc(sizeof(P)); - P* ptr2 = (P*)std::malloc(sizeof(P)); + P* ptr = (P*)new char[sizeof(P)]; + P* ptr2 = (P*)new char[sizeof(P)]; // UNDER TEST // A.construct(ptr, std::forward(t), std::forward(u)); @@ -56,8 +56,8 @@ A.destroy(ptr); A.destroy(ptr2); - std::free(ptr); - std::free(ptr2); + delete[] ptr; + delete[] ptr2; return tres && ures; } Index: libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/resource.pass.cpp @@ -33,11 +33,6 @@ A const a(mptr); assert(a.resource() == mptr); } - { - A const a(nullptr); - assert(a.resource() == nullptr); - assert(a.resource() == nullptr); - } { A const a; assert(a.resource() == std::pmr::get_default_resource()); Index: libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.poly.allocator.class/mem.poly.allocator.mem/select_on_container_copy_construction.pass.cpp @@ -19,9 +19,26 @@ #include #include +#include #include "test_macros.h" +namespace { + struct resource : std::pmr::memory_resource { + void* do_allocate(std::size_t, std::size_t) override { + std::abort(); + } + + void do_deallocate(void*, std::size_t, std::size_t) override { + std::abort(); + } + + bool do_is_equal(const std::pmr::memory_resource& that) const noexcept override { + return dynamic_cast(&that) != nullptr; + } + } a_resource; +} + int main(int, char**) { typedef std::pmr::polymorphic_allocator A; { @@ -39,12 +56,13 @@ { std::pmr::memory_resource* mptr = (std::pmr::memory_resource*)42; std::pmr::set_default_resource(mptr); - A const a(nullptr); - assert(a.resource() == nullptr); + std::pmr::memory_resource* mptr2 = &a_resource; + A const a(mptr2); + assert(a.resource() == mptr2); A const other = a.select_on_container_copy_construction(); assert(other.resource() == std::pmr::get_default_resource()); assert(other.resource() == mptr); - assert(a.resource() == nullptr); + assert(a.resource() == mptr2); } return 0; Index: libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_from_underaligned_buffer.pass.cpp @@ -10,6 +10,9 @@ // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx10.{{9|10|11|12|13|14|15}} // XFAIL: use_system_cxx_lib && target={{.+}}-apple-macosx{{11.0|12.0}} +// MSVC can't implement LWG-3120 until the next ABI break (microsoft/STL#1468) +// XFAIL: stdlib=msvc + // // class monotonic_buffer_resource @@ -40,12 +43,12 @@ mono1.release(); // Test a size that is just big enough to fit in the buffer, - // but can't fit if it's aligned. + // but will not fit with alignment greater than 1. ret = r1.allocate(16, 1); assert(ret == buffer + 1); mono1.release(); - assert(globalMemCounter.checkNewCalledEq(0)); + ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkNewCalledEq(0)); ret = r1.allocate(16, 2); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkNewCalledEq(1)); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkLastNewSizeGe(16)); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_with_initial_size.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_with_initial_size.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.monotonic.buffer/mem.res.monotonic.buffer.mem/allocate_with_initial_size.pass.cpp @@ -35,7 +35,9 @@ } int main(int, char**) { +#ifdef _LIBCPP_VERSION test(1); +#endif test(8); test(10); test(100); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/ctor_does_not_allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/ctor_does_not_allocate.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/ctor_does_not_allocate.pass.cpp @@ -20,6 +20,14 @@ #include "count_new.h" +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + template void test() { // Constructing a pool resource should not cause allocations @@ -30,13 +38,13 @@ std::pmr::set_default_resource(std::pmr::new_delete_resource()); PoolResource r1; - assert(globalMemCounter.checkNewCalledEq(0)); + assert(globalMemCounter.checkNewCalledEq(alloc_delta)); PoolResource r2(std::pmr::pool_options{1024, 2048}); - assert(globalMemCounter.checkNewCalledEq(0)); + assert(globalMemCounter.checkNewCalledEq(2 * alloc_delta)); PoolResource r3(std::pmr::pool_options{1024, 2048}, std::pmr::new_delete_resource()); - assert(globalMemCounter.checkNewCalledEq(0)); + assert(globalMemCounter.checkNewCalledEq(3 * alloc_delta)); } int main(int, char**) { Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/sync_with_default_resource.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/sync_with_default_resource.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/sync_with_default_resource.pass.cpp @@ -20,6 +20,7 @@ int main(int, char**) { std::pmr::memory_resource* expected = std::pmr::null_memory_resource(); std::pmr::set_default_resource(expected); +#if !defined(_MSVC_STL_VERSION) || !defined(_DEBUG) { std::pmr::pool_options opts{0, 0}; std::pmr::synchronized_pool_resource r1; @@ -27,6 +28,7 @@ assert(r1.upstream_resource() == expected); assert(r2.upstream_resource() == expected); } +#endif // !defined(_MSVC_STL_VERSION) || !defined(_DEBUG) expected = std::pmr::new_delete_resource(); std::pmr::set_default_resource(expected); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/unsync_with_default_resource.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/unsync_with_default_resource.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.ctor/unsync_with_default_resource.pass.cpp @@ -20,6 +20,7 @@ int main(int, char**) { std::pmr::memory_resource* expected = std::pmr::null_memory_resource(); std::pmr::set_default_resource(expected); +#if !defined(_MSVC_STL_VERSION) || !defined(_DEBUG) { std::pmr::pool_options opts{0, 0}; std::pmr::unsynchronized_pool_resource r1; @@ -27,6 +28,7 @@ assert(r1.upstream_resource() == expected); assert(r2.upstream_resource() == expected); } +#endif // !defined(_MSVC_STL_VERSION) || !defined(_DEBUG) expected = std::pmr::new_delete_resource(); std::pmr::set_default_resource(expected); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate.pass.cpp @@ -20,6 +20,14 @@ #include "count_new.h" #include "test_macros.h" +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + int main(int, char**) { globalMemCounter.reset(); { @@ -34,7 +42,7 @@ r1.deallocate(ret, 50); sync1.release(); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteCalledGreaterThan(0)); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewEq(alloc_delta)); globalMemCounter.reset(); @@ -46,7 +54,7 @@ // Check that the destructor calls release() } ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteCalledGreaterThan(0)); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewEq(-alloc_delta)); return 0; } Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate_overaligned_request.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate_overaligned_request.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_allocate_overaligned_request.pass.cpp @@ -28,6 +28,14 @@ return (result == p); } +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + int main(int, char**) { globalMemCounter.reset(); std::pmr::pool_options opts{1, 1024}; @@ -37,7 +45,7 @@ constexpr size_t big_alignment = 8 * alignof(std::max_align_t); static_assert(big_alignment > 4); - assert(globalMemCounter.checkNewCalledEq(0)); + assert(globalMemCounter.checkNewCalledEq(alloc_delta)); void* ret = r1.allocate(2048, big_alignment); assert(ret != nullptr); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_deallocate_matches_allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_deallocate_matches_allocate.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/sync_deallocate_matches_allocate.pass.cpp @@ -50,19 +50,30 @@ std::vector deallocations; }; +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + template void test_allocation_pattern(F do_pattern) { test_resource tr; - std::pmr::pool_options opts{0, 256}; - std::pmr::synchronized_pool_resource spr(opts, &tr); + { + std::pmr::pool_options opts{0, 256}; + std::pmr::synchronized_pool_resource spr(opts, &tr); + + try { + do_pattern(spr); + } catch (const std::bad_alloc&) { + } + spr.release(); - try { - do_pattern(spr); - } catch (const std::bad_alloc&) { + assert(tr.successful_allocations.size() == tr.deallocations.size() + alloc_delta); } - spr.release(); - assert(tr.successful_allocations.size() == tr.deallocations.size()); assert(std::is_permutation( tr.successful_allocations.begin(), tr.successful_allocations.end(), Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate.pass.cpp @@ -20,6 +20,14 @@ #include "count_new.h" #include "test_macros.h" +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + int main(int, char**) { globalMemCounter.reset(); { @@ -34,7 +42,7 @@ r1.deallocate(ret, 50); unsync1.release(); ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteCalledGreaterThan(0)); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewEq(alloc_delta)); globalMemCounter.reset(); @@ -46,7 +54,7 @@ // Check that the destructor calls release() } ASSERT_WITH_LIBRARY_INTERNAL_ALLOCATIONS(globalMemCounter.checkDeleteCalledGreaterThan(0)); - assert(globalMemCounter.checkOutstandingNewEq(0)); + assert(globalMemCounter.checkOutstandingNewEq(-alloc_delta)); return 0; } Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate_overaligned_request.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate_overaligned_request.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_allocate_overaligned_request.pass.cpp @@ -28,6 +28,14 @@ return (result == p); } +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + int main(int, char**) { globalMemCounter.reset(); std::pmr::pool_options opts{1, 1024}; @@ -37,7 +45,7 @@ constexpr size_t big_alignment = 8 * alignof(std::max_align_t); static_assert(big_alignment > 4); - assert(globalMemCounter.checkNewCalledEq(0)); + assert(globalMemCounter.checkNewCalledEq(alloc_delta)); void* ret = r1.allocate(2048, big_alignment); assert(ret != nullptr); Index: libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_matches_allocate.pass.cpp =================================================================== --- libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_matches_allocate.pass.cpp +++ libcxx/test/std/utilities/utility/mem.res/mem.res.pool/mem.res.pool.mem/unsync_deallocate_matches_allocate.pass.cpp @@ -50,19 +50,30 @@ std::vector deallocations; }; +#if defined(_MSVC_STL_VERSION) && _ITERATOR_DEBUG_LEVEL == 2 +// MSVCSTL's pool resources use a vector internally, which allocates a tracking +// object when iterator debugging +constexpr int alloc_delta = 1; +#else +constexpr int alloc_delta = 0; +#endif + template void test_allocation_pattern(F do_pattern) { test_resource tr; - std::pmr::pool_options opts{0, 256}; - std::pmr::unsynchronized_pool_resource uspr(opts, &tr); + { + std::pmr::pool_options opts{0, 256}; + std::pmr::unsynchronized_pool_resource uspr(opts, &tr); + + try { + do_pattern(uspr); + } catch (const std::bad_alloc&) { + } + uspr.release(); - try { - do_pattern(uspr); - } catch (const std::bad_alloc&) { + assert(tr.successful_allocations.size() == tr.deallocations.size() + alloc_delta); } - uspr.release(); - assert(tr.successful_allocations.size() == tr.deallocations.size()); assert(std::is_permutation( tr.successful_allocations.begin(), tr.successful_allocations.end(),