diff --git a/libstdc++-v3/ChangeLog b/libstdc++-v3/ChangeLog index da708305497..4674e1f7318 100644 --- a/libstdc++-v3/ChangeLog +++ b/libstdc++-v3/ChangeLog @@ -1,3 +1,20 @@ +2014-01-28 Jonathan Wakely + Kyle Lippincott + + PR libstdc++/59656 + * include/bits/shared_ptr.h (shared_ptr): Add new non-throwing + constructor and grant friendship to weak_ptr. + (weak_ptr::lock()): Use new constructor. + * include/bits/shared_ptr_base.h + (_Sp_counted_base::_M_add_ref_lock_nothrow()): Declare new function + and define specializations. + (__shared_count): Add new non-throwing constructor. + (__shared_ptr): Add new non-throwing constructor and grant friendship + to __weak_ptr. + (__weak_ptr::lock()): Use new constructor. + * testsuite/20_util/shared_ptr/cons/43820_neg.cc: Adjust dg-error. + * testsuite/20_util/shared_ptr/cons/void_neg.cc: Likewise. + 2014-01-27 Jonathan Wakely PR libstdc++/59215 diff --git a/libstdc++-v3/include/bits/shared_ptr.h b/libstdc++-v3/include/bits/shared_ptr.h index 8fcf710b328..081d3bd3748 100644 --- a/libstdc++-v3/include/bits/shared_ptr.h +++ b/libstdc++-v3/include/bits/shared_ptr.h @@ -319,6 +319,12 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION template friend shared_ptr<_Tp1> allocate_shared(const _Alloc& __a, _Args&&... __args); + + // This constructor is non-standard, it is used by weak_ptr::lock(). + shared_ptr(const weak_ptr<_Tp>& __r, std::nothrow_t) + : __shared_ptr<_Tp>(__r, std::nothrow) { } + + friend class weak_ptr<_Tp>; }; // 20.7.2.2.7 shared_ptr comparisons @@ -492,23 +498,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION shared_ptr<_Tp> lock() const noexcept - { -#ifdef __GTHREADS - if (this->expired()) - return shared_ptr<_Tp>(); - - __try - { - return shared_ptr<_Tp>(*this); - } - __catch(const bad_weak_ptr&) - { - return shared_ptr<_Tp>(); - } -#else - return this->expired() ? shared_ptr<_Tp>() : shared_ptr<_Tp>(*this); -#endif - } + { return shared_ptr<_Tp>(*this, std::nothrow); } }; // 20.7.2.3.6 weak_ptr specialized algorithms. diff --git a/libstdc++-v3/include/bits/shared_ptr_base.h b/libstdc++-v3/include/bits/shared_ptr_base.h index 1c3a47dfb6e..536df017d11 100644 --- a/libstdc++-v3/include/bits/shared_ptr_base.h +++ b/libstdc++-v3/include/bits/shared_ptr_base.h @@ -134,7 +134,10 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION void _M_add_ref_lock(); - + + bool + _M_add_ref_lock_nothrow(); + void _M_release() noexcept { @@ -246,6 +249,51 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __ATOMIC_RELAXED)); } + template<> + inline bool + _Sp_counted_base<_S_single>:: + _M_add_ref_lock_nothrow() + { + if (_M_use_count == 0) + return false; + ++_M_use_count; + return true; + } + + template<> + inline bool + _Sp_counted_base<_S_mutex>:: + _M_add_ref_lock_nothrow() + { + __gnu_cxx::__scoped_lock sentry(*this); + if (__gnu_cxx::__exchange_and_add_dispatch(&_M_use_count, 1) == 0) + { + _M_use_count = 0; + return false; + } + return true; + } + + template<> + inline bool + _Sp_counted_base<_S_atomic>:: + _M_add_ref_lock_nothrow() + { + // Perform lock-free add-if-not-zero operation. + _Atomic_word __count = _M_get_use_count(); + do + { + if (__count == 0) + return false; + // Replace the current counter value with the old value + 1, as + // long as it's not changed meanwhile. + } + while (!__atomic_compare_exchange_n(&_M_use_count, &__count, __count + 1, + true, __ATOMIC_ACQ_REL, + __ATOMIC_RELAXED)); + return true; + } + template<> inline void _Sp_counted_base<_S_single>::_M_add_ref_copy() @@ -609,6 +657,9 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Throw bad_weak_ptr when __r._M_get_use_count() == 0. explicit __shared_count(const __weak_count<_Lp>& __r); + // Does not throw if __r._M_get_use_count() == 0, caller must check. + explicit __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t); + ~__shared_count() noexcept { if (_M_pi != nullptr) @@ -761,15 +812,27 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION // Now that __weak_count is defined we can define this constructor: template<_Lock_policy _Lp> - inline __shared_count<_Lp>:: __shared_count(const __weak_count<_Lp>& __r) + inline + __shared_count<_Lp>::__shared_count(const __weak_count<_Lp>& __r) : _M_pi(__r._M_pi) { - if (_M_pi != 0) + if (_M_pi != nullptr) _M_pi->_M_add_ref_lock(); else __throw_bad_weak_ptr(); } + // Now that __weak_count is defined we can define this constructor: + template<_Lock_policy _Lp> + inline + __shared_count<_Lp>:: + __shared_count(const __weak_count<_Lp>& __r, std::nothrow_t) + : _M_pi(__r._M_pi) + { + if (_M_pi != nullptr) + if (!_M_pi->_M_add_ref_lock_nothrow()) + _M_pi = nullptr; + } // Support for enable_shared_from_this. @@ -1077,6 +1140,16 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION friend __shared_ptr<_Tp1, _Lp1> __allocate_shared(const _Alloc& __a, _Args&&... __args); + // This constructor is used by __weak_ptr::lock() and + // shared_ptr::shared_ptr(const weak_ptr&, std::nothrow_t). + __shared_ptr(const __weak_ptr<_Tp, _Lp>& __r, std::nothrow_t) + : _M_refcount(__r._M_refcount, std::nothrow) + { + _M_ptr = _M_refcount._M_get_use_count() ? __r._M_ptr : nullptr; + } + + friend class __weak_ptr<_Tp, _Lp>; + private: void* _M_get_deleter(const std::type_info& __ti) const noexcept @@ -1322,31 +1395,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION __shared_ptr<_Tp, _Lp> lock() const noexcept - { -#ifdef __GTHREADS - // Optimization: avoid throw overhead. - if (expired()) - return __shared_ptr(); - - __try - { - return __shared_ptr(*this); - } - __catch(const bad_weak_ptr&) - { - // Q: How can we get here? - // A: Another thread may have invalidated r after the - // use_count test above. - return __shared_ptr(); - } - -#else - // Optimization: avoid try/catch overhead when single threaded. - return expired() ? __shared_ptr() - : __shared_ptr(*this); - -#endif - } // XXX MT + { return __shared_ptr(*this, std::nothrow); } long use_count() 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 0a986468146..fbd8ccde620 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 p1(px); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 812 } + // { dg-error "incomplete" "" { target *-*-* } 875 } std::shared_ptr p9(ap()); // { dg-error "here" } // { dg-error "incomplete" "" { target *-*-* } 307 } diff --git a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc index 492d1db67ea..3f93a5e5249 100644 --- a/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc +++ b/libstdc++-v3/testsuite/20_util/shared_ptr/cons/void_neg.cc @@ -25,5 +25,5 @@ void test01() { std::shared_ptr p((void*)nullptr); // { dg-error "here" } - // { dg-error "incomplete" "" { target *-*-* } 811 } + // { dg-error "incomplete" "" { target *-*-* } 874 } }