diff options
| author | Eric Fiselier <eric@efcs.ca> | 2016-06-26 23:56:32 +0000 |
|---|---|---|
| committer | Eric Fiselier <eric@efcs.ca> | 2016-06-26 23:56:32 +0000 |
| commit | 39005d30196c67e1b4e4e3cdbc9f43c8bcd24f91 (patch) | |
| tree | e31653765946bb4500afd09ee2f204bd4c5fd357 | |
| parent | 819f3b95aed74e7be8837a1ef359593c07e0d733 (diff) | |
| download | bcm5719-llvm-39005d30196c67e1b4e4e3cdbc9f43c8bcd24f91.tar.gz bcm5719-llvm-39005d30196c67e1b4e4e3cdbc9f43c8bcd24f91.zip | |
Fix PR27115 - enable_shared_from_this does not work as a virtual base class.
See https://llvm.org/bugs/show_bug.cgi?id=27115
The problem was that the conversion from
'const enable_shared_from_this<T>*' to 'const T*' didn't work if
T inherited enable_shared_from_this as a virtual base class. The fix
is to take the original pointer passed to shared_ptr's constructor in the
__enable_weak_this method and perform an upcast to 'const T*' instead of
performing a downcast from the enable_shared_from_this base.
llvm-svn: 273835
| -rw-r--r-- | libcxx/include/memory | 47 | ||||
| -rw-r--r-- | libcxx/test/std/utilities/memory/util.smartptr/util.smartptr.enab/enable_shared_from_this.pass.cpp | 16 |
2 files changed, 39 insertions, 24 deletions
diff --git a/libcxx/include/memory b/libcxx/include/memory index 587d3059ebd..47963e08a0c 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -4115,23 +4115,22 @@ public: private: - template <class _Yp> + template <class _Yp, class _OrigPtr> _LIBCPP_INLINE_VISIBILITY void - __enable_weak_this(const enable_shared_from_this<_Yp>* __e) _NOEXCEPT + __enable_weak_this(const enable_shared_from_this<_Yp>* __e, + _OrigPtr* __ptr) _NOEXCEPT { + typedef typename remove_cv<_Yp>::type _RawYp; if (__e && __e->__weak_this_.expired()) { - weak_ptr<_Yp> __tmp; - __tmp.__ptr_ = const_cast<_Yp*>(static_cast<const _Yp*>(__e)); - __tmp.__cntrl_ = __cntrl_; - __cntrl_->__add_weak(); - __e->__weak_this_.swap(__tmp); + __e->__weak_this_ = shared_ptr<_RawYp>(*this, + const_cast<_RawYp*>(static_cast<const _Yp*>(__ptr))); } } _LIBCPP_INLINE_VISIBILITY - void __enable_weak_this(const volatile void*) _NOEXCEPT {} + void __enable_weak_this(const volatile void*, const volatile void*) _NOEXCEPT {} template <class _Up> friend class _LIBCPP_TYPE_VIS_ONLY shared_ptr; template <class _Up> friend class _LIBCPP_TYPE_VIS_ONLY weak_ptr; @@ -4165,7 +4164,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk; __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), allocator<_Yp>()); __hold.release(); - __enable_weak_this(__p); + __enable_weak_this(__p, __p); } template<class _Tp> @@ -4180,7 +4179,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, #endif // _LIBCPP_NO_EXCEPTIONS typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk; __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Yp>()); - __enable_weak_this(__p); + __enable_weak_this(__p, __p); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -4230,7 +4229,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, _Alloc __a, ::new(static_cast<void*>(_VSTD::addressof(*__hold2.get()))) _CntrlBlk(__p, __d, __a); __cntrl_ = _VSTD::addressof(*__hold2.release()); - __enable_weak_this(__p); + __enable_weak_this(__p, __p); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -4341,7 +4340,7 @@ shared_ptr<_Tp>::shared_ptr(auto_ptr<_Yp> __r, { typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk; __cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>()); - __enable_weak_this(__r.get()); + __enable_weak_this(__r.get(), __r.get()); __r.release(); } @@ -4369,7 +4368,7 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_Yp, _Dp> __r, { typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk; __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), allocator<_Yp>()); - __enable_weak_this(__r.get()); + __enable_weak_this(__r.get(), __r.get()); } __r.release(); } @@ -4400,7 +4399,7 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_Yp, _Dp> __r, reference_wrapper<typename remove_reference<_Dp>::type>, allocator<_Yp> > _CntrlBlk; __cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), allocator<_Yp>()); - __enable_weak_this(__r.get()); + __enable_weak_this(__r.get(), __r.get()); } __r.release(); } @@ -4421,7 +4420,7 @@ shared_ptr<_Tp>::make_shared(_Args&& ...__args) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = __hold2.release(); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4440,7 +4439,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4459,7 +4458,7 @@ shared_ptr<_Tp>::make_shared() shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = __hold2.release(); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4477,7 +4476,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = __hold2.release(); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4495,7 +4494,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0, _A1& __a1) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = __hold2.release(); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4513,7 +4512,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0, _A1& __a1, _A2& __a2) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = __hold2.release(); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4532,7 +4531,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4551,7 +4550,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4570,7 +4569,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1) shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } @@ -4589,7 +4588,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1, _A2& _ shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); - __r.__enable_weak_this(__r.__ptr_); + __r.__enable_weak_this(__r.__ptr_, __r.__ptr_); return __r; } 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 6661e831ab8..baee66e123e 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 @@ -39,12 +39,28 @@ struct Z : Y {}; void nullDeleter(void*) {} +struct Foo : virtual public std::enable_shared_from_this<Foo> +{ + virtual ~Foo() {} +}; + +struct Bar : public Foo { + Bar(int) {} +}; + + int main() { { // https://llvm.org/bugs/show_bug.cgi?id=18843 std::shared_ptr<T const> t1(new T); std::shared_ptr<T const> t2(std::make_shared<T>()); } + { // https://llvm.org/bugs/show_bug.cgi?id=27115 + std::shared_ptr<Bar> t1(new Bar(42)); + assert(t1->shared_from_this() == t1); + std::shared_ptr<Bar> t2(std::make_shared<Bar>(42)); + assert(t2->shared_from_this() == t2); + } { std::shared_ptr<Y> p(new Z); std::shared_ptr<T> q = p->shared_from_this(); |

