From b479fbad246b04fca27175415cfafe40404443d2 Mon Sep 17 00:00:00 2001 From: Jonathan Wakely Date: Wed, 15 Aug 2018 20:20:02 +0100 Subject: [PATCH] Refactor uses-allocator construction Remove duplicated logic in experimental::pmr::polymorphic_allocator by calling the __uses_allocator_construct helper. Fix bugs in std::pmr::polymorphic_allocator with incorrect SFINAE constraint and incorrect argument order. * include/bits/uses_allocator.h (__uses_allocator_construct): Qualify calls to __uses_allocator_construct_impl and __use_alloc. * include/experimental/memory_resource (polymorphic_allocator::_M_construct): Remove. (polymorphic_allocator::construct): Call __uses_allocator_construct. Qualify calls to __use_alloc. * include/std/memory_resource (polymorphic_allocator::construct): Fix type in SFINAE constraint. Use constexpr if instead of tag dispatching to _S_construct overloads. (polymorphic_allocator::construct(pair*, ...)): Fix order of arguments to _S_construct_p. (polymorphic_allocator::_S_construct): Remove. (polymorphic_allocator::_S_construct_p): Return allocators by value not by reference. * include/std/scoped_allocator (scoped_allocator_adaptor::construct): Qualify calls to __use_alloc. * testsuite/20_util/polymorphic_allocator/construct_pair.cc: New test, copied from testsuite/20_util/scoped_allocator/construct_pair.cc. * testsuite/experimental/polymorphic_allocator/1.cc: New test. * testsuite/experimental/polymorphic_allocator/construct_pair.cc: New test. From-SVN: r263566 --- libstdc++-v3/ChangeLog | 22 ++++ libstdc++-v3/include/bits/uses_allocator.h | 5 +- .../include/experimental/memory_resource | 34 ++---- libstdc++-v3/include/std/memory_resource | 40 +++---- libstdc++-v3/include/std/scoped_allocator | 6 +- .../polymorphic_allocator/construct_pair.cc | 110 ++++++++++++++++++ .../experimental/polymorphic_allocator/1.cc | 37 ++++++ .../polymorphic_allocator/construct_pair.cc | 78 +++++++++++++ 8 files changed, 274 insertions(+), 58 deletions(-) create mode 100644 libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc create mode 100644 libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc create mode 100644 libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index 15d2eb5eee9..f9596aca81f 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,5 +1,27 @@ 2018-08-15 Jonathan Wakely + * include/bits/uses_allocator.h (__uses_allocator_construct): Qualify + calls to __uses_allocator_construct_impl and __use_alloc. + * include/experimental/memory_resource + (polymorphic_allocator::_M_construct): Remove. + (polymorphic_allocator::construct): Call __uses_allocator_construct. + Qualify calls to __use_alloc. + * include/std/memory_resource (polymorphic_allocator::construct): Fix + type in SFINAE constraint. Use constexpr if instead of tag dispatching + to _S_construct overloads. + (polymorphic_allocator::construct(pair*, ...)): Fix order of + arguments to _S_construct_p. + (polymorphic_allocator::_S_construct): Remove. + (polymorphic_allocator::_S_construct_p): Return allocators by value + not by reference. + * include/std/scoped_allocator (scoped_allocator_adaptor::construct): + Qualify calls to __use_alloc. + * testsuite/20_util/polymorphic_allocator/construct_pair.cc: New test, + copied from testsuite/20_util/scoped_allocator/construct_pair.cc. + * testsuite/experimental/polymorphic_allocator/1.cc: New test. + * testsuite/experimental/polymorphic_allocator/construct_pair.cc: + New test. + * src/c++17/memory_resource.cc [!_GLIBCXX_HAS_GTHREADS] (atomic_mem_res): Add unsynchronized definition for single-threaded. diff --git a/libstdc++-v3/include/bits/uses_allocator.h b/libstdc++-v3/include/bits/uses_allocator.h index 3ef2830bebc..1d313b7e7fd 100644 --- a/libstdc++-v3/include/bits/uses_allocator.h +++ b/libstdc++-v3/include/bits/uses_allocator.h @@ -179,8 +179,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void __uses_allocator_construct(const _Alloc& __a, _Tp* __ptr, _Args&&... __args) { - __uses_allocator_construct_impl(__use_alloc<_Tp, _Alloc, _Args...>(__a), - __ptr, std::forward<_Args>(__args)...); + std::__uses_allocator_construct_impl( + std::__use_alloc<_Tp, _Alloc, _Args...>(__a), __ptr, + std::forward<_Args>(__args)...); } _GLIBCXX_END_NAMESPACE_VERSION diff --git a/libstdc++-v3/include/experimental/memory_resource b/libstdc++-v3/include/experimental/memory_resource index 61c9ce0a14a..ccb45bfa335 100644 --- a/libstdc++-v3/include/experimental/memory_resource +++ b/libstdc++-v3/include/experimental/memory_resource @@ -123,27 +123,6 @@ namespace pmr { template class polymorphic_allocator { - using __uses_alloc1_ = __uses_alloc1; - using __uses_alloc2_ = __uses_alloc2; - - template - void - _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } - - template - void - _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args) - { - ::new(__p) _Tp1(allocator_arg, this->resource(), - std::forward<_Args>(__args)...); - } - - template - void - _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)..., this->resource()); } - public: using value_type = _Tp; @@ -178,10 +157,8 @@ namespace pmr { void construct(_Tp1* __p, _Args&&... __args) { - memory_resource* const __resource = this->resource(); - auto __use_tag - = __use_alloc<_Tp1, memory_resource*, _Args...>(__resource); - _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); + std::__uses_allocator_construct(this->resource(), __p, + std::forward<_Args>(__args)...); } // Specializations for pair using piecewise construction @@ -193,9 +170,9 @@ namespace pmr { { memory_resource* const __resource = this->resource(); auto __x_use_tag = - __use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); + std::__use_alloc<_Tp1, memory_resource*, _Args1...>(__resource); auto __y_use_tag = - __use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); + std::__use_alloc<_Tp2, memory_resource*, _Args2...>(__resource); ::new(__p) std::pair<_Tp1, _Tp2>(piecewise_construct, _M_construct_p(__x_use_tag, __x), @@ -247,6 +224,9 @@ namespace pmr { memory_resource* resource() const { return _M_resource; } private: + using __uses_alloc1_ = __uses_alloc1; + using __uses_alloc2_ = __uses_alloc2; + template _Tuple&& _M_construct_p(__uses_alloc0, _Tuple& __t) diff --git a/libstdc++-v3/include/std/memory_resource b/libstdc++-v3/include/std/memory_resource index bb4e31551e6..7dc35ae723d 100644 --- a/libstdc++-v3/include/std/memory_resource +++ b/libstdc++-v3/include/std/memory_resource @@ -163,14 +163,20 @@ namespace pmr template __attribute__((__nonnull__)) - typename __not_pair<_Tp>::type + typename __not_pair<_Tp1>::type construct(_Tp1* __p, _Args&&... __args) { // _GLIBCXX_RESOLVE_LIB_DEFECTS // 2969. polymorphic_allocator::construct() shouldn't pass resource() - auto __use_tag - = __use_alloc<_Tp1, polymorphic_allocator, _Args...>(*this); - _S_construct(__use_tag, __p, std::forward<_Args>(__args)...); + using __use_tag + = std::__uses_alloc_t<_Tp1, polymorphic_allocator, _Args...>; + if constexpr (is_base_of_v<__uses_alloc0, __use_tag>) + ::new(__p) _Tp1(std::forward<_Args>(__args)...); + else if constexpr (is_base_of_v<__uses_alloc1_, __use_tag>) + ::new(__p) _Tp1(allocator_arg, *this, + std::forward<_Args>(__args)...); + else + ::new(__p) _Tp1(std::forward<_Args>(__args)..., *this); } template __y_i; ::new(__p) pair<_Tp1, _Tp2>(piecewise_construct, - _S_construct_p(__x_tag, __x, __x_i), - _S_construct_p(__y_tag, __y, __y_i)); + _S_construct_p(__x_tag, __x_i, __x), + _S_construct_p(__y_tag, __y_i, __y)); } template @@ -247,31 +253,13 @@ namespace pmr using __uses_alloc1_ = __uses_alloc1; using __uses_alloc2_ = __uses_alloc2; - template - static void - _S_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)...); } - - template - static void - _S_construct(__uses_alloc1_ __ua, _Tp1* __p, _Args&&... __args) - { - ::new(__p) _Tp1(allocator_arg, *__ua._M_a, - std::forward<_Args>(__args)...); - } - - template - static void - _S_construct(__uses_alloc2_ __ua, _Tp1* __p, _Args&&... __args) - { ::new(__p) _Tp1(std::forward<_Args>(__args)..., *__ua._M_a); } - template static tuple<_Args&&...> _S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t) { return std::move(__t); } template - static tuple + static tuple _S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>, tuple<_Args...>& __t) { @@ -281,7 +269,7 @@ namespace pmr } template - static tuple<_Args&&..., polymorphic_allocator&> + static tuple<_Args&&..., polymorphic_allocator> _S_construct_p(__uses_alloc2_ __ua, index_sequence<_Ind...>, tuple<_Args...>& __t) { return { std::get<_Ind>(std::move(__t))..., *__ua._M_a }; } diff --git a/libstdc++-v3/include/std/scoped_allocator b/libstdc++-v3/include/std/scoped_allocator index ea62f113517..f1f5dd93252 100644 --- a/libstdc++-v3/include/std/scoped_allocator +++ b/libstdc++-v3/include/std/scoped_allocator @@ -361,7 +361,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION { auto& __inner = inner_allocator(); auto __use_tag - = __use_alloc<_Tp, inner_allocator_type, _Args...>(__inner); + = std::__use_alloc<_Tp, inner_allocator_type, _Args...>(__inner); _M_construct(__use_tag, __p, std::forward<_Args>(__args)...); } @@ -375,9 +375,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // 2203. wrong argument types for piecewise construction auto& __inner = inner_allocator(); auto __x_use_tag - = __use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); + = std::__use_alloc<_T1, inner_allocator_type, _Args1...>(__inner); auto __y_use_tag - = __use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); + = std::__use_alloc<_T2, inner_allocator_type, _Args2...>(__inner); typename _Build_index_tuple::__type __x_indices; typename _Build_index_tuple::__type __y_indices; typedef __outermost_alloc_traits _O_traits; diff --git a/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc new file mode 100644 index 00000000000..d9cab043c0b --- /dev/null +++ b/libstdc++-v3/testsuite/20_util/polymorphic_allocator/construct_pair.cc @@ -0,0 +1,110 @@ +// Copyright (C) 2016-2018 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++17" } +// { dg-do run { target c++17 } } + +#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); +} + +int main() +{ + test01(); + test02(); + test03(); + test04(); +} diff --git a/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc new file mode 100644 index 00000000000..90463471719 --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/1.cc @@ -0,0 +1,37 @@ +// Copyright (C) 2018 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-do compile { target c++14 } } + +#include + +struct X { int i = 0; }; + +using test_type = std::experimental::pmr::polymorphic_allocator; + +static_assert(std::is_default_constructible{}, ""); +static_assert(std::is_destructible{}, ""); +static_assert(std::is_copy_constructible{}, ""); +// N.B. std::pmr::polymorphic_allocator is not assignable, see p0337r0 +static_assert(std::is_copy_assignable{}, ""); +static_assert(std::is_constructible{}, ""); + +static_assert(std::is_same{}, ""); + +static_assert(!std::is_polymorphic{}, ""); +static_assert(!std::is_final{}, ""); diff --git a/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc new file mode 100644 index 00000000000..1708f5e329b --- /dev/null +++ b/libstdc++-v3/testsuite/experimental/polymorphic_allocator/construct_pair.cc @@ -0,0 +1,78 @@ +// Copyright (C) 2018 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-do run { target c++14 } } + +#include +#include +#include + +struct A { }; + +void +test01() +{ + struct X { + X(A&&) { } + }; + + using pair = std::pair; + std::experimental::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::experimental::pmr::polymorphic_allocator; + X(A&&, const allocator_type&) { } + }; + + using pair = std::pair; + std::experimental::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::experimental::pmr::polymorphic_allocator; + X(std::allocator_arg_t, const allocator_type&, A&&) { } + }; + + using pair = std::pair; + std::experimental::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); +} + +int main() +{ + test01(); + test02(); + test03(); +} -- 2.30.2