Commit a58a38b3 by Jonathan Wakely Committed by Jonathan Wakely

shared_ptr_base.h (_Sp_counted_ptr): Make 'final'.

	* include/bits/shared_ptr_base.h (_Sp_counted_ptr): Make 'final'.
	(_Sp_counted_deleter): Make 'final'. Use allocator_traits.
	(_Sp_counted_ptr_inplace): Make 'final'. Use allocator_traits.
	Derive from _Sp_counted_ptr instead of _Sp_counted_deleter to use EBO
	for the allocator.
	(__shared_count, __shared_ptr): Use allocator_traits.
	* include/std/future (__future_base::_Result_alloc): Make 'final'. Use
	allocator traits.
	(__future_base::_Task_state): Make 'final'.
	(__future_base::_Deferred_state): Likewise.
	(__future_base::_Async_state): Likewise.
	* testsuite/20_util/shared_ptr/cons/alloc_min.cc: New.
	* testsuite/20_util/shared_ptr/creation/alloc_min.cc: New.
	* testsuite/20_util/shared_ptr/creation/private.cc: New.
	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line numbers.
	* testsuite/30_threads/packaged_task/cons/alloc_min.cc: New.
	* testsuite/30_threads/promise/cons/alloc_min.cc: New.

From-SVN: r181171
parent 8ebe5133
2011-11-08 Jonathan Wakely <jwakely.gcc@gmail.com>
* include/bits/shared_ptr_base.h (_Sp_counted_ptr): Make 'final'.
(_Sp_counted_deleter): Make 'final'. Use allocator_traits.
(_Sp_counted_ptr_inplace): Make 'final'. Use allocator_traits.
Derive from _Sp_counted_ptr instead of _Sp_counted_deleter to use EBO
for the allocator.
(__shared_count, __shared_ptr): Use allocator_traits.
* include/std/future (__future_base::_Result_alloc): Make 'final'. Use
allocator traits.
(__future_base::_Task_state): Make 'final'.
(__future_base::_Deferred_state): Likewise.
(__future_base::_Async_state): Likewise.
* testsuite/20_util/shared_ptr/cons/alloc_min.cc: New.
* testsuite/20_util/shared_ptr/creation/alloc_min.cc: New.
* testsuite/20_util/shared_ptr/creation/private.cc: New.
* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust line numbers.
* testsuite/30_threads/packaged_task/cons/alloc_min.cc: New.
* testsuite/30_threads/promise/cons/alloc_min.cc: New.
2011-11-08 Paolo Carlini <paolo.carlini@oracle.com>
* acinclude.m4 ([GLIBCXX_ENABLE_VISIBILITY]): Rename to
......
......@@ -281,7 +281,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Counted ptr with no deleter or allocator support
template<typename _Ptr, _Lock_policy _Lp>
class _Sp_counted_ptr : public _Sp_counted_base<_Lp>
class _Sp_counted_ptr final : public _Sp_counted_base<_Lp>
{
public:
explicit
......@@ -321,20 +321,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// Support for custom deleter and/or allocator
template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter : public _Sp_counted_base<_Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
{
typedef typename _Alloc::template
rebind<_Sp_counted_deleter>::other _My_alloc_type;
// Helper class that stores the Deleter and also acts as an allocator.
// Used to dispose of the owned pointer and the internal refcount
// Requires that copies of _Alloc can free each other's memory.
struct _My_Deleter
: public _My_alloc_type // copy constructor must not throw
: public _Alloc // copy constructor must not throw
{
_Deleter _M_del; // copy constructor must not throw
_Deleter _M_del; // copy constructor must not throw
_My_Deleter(_Deleter __d, const _Alloc& __a)
: _My_alloc_type(__a), _M_del(__d) { }
: _Alloc(__a), _M_del(__d) { }
};
public:
......@@ -353,9 +350,11 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual void
_M_destroy() noexcept
{
_My_alloc_type __a(_M_del);
this->~_Sp_counted_deleter();
__a.deallocate(this, 1);
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_counted_deleter> _Alloc_traits;
typename _Alloc_traits::allocator_type __a(_M_del);
_Alloc_traits::destroy(__a, this);
_Alloc_traits::deallocate(__a, this, 1);
}
virtual void*
......@@ -375,51 +374,46 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// helpers for make_shared / allocate_shared
template<typename _Tp>
struct _Sp_destroy_inplace
{
void operator()(_Tp* __p) const { if (__p) __p->~_Tp(); }
};
struct _Sp_make_shared_tag { };
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace
: public _Sp_counted_deleter<_Tp*, _Sp_destroy_inplace<_Tp>, _Alloc, _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
{
typedef _Sp_counted_deleter<_Tp*, _Sp_destroy_inplace<_Tp>, _Alloc, _Lp>
_Base_type;
public:
explicit
_Sp_counted_ptr_inplace(_Alloc __a)
: _Base_type(static_cast<_Tp*>(0), _Sp_destroy_inplace<_Tp>(), __a)
, _M_storage()
// Helper class that stores the pointer and also acts as an allocator.
// Used to dispose of the owned pointer and the internal refcount
// Requires that copies of _Alloc can free each other's memory.
struct _Impl
: public _Alloc // copy constructor must not throw
{
void* __p = &_M_storage;
::new (__p) _Tp(); // might throw
_Base_type::_M_ptr = static_cast<_Tp*>(__p);
}
_Impl(_Alloc __a) : _Alloc(__a), _M_ptr() { }
_Tp* _M_ptr;
};
public:
template<typename... _Args>
_Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
: _Base_type(static_cast<_Tp*>(0), _Sp_destroy_inplace<_Tp>(), __a)
, _M_storage()
: _M_impl(__a), _M_storage()
{
void* __p = &_M_storage;
::new (__p) _Tp(std::forward<_Args>(__args)...); // might throw
_Base_type::_M_ptr = static_cast<_Tp*>(__p);
_M_impl._M_ptr = static_cast<_Tp*>(static_cast<void*>(&_M_storage));
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2070. allocate_shared should use allocator_traits<A>::construct
allocator_traits<_Alloc>::construct(__a, _M_impl._M_ptr,
std::forward<_Args>(__args)...); // might throw
}
virtual void
_M_dispose() noexcept
{ allocator_traits<_Alloc>::destroy(_M_impl, _M_impl._M_ptr); }
// Override because the allocator needs to know the dynamic type
virtual void
_M_destroy() noexcept
{
typedef typename _Alloc::template
rebind<_Sp_counted_ptr_inplace>::other _My_alloc_type;
_My_alloc_type __a(_Base_type::_M_del);
this->~_Sp_counted_ptr_inplace();
__a.deallocate(this, 1);
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_counted_ptr_inplace> _Alloc_traits;
typename _Alloc_traits::allocator_type __a(_M_impl);
_Alloc_traits::destroy(__a, this);
_Alloc_traits::deallocate(__a, this, 1);
}
// Sneaky trick so __shared_ptr can get the managed pointer
......@@ -429,13 +423,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
#ifdef __GXX_RTTI
return __ti == typeid(_Sp_make_shared_tag)
? static_cast<void*>(&_M_storage)
: _Base_type::_M_get_deleter(__ti);
: 0;
#else
return 0;
#endif
}
private:
_Impl _M_impl;
typename aligned_storage<sizeof(_Tp), alignment_of<_Tp>::value>::type
_M_storage;
};
......@@ -468,18 +463,21 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
// The allocator's value_type doesn't matter, will rebind it anyway.
typedef std::allocator<int> _Alloc;
typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
typedef std::allocator<_Sp_cd_type> _Alloc2;
_Alloc2 __a2;
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_cd_type> _Alloc_traits;
typename _Alloc_traits::allocator_type __a;
_Sp_cd_type* __mem = 0;
__try
{
_M_pi = __a2.allocate(1);
::new(static_cast<void*>(_M_pi)) _Sp_cd_type(__p, __d);
__mem = _Alloc_traits::allocate(__a, 1);
_Alloc_traits::construct(__a, __mem, __p, std::move(__d));
_M_pi = __mem;
}
__catch(...)
{
__d(__p); // Call _Deleter on __p.
if (_M_pi)
__a2.deallocate(static_cast<_Sp_cd_type*>(_M_pi), 1);
if (__mem)
_Alloc_traits::deallocate(__a, __mem, 1);
__throw_exception_again;
}
}
......@@ -488,18 +486,22 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
__shared_count(_Ptr __p, _Deleter __d, _Alloc __a) : _M_pi(0)
{
typedef _Sp_counted_deleter<_Ptr, _Deleter, _Alloc, _Lp> _Sp_cd_type;
typedef typename _Alloc::template rebind<_Sp_cd_type>::other _Alloc2;
_Alloc2 __a2(__a);
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_cd_type> _Alloc_traits;
typename _Alloc_traits::allocator_type __a2(__a);
_Sp_cd_type* __mem = 0;
__try
{
_M_pi = __a2.allocate(1);
::new(static_cast<void*>(_M_pi)) _Sp_cd_type(__p, __d, __a);
__mem = _Alloc_traits::allocate(__a2, 1);
_Alloc_traits::construct(__a2, __mem,
__p, std::move(__d), std::move(__a));
_M_pi = __mem;
}
__catch(...)
{
__d(__p); // Call _Deleter on __p.
if (_M_pi)
__a2.deallocate(static_cast<_Sp_cd_type*>(_M_pi), 1);
if (__mem)
_Alloc_traits::deallocate(__a2, __mem, 1);
__throw_exception_again;
}
}
......@@ -510,18 +512,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
: _M_pi(0)
{
typedef _Sp_counted_ptr_inplace<_Tp, _Alloc, _Lp> _Sp_cp_type;
typedef typename _Alloc::template rebind<_Sp_cp_type>::other _Alloc2;
_Alloc2 __a2(__a);
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_cp_type> _Alloc_traits;
typename _Alloc_traits::allocator_type __a2(__a);
_Sp_cp_type* __mem = _Alloc_traits::allocate(__a2, 1);
__try
{
_M_pi = __a2.allocate(1);
::new(static_cast<void*>(_M_pi)) _Sp_cp_type(__a,
_Alloc_traits::construct(__a2, __mem, std::move(__a),
std::forward<_Args>(__args)...);
_M_pi = __mem;
}
__catch(...)
{
if (_M_pi)
__a2.deallocate(static_cast<_Sp_cp_type*>(_M_pi), 1);
_Alloc_traits::deallocate(__a2, __mem, 1);
__throw_exception_again;
}
}
......@@ -1001,8 +1004,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
void operator()(_Tp* __ptr)
{
_M_alloc.destroy(__ptr);
_M_alloc.deallocate(__ptr, 1);
typedef allocator_traits<_Alloc> _Alloc_traits;
_Alloc_traits::destroy(_M_alloc, __ptr);
_Alloc_traits::deallocate(_M_alloc, __ptr, 1);
}
_Alloc _M_alloc;
};
......@@ -1014,14 +1018,18 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
typedef typename _Alloc::template rebind<_Tp>::other _Alloc2;
_Deleter<_Alloc2> __del = { _Alloc2(__a) };
_M_ptr = __del._M_alloc.allocate(1);
typedef allocator_traits<_Alloc2> __traits;
_M_ptr = __traits::allocate(__del._M_alloc, 1);
__try
{
__del._M_alloc.construct(_M_ptr, std::forward<_Args>(__args)...);
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2070. allocate_shared should use allocator_traits<A>::construct
__traits::construct(__del._M_alloc, _M_ptr,
std::forward<_Args>(__args)...);
}
__catch(...)
{
__del._M_alloc.deallocate(_M_ptr, 1);
__traits::deallocate(__del._M_alloc, _M_ptr, 1);
__throw_exception_again;
}
__shared_count<_Lp> __count(_M_ptr, __del, __del._M_alloc);
......
......@@ -264,10 +264,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
/// Result_alloc.
template<typename _Res, typename _Alloc>
struct _Result_alloc : _Result<_Res>, _Alloc
struct _Result_alloc final : _Result<_Res>, _Alloc
{
typedef typename _Alloc::template rebind<_Result_alloc>::other
__allocator_type;
typedef typename allocator_traits<_Alloc>::template
rebind_alloc<_Result_alloc> __allocator_type;
explicit
_Result_alloc(const _Alloc& __a) : _Result<_Res>(), _Alloc(__a)
......@@ -276,9 +276,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
private:
void _M_destroy()
{
typedef allocator_traits<__allocator_type> __traits;
__allocator_type __a(*this);
__a.destroy(this);
__a.deallocate(this, 1);
__traits::destroy(__a, this);
__traits::deallocate(__a, this, 1);
}
};
......@@ -287,15 +288,17 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_S_allocate_result(const _Allocator& __a)
{
typedef _Result_alloc<_Res, _Allocator> __result_type;
typename __result_type::__allocator_type __a2(__a);
__result_type* __p = __a2.allocate(1);
typedef allocator_traits<typename __result_type::__allocator_type>
__traits;
typename __traits::allocator_type __a2(__a);
__result_type* __p = __traits::allocate(__a2, 1);
__try
{
__a2.construct(__p, __a);
__traits::construct(__a2, __p, __a);
}
__catch(...)
{
__a2.deallocate(__p, 1);
__traits::deallocate(__a2, __p, 1);
__throw_exception_again;
}
return _Ptr<__result_type>(__p);
......@@ -1239,7 +1242,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
template<typename _Res, typename... _Args>
struct __future_base::_Task_state<_Res(_Args...)>
struct __future_base::_Task_state<_Res(_Args...)> final
: __future_base::_State_base
{
typedef _Res _Res_type;
......@@ -1393,7 +1396,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _BoundFn, typename _Res>
class __future_base::_Deferred_state : public __future_base::_State_base
class __future_base::_Deferred_state final
: public __future_base::_State_base
{
public:
explicit
......@@ -1415,7 +1419,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
};
template<typename _BoundFn, typename _Res>
class __future_base::_Async_state : public __future_base::_State_base
class __future_base::_Async_state final
: public __future_base::_State_base
{
public:
explicit
......
......@@ -32,9 +32,9 @@ void test01()
{
X* px = 0;
std::shared_ptr<X> p1(px); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 768 }
// { dg-error "incomplete" "" { target *-*-* } 771 }
std::shared_ptr<X> p9(ap()); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 862 }
// { dg-error "incomplete" "" { target *-*-* } 865 }
}
// { dg-options "-std=gnu++0x" }
// { dg-do compile }
// Copyright (C) 2011 Free Software Foundation
//
// 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/>.
// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
#include <memory>
#include <testsuite_allocator.h>
struct X { };
// 20.7.2.2.1 shared_ptr constructors [util.smartptr.shared.const]
// test shared_ptr with minimal allocator
__gnu_test::SimpleAllocator<X> alloc;
auto deleter = [](X* p) { delete p; };
std::shared_ptr<X> p(new X, deleter, alloc);
// { dg-options "-std=gnu++0x" }
// { dg-do compile }
// Copyright (C) 2011 Free Software Foundation
//
// 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/>.
// 20.7.2.2 Class template shared_ptr [util.smartptr.shared]
#include <memory>
#include <testsuite_allocator.h>
struct X { };
// 20.7.2.2.6 shared_ptr creation [util.smartptr.shared.create]
// test shared_ptr with minimal allocator
__gnu_test::SimpleAllocator<X> alloc;
auto p = std::allocate_shared<X>(alloc);
// { dg-options "-std=gnu++0x" }
// Copyright (C) 2011 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/>.
#include <memory>
#include <new>
// The behaviour tested here relies on the resolution of LWG issue 2070
template<typename T> struct MyAlloc;
class Private
{
Private() = default;
Private(const Private&) = default;
~Private() = default;
friend class MyAlloc<Private>;
public:
int get() const { return 0; }
};
template<typename T>
struct MyAlloc : std::allocator<Private>
{
void construct(T* p) { ::new((void*)p) T(); }
void destroy(T* p) { p->~T(); }
};
int main()
{
MyAlloc<Private> a;
auto p = std::allocate_shared<Private>(a);
return p->get();
}
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-require-cstdint "" }
// { dg-require-gthreads "" }
// { dg-require-atomic-builtins "" }
// Copyright (C) 2011 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/>.
// Test that packaged_task can use a minimal C++11 allocator
// and doesn't rely on C++98 allocator interface.
#include <future>
#include <testsuite_allocator.h>
using std::packaged_task;
using std::allocator_arg;
__gnu_test::SimpleAllocator<int> a;
packaged_task<int()> p(allocator_arg, a, []() { return 1; });
// { dg-do compile }
// { dg-options "-std=gnu++0x" }
// { dg-require-cstdint "" }
// { dg-require-gthreads "" }
// { dg-require-atomic-builtins "" }
// Copyright (C) 2011 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/>.
// Test that promise can use a minimal C++11 allocator
// and doesn't rely on C++98 allocator interface.
#include <future>
#include <testsuite_allocator.h>
using std::promise;
using std::allocator_arg;
using std::tuple;
typedef promise<int> p;
typedef promise<int&> pr;
typedef promise<void> pv;
__gnu_test::SimpleAllocator<p> a;
tuple<p, pr, pv> t1{ allocator_arg, a };
tuple<p, pr, pv> t2{ allocator_arg, a, p{}, pr{}, pv{} };
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment