aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Wakely <jwakely.gcc@gmail.com>2013-04-28 11:38:21 +0000
committerJonathan Wakely <redi@gcc.gnu.org>2013-04-28 12:38:21 +0100
commitfe807059aaaf1be52e81513df1e25ef476c56b7d (patch)
treedde84f495deb32e31bc879ea489238264f8f45c7
parent35eb492bcfbc6627bb5d800d0af2cfd8bf39203f (diff)
downloadgcc-fe807059aaaf1be52e81513df1e25ef476c56b7d.zip
gcc-fe807059aaaf1be52e81513df1e25ef476c56b7d.tar.gz
gcc-fe807059aaaf1be52e81513df1e25ef476c56b7d.tar.bz2
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
-rw-r--r--libstdc++-v3/ChangeLog15
-rw-r--r--libstdc++-v3/include/bits/shared_ptr_base.h121
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc2
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc51
-rw-r--r--libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc14
5 files changed, 156 insertions, 47 deletions
diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog
index 14ee40b..bb2bb86 100644
--- a/libstdc++-v3/ChangeLog
+++ b/libstdc++-v3/ChangeLog
@@ -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
diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h
index f463645..a0f513f 100644
--- a/libstdc++-v3/include/bits/shared_ptr_base.h
+++ b/libstdc++-v3/include/bits/shared_ptr_base.h
@@ -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
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
index 3a5f053..b6d1009 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/43820_neg.cc
@@ -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 }
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc
new file mode 100644
index 0000000..757e7eb
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/51365.cc
@@ -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);
diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc
index b6c47ce..6949c36 100644
--- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc
+++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/52924.cc
@@ -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);