re PR libstdc++/51365 (cannot use final empty class in std::tuple)

PR libstdc++/51365
	* include/bits/shared_ptr_base (_Sp_ebo_helper): Helper class to
	implement EBO safely.
	(_Sp_counted_base::_M_get_deleter): Add noexcept.
	(_Sp_counter_ptr): Use noexcept instead of comments.
	(_Sp_counted_deleter): Likewise. Use _Sp_ebo_helper.
	(_Sp_counted_ptr_inplace): Likewise.
	* testsuite/20_util/shared_ptr/cons/51365.cc: New.
	* testsuite/20_util/shared_ptr/cons/52924.cc: Add rebind member to
	custom allocator and test construction with custom allocator.
	* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error
	line number.

From-SVN: r198367
This commit is contained in:
Jonathan Wakely 2013-04-28 11:38:21 +00:00 committed by Jonathan Wakely
parent 35eb492bcf
commit fe807059aa
5 changed files with 156 additions and 47 deletions

View File

@ -1,3 +1,18 @@
2013-04-28 Jonathan Wakely <jwakely.gcc@gmail.com>
PR libstdc++/51365
* include/bits/shared_ptr_base (_Sp_ebo_helper): Helper class to
implement EBO safely.
(_Sp_counted_base::_M_get_deleter): Add noexcept.
(_Sp_counter_ptr): Use noexcept instead of comments.
(_Sp_counted_deleter): Likewise. Use _Sp_ebo_helper.
(_Sp_counted_ptr_inplace): Likewise.
* testsuite/20_util/shared_ptr/cons/51365.cc: New.
* testsuite/20_util/shared_ptr/cons/52924.cc: Add rebind member to
custom allocator and test construction with custom allocator.
* testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error
line number.
2013-04-26 Paolo Carlini <paolo.carlini@oracle.com>
* testsuite/23_containers/unordered_set/insert/move_range.cc: Adjust

View File

@ -126,7 +126,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ delete this; }
virtual void*
_M_get_deleter(const std::type_info&) = 0;
_M_get_deleter(const std::type_info&) noexcept = 0;
void
_M_add_ref_copy()
@ -284,7 +284,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
public:
explicit
_Sp_counted_ptr(_Ptr __p)
_Sp_counted_ptr(_Ptr __p) noexcept
: _M_ptr(__p) { }
virtual void
@ -296,14 +296,14 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{ delete this; }
virtual void*
_M_get_deleter(const std::type_info&)
{ return 0; }
_M_get_deleter(const std::type_info&) noexcept
{ return nullptr; }
_Sp_counted_ptr(const _Sp_counted_ptr&) = delete;
_Sp_counted_ptr& operator=(const _Sp_counted_ptr&) = delete;
protected:
_Ptr _M_ptr; // copy constructor must not throw
private:
_Ptr _M_ptr;
};
template<>
@ -318,59 +318,91 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
inline void
_Sp_counted_ptr<nullptr_t, _S_atomic>::_M_dispose() noexcept { }
template<int _Nm, typename _Tp,
bool __use_ebo = !__is_final(_Tp) && __is_empty(_Tp)>
struct _Sp_ebo_helper;
/// Specialization using EBO.
template<int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, true> : private _Tp
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _Tp(__tp) { }
static _Tp&
_S_get(_Sp_ebo_helper& __eboh) { return static_cast<_Tp&>(__eboh); }
};
/// Specialization not using EBO.
template<int _Nm, typename _Tp>
struct _Sp_ebo_helper<_Nm, _Tp, false>
{
explicit _Sp_ebo_helper(const _Tp& __tp) : _M_tp(__tp) { }
static _Tp&
_S_get(_Sp_ebo_helper& __eboh)
{ return __eboh._M_tp; }
private:
_Tp _M_tp;
};
// Support for custom deleter and/or allocator
template<typename _Ptr, typename _Deleter, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_deleter final : public _Sp_counted_base<_Lp>
{
// 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 _Alloc // copy constructor must not throw
class _Impl : _Sp_ebo_helper<0, _Deleter>, _Sp_ebo_helper<1, _Alloc>
{
_Deleter _M_del; // copy constructor must not throw
_My_Deleter(_Deleter __d, const _Alloc& __a)
: _Alloc(__a), _M_del(__d) { }
typedef _Sp_ebo_helper<0, _Deleter> _Del_base;
typedef _Sp_ebo_helper<1, _Alloc> _Alloc_base;
public:
_Impl(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _M_ptr(__p), _Del_base(__d), _Alloc_base(__a)
{ }
_Deleter& _M_del() noexcept { return _Del_base::_S_get(*this); }
_Alloc& _M_alloc() noexcept { return _Alloc_base::_S_get(*this); }
_Ptr _M_ptr;
};
public:
// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d)
: _M_ptr(__p), _M_del(__d, _Alloc()) { }
_Sp_counted_deleter(_Ptr __p, _Deleter __d) noexcept
: _M_impl(__p, __d, _Alloc()) { }
// __d(__p) must not throw.
_Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a)
: _M_ptr(__p), _M_del(__d, __a) { }
_Sp_counted_deleter(_Ptr __p, _Deleter __d, const _Alloc& __a) noexcept
: _M_impl(__p, __d, __a) { }
~_Sp_counted_deleter() noexcept { }
virtual void
_M_dispose() noexcept
{ _M_del._M_del(_M_ptr); }
{ _M_impl._M_del()(_M_impl._M_ptr); }
virtual void
_M_destroy() noexcept
{
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_counted_deleter> _Alloc_traits;
typename _Alloc_traits::allocator_type __a(_M_del);
typename _Alloc_traits::allocator_type __a(_M_impl._M_alloc());
_Alloc_traits::destroy(__a, this);
_Alloc_traits::deallocate(__a, this, 1);
}
virtual void*
_M_get_deleter(const std::type_info& __ti)
_M_get_deleter(const std::type_info& __ti) noexcept
{
#ifdef __GXX_RTTI
return __ti == typeid(_Deleter) ? &_M_del._M_del : 0;
return __ti == typeid(_Deleter) ? &_M_impl._M_del() : nullptr;
#else
return 0;
return nullptr;
#endif
}
protected:
_Ptr _M_ptr; // copy constructor must not throw
_My_Deleter _M_del; // copy constructor must not throw
private:
_Impl _M_impl;
};
// helpers for make_shared / allocate_shared
@ -380,25 +412,26 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
template<typename _Tp, typename _Alloc, _Lock_policy _Lp>
class _Sp_counted_ptr_inplace final : public _Sp_counted_base<_Lp>
{
// 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
class _Impl : _Sp_ebo_helper<0, _Alloc>
{
_Impl(_Alloc __a) : _Alloc(__a), _M_ptr() { }
_Tp* _M_ptr;
typedef _Sp_ebo_helper<0, _Alloc> _A_base;
public:
explicit _Impl(_Alloc __a) noexcept : _A_base(__a) { }
_Alloc& _M_alloc() noexcept { return _A_base::_S_get(*this); }
__gnu_cxx::__aligned_buffer<_Tp> _M_storage;
};
public:
template<typename... _Args>
_Sp_counted_ptr_inplace(_Alloc __a, _Args&&... __args)
: _M_impl(__a), _M_storage()
: _M_impl(__a)
{
_M_impl._M_ptr = _M_storage._M_ptr();
// _GLIBCXX_RESOLVE_LIB_DEFECTS
// 2070. allocate_shared should use allocator_traits<A>::construct
allocator_traits<_Alloc>::construct(__a, _M_impl._M_ptr,
allocator_traits<_Alloc>::construct(__a, _M_ptr(),
std::forward<_Args>(__args)...); // might throw
}
@ -406,7 +439,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
virtual void
_M_dispose() noexcept
{ allocator_traits<_Alloc>::destroy(_M_impl, _M_impl._M_ptr); }
{
allocator_traits<_Alloc>::destroy(_M_impl._M_alloc(), _M_ptr());
}
// Override because the allocator needs to know the dynamic type
virtual void
@ -414,7 +449,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
{
typedef typename allocator_traits<_Alloc>::template
rebind_traits<_Sp_counted_ptr_inplace> _Alloc_traits;
typename _Alloc_traits::allocator_type __a(_M_impl);
typename _Alloc_traits::allocator_type __a(_M_impl._M_alloc());
_Alloc_traits::destroy(__a, this);
_Alloc_traits::deallocate(__a, this, 1);
}
@ -424,17 +459,19 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
_M_get_deleter(const std::type_info& __ti) noexcept
{
#ifdef __GXX_RTTI
return __ti == typeid(_Sp_make_shared_tag) ? _M_storage._M_addr() : 0;
return __ti == typeid(_Sp_make_shared_tag) ? _M_ptr() : nullptr;
#else
return 0;
return nullptr;
#endif
}
private:
_Tp* _M_ptr() noexcept { return _M_impl._M_storage._M_ptr(); }
_Impl _M_impl;
__gnu_cxx::__aligned_buffer<_Tp> _M_storage;
};
template<_Lock_policy _Lp>
class __shared_count
{
@ -592,7 +629,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
void*
_M_get_deleter(const std::type_info& __ti) const noexcept
{ return _M_pi ? _M_pi->_M_get_deleter(__ti) : 0; }
{ return _M_pi ? _M_pi->_M_get_deleter(__ti) : nullptr; }
bool
_M_less(const __shared_count& __rhs) const noexcept

View File

@ -32,7 +32,7 @@ void test01()
{
X* px = 0;
std::shared_ptr<X> p1(px); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 770 }
// { dg-error "incomplete" "" { target *-*-* } 807 }
std::shared_ptr<X> p9(ap()); // { dg-error "here" }
// { dg-error "incomplete" "" { target *-*-* } 307 }

View File

@ -0,0 +1,51 @@
// { dg-options "-std=gnu++0x" }
// { dg-do compile }
// Copyright (C) 2012-2013 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>
// libstdc++/51365
// Test with 'final' deleter and allocator.
struct A { };
struct D final
{
void operator()(A*) { }
};
template<typename T>
struct Alloc final : std::allocator<T>
{
Alloc() = default;
template<typename U> Alloc(const Alloc<U>&) { }
template<typename U>
struct rebind
{ typedef Alloc<U> other; };
};
A a;
D d;
Alloc<A> al;
auto sd = std::shared_ptr<A>(&a, d);
auto sa = std::shared_ptr<A>(&a, d, al);
auto as = std::allocate_shared<A>(al);

View File

@ -22,14 +22,12 @@
// libstdc++/52924
struct A { } a;
struct A { };
struct D {
~D() noexcept(false) { }
void operator()(A*) { }
} d;
auto sp = std::shared_ptr<A>(&a, d);
};
template<typename T>
struct Alloc : std::allocator<T>
@ -37,8 +35,16 @@ struct Alloc : std::allocator<T>
Alloc() = default;
~Alloc() noexcept(false) { }
template<typename U> Alloc(const Alloc<U>&) { }
template<typename U>
struct rebind
{ typedef Alloc<U> other; };
};
A a;
D d;
Alloc<A> al;
auto sd = std::shared_ptr<A>(&a, d);
auto sa = std::shared_ptr<A>(&a, d, al);
auto as = std::allocate_shared<A>(al);