diff --git a/libcxx/include/memory b/libcxx/include/memory index 7627248a4053..0146352349d1 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -4120,7 +4120,7 @@ private: void __enable_weak_this(const enable_shared_from_this<_Yp>* __e) _NOEXCEPT { - if (__e) + if (__e && __e->__weak_this_.expired()) { __e->__weak_this_.__ptr_ = const_cast<_Yp*>(static_cast(__e)); __e->__weak_this_.__cntrl_ = __cntrl_; @@ -5432,6 +5432,16 @@ public: shared_ptr<_Tp const> shared_from_this() const {return shared_ptr(__weak_this_);} +#if _LIBCPP_STD_VER > 14 + _LIBCPP_INLINE_VISIBILITY + weak_ptr<_Tp> weak_from_this() _NOEXCEPT + { return __weak_this_; } + + _LIBCPP_INLINE_VISIBILITY + weak_ptr weak_from_this() const _NOEXCEPT + { return __weak_this_; } +#endif // _LIBCPP_STD_VER > 14 + template friend class shared_ptr; }; diff --git a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp index 77af13fa90d1..4233d7653207 100644 --- a/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp +++ b/libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp @@ -18,11 +18,15 @@ // public: // shared_ptr shared_from_this(); // shared_ptr shared_from_this() const; +// weak_ptr weak_from_this() noexcept; // C++17 +// weak_ptr weak_from_this() const noexecpt; // C++17 // }; #include #include +#include "test_macros.h" + struct T : public std::enable_shared_from_this { @@ -32,6 +36,8 @@ struct Y : T {}; struct Z : Y {}; +void nullDeleter(void*) {} + int main() { { // https://llvm.org/bugs/show_bug.cgi?id=18843 @@ -50,4 +56,84 @@ int main() assert(p == q); assert(!p.owner_before(q) && !q.owner_before(p)); // p and q share ownership } + // Test LWG issue 2529. Only reset '__weak_ptr_' when it's already expired. + // http://cplusplus.github.io/LWG/lwg-active.html#2529. + // Test two different ways: + // * Using 'weak_from_this().expired()' in C++17. + // * Using 'shared_from_this()' in all dialects. + { + + T* ptr = new T; + std::shared_ptr s(ptr); + { + // Don't re-initialize the "enabled_shared_from_this" base + // because it already references a non-expired shared_ptr. + std::shared_ptr s2(ptr, &nullDeleter); + } +#if TEST_STD_VER > 14 + // The enabled_shared_from_this base should still be referencing + // the original shared_ptr. + assert(!ptr->weak_from_this().expired()); +#endif +#ifndef TEST_HAS_NO_EXCEPTIONS + { + try { + std::shared_ptr new_s = ptr->shared_from_this(); + assert(new_s == s); + } catch (std::bad_weak_ptr const&) { + assert(false); + } catch (...) { + assert(false); + } + } +#endif + } + // Test LWG issue 2529 again. This time check that an expired pointer + // is replaced. + { + T* ptr = new T; + std::weak_ptr weak; + { + std::shared_ptr s(ptr, &nullDeleter); + assert(ptr->shared_from_this() == s); + weak = s; + assert(!weak.expired()); + } + assert(weak.expired()); + weak.reset(); +#ifndef TEST_HAS_NO_EXCEPTIONS + try { + ptr->shared_from_this(); + assert(false); + } catch (std::bad_weak_ptr const&) { + } catch (...) { assert(false); } +#endif + { + std::shared_ptr s2(ptr, &nullDeleter); + assert(ptr->shared_from_this() == s2); + } + delete ptr; + } + // Test weak_from_this_methods +#if TEST_STD_VER > 14 + { + T* ptr = new T; + const T* cptr = ptr; + + static_assert(noexcept(ptr->weak_from_this()), "Operation must be noexcept"); + static_assert(noexcept(cptr->weak_from_this()), "Operation must be noexcept"); + + std::weak_ptr my_weak = ptr->weak_from_this(); + assert(my_weak.expired()); + + std::weak_ptr my_const_weak = cptr->weak_from_this(); + assert(my_const_weak.expired()); + + // Enable shared_from_this with ptr. + std::shared_ptr sptr(ptr); + my_weak = ptr->weak_from_this(); + assert(!my_weak.expired()); + assert(my_weak.lock().get() == ptr); + } +#endif } diff --git a/libcxx/www/cxx1z_status.html b/libcxx/www/cxx1z_status.html index 3003a5f9a109..68d15e87eaf1 100644 --- a/libcxx/www/cxx1z_status.html +++ b/libcxx/www/cxx1z_status.html @@ -82,7 +82,7 @@ P0226R1LWGMathematical Special Functions for C++17Jacksonville P0220R1LWGAdopt Library Fundamentals V1 TS Components for C++17Jacksonville P0218R1LWGAdopt the File System TS for C++17Jacksonville - P0033R1LWGRe-enabling shared_from_thisJacksonville + P0033R1LWGRe-enabling shared_from_thisJacksonvilleComplete3.9 P0005R4LWGAdopt not_fn from Library Fundamentals 2 for C++17Jacksonville P0152R1LWGconstexpr atomic::is_always_lock_freeJacksonvilleComplete3.9 P0185R1LWGAdding [nothrow-]swappable traitsJacksonvilleComplete3.9