Index: include/experimental/memory_resource =================================================================== --- include/experimental/memory_resource +++ include/experimental/memory_resource @@ -206,7 +206,7 @@ void construct(_Tp* __p, _Ts &&... __args) { _VSTD_LFTS::__lfts_user_alloc_construct( - __p, resource(), _VSTD::forward<_Ts>(__args)... + __p, *this, _VSTD::forward<_Ts>(__args)... ); } @@ -218,14 +218,14 @@ ::new ((void*)__p) pair<_T1, _T2>(piecewise_construct , __transform_tuple( typename __lfts_uses_alloc_ctor< - _T1, memory_resource*, _Args1... + _T1, polymorphic_allocator&, _Args1... >::type() , _VSTD::move(__x) , typename __make_tuple_indices::type{} ) , __transform_tuple( typename __lfts_uses_alloc_ctor< - _T2, memory_resource*, _Args2... + _T2, polymorphic_allocator&, _Args2... >::type() , _VSTD::move(__y) , typename __make_tuple_indices::type{} @@ -289,23 +289,23 @@ template _LIBCPP_INLINE_VISIBILITY - tuple + tuple __transform_tuple(integral_constant, tuple<_Args...> && __t, - __tuple_indices<_Idx...>) const + __tuple_indices<_Idx...>) { - using _Tup = tuple; - return _Tup(allocator_arg, resource(), + using _Tup = tuple; + return _Tup(allocator_arg, *this, _VSTD::get<_Idx>(_VSTD::move(__t))...); } template _LIBCPP_INLINE_VISIBILITY - tuple<_Args&&..., memory_resource*> + tuple<_Args&&..., polymorphic_allocator&> __transform_tuple(integral_constant, tuple<_Args...> && __t, - __tuple_indices<_Idx...>) const + __tuple_indices<_Idx...>) { - using _Tup = tuple<_Args&&..., memory_resource*>; - return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., resource()); + using _Tup = tuple<_Args&&..., polymorphic_allocator&>; + return _Tup(_VSTD::get<_Idx>(_VSTD::move(__t))..., *this); } _LIBCPP_INLINE_VISIBILITY Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_const_lvalue_pair.pass.cpp @@ -90,6 +90,32 @@ assert((doTest(UA_AllocArg, UA_None, p))); } } + +template +void test_pmr_not_uses_allocator(std::pair const& p) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, p))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_None, UA_None, p))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, p))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, p))); + } +} + template struct Print; @@ -103,7 +129,7 @@ int y = 42; const std::pair p(x, y); test_pmr_uses_allocator(p); - test_pmr_uses_allocator(p); + test_pmr_not_uses_allocator(p); test_pmr_uses_allocator(p); } { @@ -111,7 +137,7 @@ int y = 42; const std::pair p(x, std::move(y)); test_pmr_uses_allocator(p); - test_pmr_uses_allocator(p); + test_pmr_not_uses_allocator(p); test_pmr_uses_allocator(p); } } Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_rvalue.pass.cpp @@ -90,6 +90,31 @@ } } +template +void test_pmr_not_uses_allocator(std::pair&& p) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, std::move(p)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, std::move(p)))); + } +} + int main() { using ERT = std::experimental::erased_type; @@ -100,7 +125,7 @@ int y = 42; std::pair p(x, std::move(y)); test_pmr_uses_allocator(std::move(p)); - test_pmr_uses_allocator(std::move(p)); + test_pmr_not_uses_allocator(std::move(p)); test_pmr_uses_allocator(std::move(p)); } { @@ -108,7 +133,7 @@ int y = 42; std::pair p(std::move(x), y); test_pmr_uses_allocator(std::move(p)); - test_pmr_uses_allocator(std::move(p)); + test_pmr_not_uses_allocator(std::move(p)); test_pmr_uses_allocator(std::move(p)); } } Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_pair_values.pass.cpp @@ -93,6 +93,35 @@ } } +template +void test_pmr_not_uses_allocator(TT&& t, UU&& u) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::forward(t), std::forward(u)))); + } +} + int main() { using ERT = std::experimental::erased_type; @@ -102,14 +131,14 @@ int x = 42; int y = 42; test_pmr_uses_allocator(x, std::move(y)); - test_pmr_uses_allocator(x, std::move(y)); + test_pmr_not_uses_allocator(x, std::move(y)); test_pmr_uses_allocator(x, std::move(y)); } { int x = 42; const int y = 42; test_pmr_uses_allocator(std::move(x), y); - test_pmr_uses_allocator(std::move(x), y); + test_pmr_not_uses_allocator(std::move(x), y); test_pmr_uses_allocator(std::move(x), y); } } Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair.pass.cpp @@ -83,6 +83,35 @@ } } +template +void test_pmr_not_uses_allocator(std::tuple ttuple, std::tuple utuple) +{ + { + using T = NotUsesAllocator; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV1; + using U = UsesAllocatorV2; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV2; + using U = UsesAllocatorV3; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } + { + using T = UsesAllocatorV3; + using U = NotUsesAllocator; + assert((doTest(UA_None, UA_None, + std::move(ttuple), std::move(utuple)))); + } +} + int main() { using ERT = std::experimental::erased_type; @@ -91,7 +120,7 @@ { std::tuple<> t1; test_pmr_uses_allocator(t1, t1); - test_pmr_uses_allocator(t1, t1); + test_pmr_not_uses_allocator(t1, t1); test_pmr_uses_allocator(t1, t1); } { @@ -99,8 +128,8 @@ std::tuple<> t2; test_pmr_uses_allocator(t1, t2); test_pmr_uses_allocator(t2, t1); - test_pmr_uses_allocator(t1, t2); - test_pmr_uses_allocator(t2, t1); + test_pmr_not_uses_allocator(t1, t2); + test_pmr_not_uses_allocator(t2, t1); test_pmr_uses_allocator(t1, t2); test_pmr_uses_allocator(t2, t1); } @@ -111,8 +140,8 @@ std::tuple t2(x, std::move(dx)); test_pmr_uses_allocator( t1, std::move(t2)); test_pmr_uses_allocator(std::move(t2), t1); - test_pmr_uses_allocator( t1, std::move(t2)); - test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_not_uses_allocator( t1, std::move(t2)); + test_pmr_not_uses_allocator(std::move(t2), t1); test_pmr_uses_allocator( t1, std::move(t2)); test_pmr_uses_allocator(std::move(t2), t1); } @@ -126,8 +155,8 @@ std::tuple t2(x, std::move(dx), s); test_pmr_uses_allocator( t1, std::move(t2)); test_pmr_uses_allocator(std::move(t2), t1); - test_pmr_uses_allocator( t1, std::move(t2)); - test_pmr_uses_allocator(std::move(t2), t1); + test_pmr_not_uses_allocator( t1, std::move(t2)); + test_pmr_not_uses_allocator(std::move(t2), t1); test_pmr_uses_allocator( t1, std::move(t2)); test_pmr_uses_allocator(std::move(t2), t1); } Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp =================================================================== --- /dev/null +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_piecewise_pair_evil.pass.cpp @@ -0,0 +1,141 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// template class polymorphic_allocator + +// template +// void polymorphic_allocator::construct(pair*, piecewise_construct_t +// tuple, tuple) + +#include +#include +#include +#include +#include +#include + +#include "test_macros.h" + +namespace ex = std::experimental::pmr; + +template +struct EvilAlloc { + explicit EvilAlloc() : inner_(ex::null_memory_resource()) {} + + EvilAlloc(ex::polymorphic_allocator & a) : inner_(a) {} + EvilAlloc(ex::polymorphic_allocator && a) : inner_(a) {} + EvilAlloc(ex::polymorphic_allocator const & a) = delete; + EvilAlloc(ex::polymorphic_allocator const && a) = delete; + + using value_type = T; + template EvilAlloc(EvilAlloc const & rhs) : inner_(rhs.inner_) {} + + ex::polymorphic_allocator inner_; +}; + +struct WidgetV0 { + WidgetV0(int v) : value_(v) {} + + bool holds(int v, const ex::polymorphic_allocator&) const { + return value_ == v; + } +private: + int value_; +}; + +struct WidgetV1 { + using allocator_type = EvilAlloc; + + WidgetV1(int v) : value_(v), alloc_() {} + WidgetV1(std::allocator_arg_t, EvilAlloc a, int v) : value_(v), alloc_(a) {} + + bool holds(int v, const ex::polymorphic_allocator& a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +struct WidgetV2 { + using allocator_type = EvilAlloc; + + WidgetV2(int v) : value_(v), alloc_() {} + WidgetV2(int v, EvilAlloc a) : value_(v), alloc_(a) {} + + bool holds(int v, ex::polymorphic_allocator a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +struct WidgetV3 { + using allocator_type = EvilAlloc; + + WidgetV3(int v) : value_(v), alloc_() {} + WidgetV3(std::allocator_arg_t, EvilAlloc a, int v) : value_(v), alloc_(a) {} + WidgetV3(int v, EvilAlloc a) : value_(v), alloc_(a) {} + + bool holds(int v, ex::polymorphic_allocator a) const { + return value_ == v && alloc_.inner_ == a; + } +private: + int value_; + EvilAlloc alloc_; +}; + +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); +static_assert(std::uses_allocator>::value, ""); + +template +void test_evil() +{ + using PMA = ex::polymorphic_allocator; + PMA pma(ex::new_delete_resource()); + { + using Pair = std::pair; + void *where = std::malloc(sizeof (Pair)); + Pair *p = (Pair *)where; + pma.construct(p, std::piecewise_construct, std::make_tuple(42), std::make_tuple(42)); + assert(p->first.holds(42, pma)); + assert(p->second.holds(42, pma)); + pma.destroy(p); + std::free(where); + } +} + +int main() +{ + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); + test_evil(); +} Index: test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp =================================================================== --- test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp +++ test/std/experimental/memory/memory.polymorphic.allocator.class/memory.polymorphic.allocator.mem/construct_types.pass.cpp @@ -126,6 +126,39 @@ } } +template +void test_pmr_not_uses_alloc(Args&&... args) +{ + TestResource R(12435); + ex::memory_resource* M = &R; + { + // NotUsesAllocator provides valid signatures for each uses-allocator + // construction but does not supply the required allocator_type typedef. + // Test that we can call these constructors manually without + // polymorphic_allocator interfering. + using T = NotUsesAllocator; + assert(doTestUsesAllocV0(std::forward(args)...)); + assert((doTestUsesAllocV1(M, std::forward(args)...))); + assert((doTestUsesAllocV2(M, std::forward(args)...))); + } + { + // Test T(std::allocator_arg_t, Alloc const&, Args...) construction + using T = UsesAllocatorV1; + assert((doTest(UA_None, std::forward(args)...))); + } + { + // Test T(Args..., Alloc const&) construction + using T = UsesAllocatorV2; + assert((doTest(UA_None, std::forward(args)...))); + } + { + // Test that T(std::allocator_arg_t, Alloc const&, Args...) construction + // is preferred when T(Args..., Alloc const&) is also available. + using T = UsesAllocatorV3; + assert((doTest(UA_None, std::forward(args)...))); + } +} + // Test that polymorphic_allocator does not prevent us from manually // doing non-pmr uses-allocator construction. template @@ -167,16 +200,16 @@ const int cvalue = 43; { test_pmr_uses_alloc(); - test_pmr_uses_alloc(); + test_pmr_not_uses_alloc(); test_pmr_uses_alloc(); test_pmr_uses_alloc(value); - test_pmr_uses_alloc(value); + test_pmr_not_uses_alloc(value); test_pmr_uses_alloc(value); test_pmr_uses_alloc(cvalue); - test_pmr_uses_alloc(cvalue); + test_pmr_not_uses_alloc(cvalue); test_pmr_uses_alloc(cvalue); test_pmr_uses_alloc(cvalue, std::move(value)); - test_pmr_uses_alloc(cvalue, std::move(value)); + test_pmr_not_uses_alloc(cvalue, std::move(value)); test_pmr_uses_alloc(cvalue, std::move(value)); } { Index: test/support/test_memory_resource.hpp =================================================================== --- test/support/test_memory_resource.hpp +++ test/support/test_memory_resource.hpp @@ -28,7 +28,7 @@ // because it can't include template <> struct TransformErasedTypeAlloc { - using type = std::experimental::pmr::memory_resource*; + using type = std::experimental::pmr::polymorphic_allocator; }; template