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:
parent
35eb492bcf
commit
fe807059aa
@ -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
|
||||
|
@ -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
|
||||
|
@ -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 }
|
||||
|
51
libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc
Normal file
51
libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc
Normal 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);
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user