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
This commit is contained in:
Eric Fiselier 2016-06-26 23:56:32 +00:00
parent 819f3b95ae
commit 39005d3019
2 changed files with 39 additions and 24 deletions

View File

@ -4115,23 +4115,22 @@ public:
private: private:
template <class _Yp> template <class _Yp, class _OrigPtr>
_LIBCPP_INLINE_VISIBILITY _LIBCPP_INLINE_VISIBILITY
void 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()) if (__e && __e->__weak_this_.expired())
{ {
weak_ptr<_Yp> __tmp; __e->__weak_this_ = shared_ptr<_RawYp>(*this,
__tmp.__ptr_ = const_cast<_Yp*>(static_cast<const _Yp*>(__e)); const_cast<_RawYp*>(static_cast<const _Yp*>(__ptr)));
__tmp.__cntrl_ = __cntrl_;
__cntrl_->__add_weak();
__e->__weak_this_.swap(__tmp);
} }
} }
_LIBCPP_INLINE_VISIBILITY _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 shared_ptr;
template <class _Up> friend class _LIBCPP_TYPE_VIS_ONLY weak_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; typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), allocator<_Yp>()); __cntrl_ = new _CntrlBlk(__p, default_delete<_Yp>(), allocator<_Yp>());
__hold.release(); __hold.release();
__enable_weak_this(__p); __enable_weak_this(__p, __p);
} }
template<class _Tp> template<class _Tp>
@ -4180,7 +4179,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d,
#endif // _LIBCPP_NO_EXCEPTIONS #endif // _LIBCPP_NO_EXCEPTIONS
typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk; typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__p, __d, allocator<_Yp>()); __cntrl_ = new _CntrlBlk(__p, __d, allocator<_Yp>());
__enable_weak_this(__p); __enable_weak_this(__p, __p);
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
} }
catch (...) catch (...)
@ -4230,7 +4229,7 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, _Alloc __a,
::new(static_cast<void*>(_VSTD::addressof(*__hold2.get()))) ::new(static_cast<void*>(_VSTD::addressof(*__hold2.get())))
_CntrlBlk(__p, __d, __a); _CntrlBlk(__p, __d, __a);
__cntrl_ = _VSTD::addressof(*__hold2.release()); __cntrl_ = _VSTD::addressof(*__hold2.release());
__enable_weak_this(__p); __enable_weak_this(__p, __p);
#ifndef _LIBCPP_NO_EXCEPTIONS #ifndef _LIBCPP_NO_EXCEPTIONS
} }
catch (...) 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; typedef __shared_ptr_pointer<_Yp*, default_delete<_Yp>, allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>()); __cntrl_ = new _CntrlBlk(__r.get(), default_delete<_Yp>(), allocator<_Yp>());
__enable_weak_this(__r.get()); __enable_weak_this(__r.get(), __r.get());
__r.release(); __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; typedef __shared_ptr_pointer<_Yp*, _Dp, allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), allocator<_Yp>()); __cntrl_ = new _CntrlBlk(__r.get(), __r.get_deleter(), allocator<_Yp>());
__enable_weak_this(__r.get()); __enable_weak_this(__r.get(), __r.get());
} }
__r.release(); __r.release();
} }
@ -4400,7 +4399,7 @@ shared_ptr<_Tp>::shared_ptr(unique_ptr<_Yp, _Dp> __r,
reference_wrapper<typename remove_reference<_Dp>::type>, reference_wrapper<typename remove_reference<_Dp>::type>,
allocator<_Yp> > _CntrlBlk; allocator<_Yp> > _CntrlBlk;
__cntrl_ = new _CntrlBlk(__r.get(), ref(__r.get_deleter()), allocator<_Yp>()); __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(); __r.release();
} }
@ -4421,7 +4420,7 @@ shared_ptr<_Tp>::make_shared(_Args&& ...__args)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = __hold2.release(); __r.__cntrl_ = __hold2.release();
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4440,7 +4439,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__cntrl_ = _VSTD::addressof(*__hold2.release());
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4459,7 +4458,7 @@ shared_ptr<_Tp>::make_shared()
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = __hold2.release(); __r.__cntrl_ = __hold2.release();
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4477,7 +4476,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = __hold2.release(); __r.__cntrl_ = __hold2.release();
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4495,7 +4494,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0, _A1& __a1)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = __hold2.release(); __r.__cntrl_ = __hold2.release();
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4513,7 +4512,7 @@ shared_ptr<_Tp>::make_shared(_A0& __a0, _A1& __a1, _A2& __a2)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = __hold2.release(); __r.__cntrl_ = __hold2.release();
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4532,7 +4531,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__cntrl_ = _VSTD::addressof(*__hold2.release());
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4551,7 +4550,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__cntrl_ = _VSTD::addressof(*__hold2.release());
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4570,7 +4569,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1)
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__cntrl_ = _VSTD::addressof(*__hold2.release());
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }
@ -4589,7 +4588,7 @@ shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1, _A2& _
shared_ptr<_Tp> __r; shared_ptr<_Tp> __r;
__r.__ptr_ = __hold2.get()->get(); __r.__ptr_ = __hold2.get()->get();
__r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__cntrl_ = _VSTD::addressof(*__hold2.release());
__r.__enable_weak_this(__r.__ptr_); __r.__enable_weak_this(__r.__ptr_, __r.__ptr_);
return __r; return __r;
} }

View File

@ -39,12 +39,28 @@ struct Z : Y {};
void nullDeleter(void*) {} void nullDeleter(void*) {}
struct Foo : virtual public std::enable_shared_from_this<Foo>
{
virtual ~Foo() {}
};
struct Bar : public Foo {
Bar(int) {}
};
int main() int main()
{ {
{ // https://llvm.org/bugs/show_bug.cgi?id=18843 { // https://llvm.org/bugs/show_bug.cgi?id=18843
std::shared_ptr<T const> t1(new T); std::shared_ptr<T const> t1(new T);
std::shared_ptr<T const> t2(std::make_shared<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<Y> p(new Z);
std::shared_ptr<T> q = p->shared_from_this(); std::shared_ptr<T> q = p->shared_from_this();