2018-08-15 Jonathan Wakely <jwakely@redhat.com>
+ * 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<T1, T2>*, ...)): 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.
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
template<typename _Tp>
class polymorphic_allocator
{
- using __uses_alloc1_ = __uses_alloc1<memory_resource*>;
- using __uses_alloc2_ = __uses_alloc2<memory_resource*>;
-
- template<typename _Tp1, typename... _Args>
- void
- _M_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args)
- { ::new(__p) _Tp1(std::forward<_Args>(__args)...); }
-
- template<typename _Tp1, typename... _Args>
- void
- _M_construct(__uses_alloc1_, _Tp1* __p, _Args&&... __args)
- {
- ::new(__p) _Tp1(allocator_arg, this->resource(),
- std::forward<_Args>(__args)...);
- }
-
- template<typename _Tp1, typename... _Args>
- void
- _M_construct(__uses_alloc2_, _Tp1* __p, _Args&&... __args)
- { ::new(__p) _Tp1(std::forward<_Args>(__args)..., this->resource()); }
-
public:
using value_type = _Tp;
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
{
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),
memory_resource* resource() const { return _M_resource; }
private:
+ using __uses_alloc1_ = __uses_alloc1<memory_resource*>;
+ using __uses_alloc2_ = __uses_alloc2<memory_resource*>;
+
template<typename _Tuple>
_Tuple&&
_M_construct_p(__uses_alloc0, _Tuple& __t)
template<typename _Tp1, typename... _Args>
__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<typename _Tp1, typename _Tp2,
index_sequence_for<_Args2...> __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<typename _Tp1, typename _Tp2>
using __uses_alloc1_ = __uses_alloc1<polymorphic_allocator>;
using __uses_alloc2_ = __uses_alloc2<polymorphic_allocator>;
- template<typename _Tp1, typename... _Args>
- static void
- _S_construct(__uses_alloc0, _Tp1* __p, _Args&&... __args)
- { ::new(__p) _Tp1(std::forward<_Args>(__args)...); }
-
- template<typename _Tp1, typename... _Args>
- static void
- _S_construct(__uses_alloc1_ __ua, _Tp1* __p, _Args&&... __args)
- {
- ::new(__p) _Tp1(allocator_arg, *__ua._M_a,
- std::forward<_Args>(__args)...);
- }
-
- template<typename _Tp1, typename... _Args>
- static void
- _S_construct(__uses_alloc2_ __ua, _Tp1* __p, _Args&&... __args)
- { ::new(__p) _Tp1(std::forward<_Args>(__args)..., *__ua._M_a); }
-
template<typename _Ind, typename... _Args>
static tuple<_Args&&...>
_S_construct_p(__uses_alloc0, _Ind, tuple<_Args...>& __t)
{ return std::move(__t); }
template<size_t... _Ind, typename... _Args>
- static tuple<allocator_arg_t, polymorphic_allocator&, _Args&&...>
+ static tuple<allocator_arg_t, polymorphic_allocator, _Args&&...>
_S_construct_p(__uses_alloc1_ __ua, index_sequence<_Ind...>,
tuple<_Args...>& __t)
{
}
template<size_t... _Ind, typename... _Args>
- 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 }; }
{
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)...);
}
// 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<sizeof...(_Args1)>::__type __x_indices;
typename _Build_index_tuple<sizeof...(_Args2)>::__type __y_indices;
typedef __outermost_alloc_traits<scoped_allocator_adaptor> _O_traits;
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-options "-std=gnu++17" }
+// { dg-do run { target c++17 } }
+
+#include <memory_resource>
+#include <utility>
+#include <tuple>
+
+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<X, int>;
+ std::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<do_not_copy>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+void
+test02()
+{
+ struct X {
+ using allocator_type = std::pmr::polymorphic_allocator<int>;
+ X(do_not_copy&&, const allocator_type&) { }
+ };
+
+ using pair = std::pair<X, int>;
+ std::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<do_not_copy>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+void
+test03()
+{
+ struct X {
+ using allocator_type = std::pmr::polymorphic_allocator<int>;
+ X(std::allocator_arg_t, const allocator_type&, do_not_copy&&) { }
+ };
+
+ using pair = std::pair<X, int>;
+ std::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<do_not_copy>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+void
+test04()
+{
+ struct X
+ {
+ using allocator_type = std::pmr::polymorphic_allocator<int>;
+ X() = default;
+ X(const X&) { throw 1; }
+ X(const X&, const allocator_type&) { }
+ };
+
+ struct Y
+ {
+ using allocator_type = std::pmr::polymorphic_allocator<int>;
+ Y() = default;
+ Y(const Y&) = delete;
+ Y(std::allocator_arg_t, const allocator_type&, const Y&) { }
+ };
+
+ using pair_type = std::pair<X, Y>;
+ std::pmr::polymorphic_allocator<pair_type> 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();
+}
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do compile { target c++14 } }
+
+#include <experimental/memory_resource>
+
+struct X { int i = 0; };
+
+using test_type = std::experimental::pmr::polymorphic_allocator<X>;
+
+static_assert(std::is_default_constructible<test_type>{}, "");
+static_assert(std::is_destructible<test_type>{}, "");
+static_assert(std::is_copy_constructible<test_type>{}, "");
+// N.B. std::pmr::polymorphic_allocator is not assignable, see p0337r0
+static_assert(std::is_copy_assignable<test_type>{}, "");
+static_assert(std::is_constructible<test_type,
+ std::experimental::pmr::memory_resource*>{}, "");
+
+static_assert(std::is_same<test_type::value_type, X>{}, "");
+
+static_assert(!std::is_polymorphic<test_type>{}, "");
+static_assert(!std::is_final<test_type>{}, "");
--- /dev/null
+// 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
+// <http://www.gnu.org/licenses/>.
+
+// { dg-do run { target c++14 } }
+
+#include <experimental/memory_resource>
+#include <utility>
+#include <tuple>
+
+struct A { };
+
+void
+test01()
+{
+ struct X {
+ X(A&&) { }
+ };
+
+ using pair = std::pair<X, int>;
+ std::experimental::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<A>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+void
+test02()
+{
+ struct X {
+ using allocator_type = std::experimental::pmr::polymorphic_allocator<int>;
+ X(A&&, const allocator_type&) { }
+ };
+
+ using pair = std::pair<X, int>;
+ std::experimental::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<A>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+void
+test03()
+{
+ struct X {
+ using allocator_type = std::experimental::pmr::polymorphic_allocator<int>;
+ X(std::allocator_arg_t, const allocator_type&, A&&) { }
+ };
+
+ using pair = std::pair<X, int>;
+ std::experimental::pmr::polymorphic_allocator<pair> a;
+ auto ptr = a.allocate(1);
+ a.construct(ptr, std::piecewise_construct,
+ std::tuple<A>{}, std::make_tuple(1));
+ a.deallocate(ptr, 1);
+}
+
+int main()
+{
+ test01();
+ test02();
+ test03();
+}