From: Jonathan Wakely Date: Fri, 1 Mar 2019 13:50:36 +0000 (+0000) Subject: C++2a Utility functions to implement uses-allocator construction (P0591R4) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=987bbe48bb03e04810e6c97f292549f11b5b2126;p=gcc.git C++2a Utility functions to implement uses-allocator construction (P0591R4) * include/std/memory (uses_allocator_construction_args): New set of overloaded functions. (make_obj_using_allocator, uninitialized_construct_using_allocator): New functions. * include/std/memory_resource (polymorphic_allocator::construct) [__cplusplus > 201703l]: Replace all overloads with a single function using uses_allocator_construction_args. * testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New test. * testsuite/20_util/uses_allocator/make_obj.cc: New test. From-SVN: r269311 --- diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 05675919faa..67249de5bf5 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,16 @@ +2019-03-01 Jonathan Wakely + + * include/std/memory (uses_allocator_construction_args): New set of + overloaded functions. + (make_obj_using_allocator, uninitialized_construct_using_allocator): + New functions. + * include/std/memory_resource (polymorphic_allocator::construct) + [__cplusplus > 201703l]: Replace all overloads with a single function + using uses_allocator_construction_args. + * testsuite/20_util/polymorphic_allocator/construct_c++2a.cc: New + test. + * testsuite/20_util/uses_allocator/make_obj.cc: New test. + 2019-02-27 Jonathan Wakely PR libstdc++/89466 diff --git a/libstdc++-v3/include/std/memory b/libstdc++-v3/include/std/memory index ff9add9cef2..00a85eef25e 100644 --- a/libstdc++-v3/include/std/memory +++ b/libstdc++-v3/include/std/memory @@ -91,6 +91,8 @@ #include #if __cplusplus > 201703L # include // for ispow2 +# include // for placement operator new +# include // for tuple, make_tuple, make_from_tuple #endif namespace std _GLIBCXX_VISIBILITY(default) { @@ -166,6 +168,197 @@ get_pointer_safety() noexcept { return pointer_safety::relaxed; } } #endif // C++2a +#if __cplusplus > 201703L + template + struct __is_pair : false_type { }; + template + struct __is_pair> : true_type { }; + template + struct __is_pair> : true_type { }; + + template>>, + typename _Alloc, typename... _Args> + constexpr auto + __uses_alloc_args(const _Alloc& __a, _Args&&... __args) noexcept + { + if constexpr (uses_allocator_v, _Alloc>) + { + if constexpr (is_constructible_v<_Tp, allocator_arg_t, + const _Alloc&, _Args...>) + { + return tuple( + allocator_arg, __a, std::forward<_Args>(__args)...); + } + else + { + static_assert(is_constructible_v<_Tp, _Args..., const _Alloc&>); + + return tuple<_Args&&..., const _Alloc&>( + std::forward<_Args>(__args)..., __a); + } + } + else + { + static_assert(is_constructible_v<_Tp, _Args...>); + + return tuple<_Args&&...>(std::forward<_Args>(__args)...); + } + } + +#if __cpp_concepts + template + concept bool _Std_pair = __is_pair<_Tp>::value; +#endif + +// This is a temporary workaround until -fconcepts is implied by -std=gnu++2a +#if __cpp_concepts +# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) _Std_pair T +# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) _Std_pair T +#else +# define _GLIBCXX_STD_PAIR_CONSTRAINT(T) \ + typename T, typename __ = _Require<__is_pair> +# define _GLIBCXX_STD_PAIR_CONSTRAINT_(T) typename T, typename +#endif + + template>>, +#endif + typename _Alloc, typename... _Args> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + _Args&&... __args) noexcept +#if __cpp_concepts + requires ! _Std_pair<_Tp> +#endif + { + return std::__uses_alloc_args<_Tp>(__a, std::forward<_Args>(__args)...); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Tuple1, typename _Tuple2> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t, + _Tuple1&& __x, _Tuple2&& __y) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc> + constexpr auto + uses_allocator_construction_args(const _Alloc&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, _Up&&, _Vp&&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, + const pair<_Up, _Vp>&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc&, pair<_Up, _Vp>&&) noexcept; + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Tuple1, typename _Tuple2> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, piecewise_construct_t, + _Tuple1&& __x, _Tuple2&& __y) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::apply([&__a](auto&&... __args1) { + return std::uses_allocator_construction_args<_Tp1>( + __a, std::forward(__args1)...); + }, std::forward<_Tuple1>(__x)), + std::apply([&__a](auto&&... __args2) { + return std::uses_allocator_construction_args<_Tp2>( + __a, std::forward(__args2)...); + }, std::forward<_Tuple2>(__y))); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a), + std::uses_allocator_construction_args<_Tp2>(__a)); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, _Up&& __u, _Vp&& __v) + noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, + std::forward<_Up>(__u)), + std::uses_allocator_construction_args<_Tp2>(__a, + std::forward<_Vp>(__v))); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + const pair<_Up, _Vp>& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, __pr.first), + std::uses_allocator_construction_args<_Tp2>(__a, __pr.second)); + } + + template<_GLIBCXX_STD_PAIR_CONSTRAINT_(_Tp), typename _Alloc, + typename _Up, typename _Vp> + constexpr auto + uses_allocator_construction_args(const _Alloc& __a, + pair<_Up, _Vp>&& __pr) noexcept + { + using _Tp1 = typename _Tp::first_type; + using _Tp2 = typename _Tp::second_type; + + return std::make_tuple(piecewise_construct, + std::uses_allocator_construction_args<_Tp1>(__a, + std::move(__pr).first), + std::uses_allocator_construction_args<_Tp2>(__a, + std::move(__pr).second)); + } + + template + inline _Tp + make_obj_using_allocator(const _Alloc& __a, _Args&&... __args) + { + return std::make_from_tuple<_Tp>(uses_allocator_construction_args<_Tp>( + __a, std::forward<_Args>(__args)...)); + } + + template + inline _Tp* + uninitialized_construct_using_allocator(_Tp* __p, const _Alloc& __a, + _Args&&... __args) + { + void* __vp = const_cast(static_cast(__p)); + return ::new(__vp) _Tp(std::make_obj_using_allocator<_Tp>(__a, + std::forward<_Args>(__args)...)); + } + +#endif // C++2a + _GLIBCXX_END_NAMESPACE_VERSION } // namespace #endif // C++11 diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index 93b2ebd9759..a212bccc9b1 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -170,6 +170,7 @@ namespace pmr __attribute__((__nonnull__)) { _M_resource->deallocate(__p, __n * sizeof(_Tp), alignof(_Tp)); } +#if __cplusplus <= 201703L template __attribute__((__nonnull__)) typename __not_pair<_Tp1>::type @@ -242,6 +243,16 @@ namespace pmr forward_as_tuple(std::forward<_Up>(__pr.first)), forward_as_tuple(std::forward<_Vp>(__pr.second))); } +#else + template + __attribute__((__nonnull__)) + void + construct(_Tp1* __p, _Args&&... __args) + { + std::uninitialized_construct_using_allocator(__p, *this, + std::forward<_Args>(__args)...); + } +#endif template __attribute__((__nonnull__)) diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc new file mode 100644 index 00000000000..9048ca196ff --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_c++2a.cc @@ -0,0 +1,125 @@ +// Copyright (C) 2016-2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include +#include + +struct do_not_copy { + do_not_copy() = default; + do_not_copy(const do_not_copy&) { throw 1; } +}; + +void +test01() +{ + struct X { + X(do_not_copy&&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test02() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(do_not_copy&&, const allocator_type&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test03() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(std::allocator_arg_t, const allocator_type&, do_not_copy&&) { } + }; + + using pair = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, std::piecewise_construct, + std::tuple{}, std::make_tuple(1)); + a.deallocate(ptr, 1); +} + +void +test04() +{ + struct X + { + using allocator_type = std::pmr::polymorphic_allocator; + X() = default; + X(const X&) { throw 1; } + X(const X&, const allocator_type&) { } + }; + + struct Y + { + using allocator_type = std::pmr::polymorphic_allocator; + Y() = default; + Y(const Y&) = delete; + Y(std::allocator_arg_t, const allocator_type&, const Y&) { } + }; + + using pair_type = std::pair; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + /* not const */ pair_type p; + a.construct(ptr, p); // LWG 2975 + a.deallocate(ptr, 1); +} + +void +test05() +{ + struct X { + using allocator_type = std::pmr::polymorphic_allocator; + X(int); + X(int, const allocator_type&) { } + }; + std::pmr::polymorphic_allocator a; + auto ptr = a.allocate(1); + a.construct(ptr, 1); + a.deallocate(ptr, 1); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); +} diff --git a/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc b/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc new file mode 100644 index 00000000000..670c59afb33 --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/uses_allocator/make_obj.cc @@ -0,0 +1,403 @@ +// Copyright (C) 2019 Free Software Foundation, Inc. +// +// This file is part of the GNU ISO C++ Library. This library is free +// software; you can redistribute it and/or modify it under the +// terms of the GNU General Public License as published by the +// Free Software Foundation; either version 3, or (at your option) +// any later version. + +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. + +// You should have received a copy of the GNU General Public License along +// with this library; see the file COPYING3. If not see +// . + +// { dg-options "-std=gnu++2a" } +// { dg-do run { target c++2a } } + +#include +#include + +using test_allocator = __gnu_test::uneq_allocator; + +struct Arg { }; + +struct A +{ + A() : nargs(0) { } + A(float&) : nargs(1) { } + A(int, void*) : nargs(2) { } + + // These should not be used: + A(const test_allocator& a); + A(float&, const test_allocator& a); + A(int, void*, const test_allocator& a); + + const int nargs; + const int alloc_id = -1; + + // std::uses_allocator should be false: + using allocator_type = void*(); +}; + +struct B +{ + // This means std::uses_allocator is true: + using allocator_type = test_allocator; + + B() : nargs(0) { } + B(float&) : nargs(1) { } + B(int, void*) : nargs(2) { } + + B(std::allocator_arg_t, const test_allocator& a) + : nargs(0), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, float&) + : nargs(1), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, int, void*) + : nargs(2), alloc_id(a.get_personality()) { } + B(std::allocator_arg_t, const test_allocator& a, B&& b) + : nargs(b.nargs), alloc_id(a.get_personality()) { } + + // These should not be used: + B(const test_allocator&); + B(float&, const test_allocator&, float&); + B(int, void*, const test_allocator&); + B(const test_allocator&, float&); + B(const test_allocator&, int, void*); + B(B&&); + B(B&&, const test_allocator&); + + const int nargs; + const int alloc_id = -1; +}; + +struct C +{ + C() : nargs(0) { } + C(float&) : nargs(1) { } + C(int, void*) : nargs(2) { } + + C(const test_allocator& a) + : nargs(0), alloc_id(a.get_personality()) { } + C(float&, const test_allocator& a) + : nargs(1), alloc_id(a.get_personality()) { } + C(int, void*, const test_allocator& a) + : nargs(2), alloc_id(a.get_personality()) { } + C(C&& c, const test_allocator& a) + : nargs(c.nargs), alloc_id(a.get_personality()) { } + + C(C&&); + + const int nargs; + const int alloc_id = -1; +}; + +namespace std { + // This means std::uses_allocator is true: + template<> struct uses_allocator : std::true_type { }; +} + +test_allocator alloc1(1); +test_allocator alloc2(2); + +void +test01() +{ + auto i0 = std::make_obj_using_allocator(alloc1, 2); + VERIFY( i0 == 2 ); + + float f = 0.0f; + + auto a0 = std::make_obj_using_allocator(alloc1); + VERIFY( a0.nargs == 0 ); + VERIFY( a0.alloc_id == -1 ); + auto a1 = std::make_obj_using_allocator(alloc1, f); + VERIFY( a1.nargs == 1 ); + VERIFY( a1.alloc_id == -1 ); + auto a2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( a2.nargs == 2 ); + VERIFY( a2.alloc_id == -1 ); + + auto b0 = std::make_obj_using_allocator(alloc1); + VERIFY( b0.nargs == 0 ); + VERIFY( b0.alloc_id == 1 ); + auto b1 = std::make_obj_using_allocator(alloc2, f); + VERIFY( b1.nargs == 1 ); + VERIFY( b1.alloc_id == 2 ); + auto b2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( b2.nargs == 2 ); + VERIFY( b2.alloc_id == 1 ); + + auto c0 = std::make_obj_using_allocator(alloc1); + VERIFY( c0.nargs == 0 ); + VERIFY( c0.alloc_id == 1 ); + auto c1 = std::make_obj_using_allocator(alloc2, f); + VERIFY( c1.nargs == 1 ); + VERIFY( c1.alloc_id == 2 ); + auto c2 = std::make_obj_using_allocator(alloc1, 123, nullptr); + VERIFY( c2.nargs == 2 ); + VERIFY( c2.alloc_id == 1 ); +} + +void +test02() +{ + decltype(auto) b + = std::make_obj_using_allocator(alloc1, 123, nullptr); + static_assert( std::is_const_v ); + VERIFY( b.nargs == 2 ); + VERIFY( b.alloc_id == 1 ); + + decltype(auto) c = std::make_obj_using_allocator(alloc1); + static_assert( std::is_const_v ); + VERIFY( c.nargs == 0 ); + VERIFY( c.alloc_id == 1 ); +} + +void +test03() +{ + B b; + decltype(auto) ref = std::make_obj_using_allocator(alloc1, b); + static_assert( std::is_same_v ); + VERIFY( &ref == &b ); + VERIFY( ref.nargs == 0 ); + VERIFY( ref.alloc_id == -1 ); + const B& cref = std::make_obj_using_allocator(alloc1, b); + static_assert( std::is_same_v ); + VERIFY( &cref == &b ); + VERIFY( cref.nargs == 0 ); + VERIFY( cref.alloc_id == -1 ); +} + +void +test04() +{ + struct D + { + D(std::allocator_arg_t) { } + D(std::allocator_arg_t, int) { } + + // These should not be used: + D(std::allocator_arg_t, const test_allocator&); + D(std::allocator_arg_t, const test_allocator&, int); + + ~D() { } + }; + + D d1 = std::make_obj_using_allocator(alloc1, std::allocator_arg); + + struct E + { + using allocator_type = test_allocator; + + E(std::allocator_arg_t, const test_allocator&) { } + E(std::allocator_arg_t, int, const test_allocator&) { } + + // These should not be used: + E(std::allocator_arg_t); + E(std::allocator_arg_t, int); + + ~E() { } + }; + + E e1 = std::make_obj_using_allocator(alloc1, std::allocator_arg); + E e2 = std::make_obj_using_allocator(alloc2, std::allocator_arg, 2); +} + +void +test05() +{ + using std::pair; + std::piecewise_construct_t p; + std::tuple<> t0; + float f = 0.0f; + std::tuple t1(f); + std::tuple t2{}; + + auto aa00 = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( aa00.first.nargs == 0 ); + VERIFY( aa00.first.alloc_id == -1 ); + VERIFY( aa00.second.nargs == 0 ); + VERIFY( aa00.second.alloc_id == -1 ); + auto ab00 = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( ab00.first.nargs == 0 ); + VERIFY( ab00.first.alloc_id == -1 ); + VERIFY( ab00.second.nargs == 0 ); + VERIFY( ab00.second.alloc_id == 1 ); + auto bc00 = std::make_obj_using_allocator>(alloc2, p, t0, t0); + VERIFY( bc00.first.nargs == 0 ); + VERIFY( bc00.first.alloc_id == 2 ); + VERIFY( bc00.second.nargs == 0 ); + VERIFY( bc00.second.alloc_id == 2 ); + auto cb00 = std::make_obj_using_allocator>(alloc2, p, t0, t0); + VERIFY( cb00.first.nargs == 0 ); + VERIFY( cb00.first.alloc_id == 2 ); + VERIFY( cb00.second.nargs == 0 ); + VERIFY( cb00.second.alloc_id == 2 ); + auto cc00 + = std::make_obj_using_allocator>(alloc1, p, t0, t0); + VERIFY( cc00.first.nargs == 0 ); + VERIFY( cc00.first.alloc_id == 1 ); + VERIFY( cc00.second.nargs == 0 ); + VERIFY( cc00.second.alloc_id == 1 ); + + auto aa21 = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( aa21.first.nargs == 2 ); + VERIFY( aa21.first.alloc_id == -1 ); + VERIFY( aa21.second.nargs == 1 ); + VERIFY( aa21.second.alloc_id == -1 ); + auto ab21 = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( ab21.first.nargs == 2 ); + VERIFY( ab21.first.alloc_id == -1 ); + VERIFY( ab21.second.nargs == 1 ); + VERIFY( ab21.second.alloc_id == 1 ); + auto bc11 = std::make_obj_using_allocator>(alloc2, p, t1, t1); + VERIFY( bc11.first.nargs == 1 ); + VERIFY( bc11.first.alloc_id == 2 ); + VERIFY( bc11.second.nargs == 1 ); + VERIFY( bc11.second.alloc_id == 2 ); + auto cb12 = std::make_obj_using_allocator>(alloc2, p, t1, t2); + VERIFY( cb12.first.nargs == 1 ); + VERIFY( cb12.first.alloc_id == 2 ); + VERIFY( cb12.second.nargs == 2 ); + VERIFY( cb12.second.alloc_id == 2 ); + auto cc22 + = std::make_obj_using_allocator>(alloc1, p, t2, t1); + VERIFY( cc22.first.nargs == 2 ); + VERIFY( cc22.first.alloc_id == 1 ); + VERIFY( cc22.second.nargs == 1 ); + VERIFY( cc22.second.alloc_id == 1 ); +} + +void +test06() +{ + using std::pair; + float f = 0.0f; + + auto aa00 = std::make_obj_using_allocator>(alloc1); + VERIFY( aa00.first.nargs == 0 ); + VERIFY( aa00.first.alloc_id == -1 ); + VERIFY( aa00.second.nargs == 0 ); + VERIFY( aa00.second.alloc_id == -1 ); + auto ab00 = std::make_obj_using_allocator>(alloc1); + VERIFY( ab00.first.nargs == 0 ); + VERIFY( ab00.first.alloc_id == -1 ); + VERIFY( ab00.second.nargs == 0 ); + VERIFY( ab00.second.alloc_id == 1 ); + auto bc00 = std::make_obj_using_allocator>(alloc2); + VERIFY( bc00.first.nargs == 0 ); + VERIFY( bc00.first.alloc_id == 2 ); + VERIFY( bc00.second.nargs == 0 ); + VERIFY( bc00.second.alloc_id == 2 ); + auto cb00 = std::make_obj_using_allocator>(alloc2); + VERIFY( cb00.first.nargs == 0 ); + VERIFY( cb00.first.alloc_id == 2 ); + VERIFY( cb00.second.nargs == 0 ); + VERIFY( cb00.second.alloc_id == 2 ); + auto cc00 = std::make_obj_using_allocator>(alloc1); + VERIFY( cc00.first.nargs == 0 ); + VERIFY( cc00.first.alloc_id == 1 ); + VERIFY( cc00.second.nargs == 0 ); + VERIFY( cc00.second.alloc_id == 1 ); + + auto aa11 = std::make_obj_using_allocator>(alloc1, f, f); + VERIFY( aa11.first.nargs == 1 ); + VERIFY( aa11.first.alloc_id == -1 ); + VERIFY( aa11.second.nargs == 1 ); + VERIFY( aa11.second.alloc_id == -1 ); + auto aba1 = std::make_obj_using_allocator>(alloc1, A{}, f); + VERIFY( aba1.first.nargs == 0 ); + VERIFY( aba1.first.alloc_id == -1 ); + VERIFY( aba1.second.nargs == 1 ); + VERIFY( aba1.second.alloc_id == 1 ); + auto bc11 = std::make_obj_using_allocator>(alloc2, f, f); + VERIFY( bc11.first.nargs == 1 ); + VERIFY( bc11.first.alloc_id == 2 ); + VERIFY( bc11.second.nargs == 1 ); + VERIFY( bc11.second.alloc_id == 2 ); + auto cb1b = std::make_obj_using_allocator>(alloc2, f, B{}); + VERIFY( cb1b.first.nargs == 1 ); + VERIFY( cb1b.first.alloc_id == 2 ); + VERIFY( cb1b.second.nargs == 0 ); + VERIFY( cb1b.second.alloc_id == 2 ); + auto cccc + = std::make_obj_using_allocator>(alloc1, C{}, C{}); + VERIFY( cccc.first.nargs == 0 ); + VERIFY( cccc.first.alloc_id == 1 ); + VERIFY( cccc.second.nargs == 0 ); + VERIFY( cccc.second.alloc_id == 1 ); + + pair p1a(f, A{}); + pair p11(f, f); + auto aa1a = std::make_obj_using_allocator>(alloc1, p1a); + VERIFY( aa1a.first.nargs == 1 ); + VERIFY( aa1a.first.alloc_id == -1 ); + VERIFY( aa1a.second.nargs == 0 ); + VERIFY( aa1a.second.alloc_id == -1 ); + auto ab11 = std::make_obj_using_allocator>(alloc1, p11); + VERIFY( ab11.first.nargs == 1 ); + VERIFY( ab11.first.alloc_id == -1 ); + VERIFY( ab11.second.nargs == 1 ); + VERIFY( ab11.second.alloc_id == 1 ); + auto cb11 = std::make_obj_using_allocator>(alloc2, p11); + VERIFY( cb11.first.nargs == 1 ); + VERIFY( cb11.first.alloc_id == 2 ); + VERIFY( cb11.second.nargs == 1 ); + VERIFY( cb11.second.alloc_id == 2 ); + + auto bcbc = std::make_obj_using_allocator>(alloc2, pair()); + VERIFY( bcbc.first.nargs == 0 ); + VERIFY( bcbc.first.alloc_id == 2 ); + VERIFY( bcbc.second.nargs == 0 ); + VERIFY( bcbc.second.alloc_id == 2 ); + + auto cc11 = std::make_obj_using_allocator>(alloc2, std::move(p11)); + VERIFY( cc11.first.nargs == 1 ); + VERIFY( cc11.first.alloc_id == 2 ); + VERIFY( cc11.second.nargs == 1 ); + VERIFY( cc11.second.alloc_id == 2 ); +} + +void +test07() +{ + using nested_pair = std::pair, C>; + auto p = std::make_obj_using_allocator(alloc1); + VERIFY( p.first.first.alloc_id == 1 ); + VERIFY( p.first.second.alloc_id == 1 ); + VERIFY( p.second.alloc_id == 1 ); +} + +void +test08() +{ + // LWG DR 3187. + // P0591R4 reverted DR 2586 fixes to scoped_allocator_adaptor::construct() + + struct X { + using allocator_type = std::allocator; + X(std::allocator_arg_t, allocator_type&&) { } + X(const allocator_type&) { } + }; + + std::allocator a; + std::make_obj_using_allocator(a); +} + +int +main() +{ + test01(); + test02(); + test03(); + test04(); + test05(); + test06(); + test07(); + test08(); +}