From: Eric Fiselier Date: Thu, 23 Oct 2014 04:12:28 +0000 (+0000) Subject: Add support for "fancy" pointers to shared_ptr. Fixes PR20616 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=319be7222003a55cbb373ebcc0601bb84c869f82;p=platform%2Fupstream%2Fllvm.git Add support for "fancy" pointers to shared_ptr. Fixes PR20616 Summary: This patch add support for "fancy pointers/allocators" as well as fixing support for shared_pointer and "minimal" allocators. Fancy pointers are class types that meet the NullablePointer requirements. In our case they are created by fancy allocators. `support/min_allocator.h` is an archetype for these types. There are three types of changes made in this patch: 1. `_Alloc::template rebind::other` -> `__allocator_traits_rebind<_Alloc, T>::type`. This change was made because allocators don't need a rebind template. `__allocator_traits_rebind` is used instead of `allocator_traits::rebind` because use of `allocator_traits::rebind` requires a workaround for when template aliases are unavailable. 2. `a.deallocate(this, 1)` -> `a.deallocate(pointer_traits::pointer_to(*this), 1)`. This change change is made because fancy pointers aren't always constructible from raw pointers. 3. `p.get()` -> `addressof(*p.get())`. Fancy pointers aren't actually a pointer. When we need a "real" pointer we take the address of dereferencing the fancy pointer. This should give us the actual raw pointer. Test Plan: Tests were added using `support/min_allocator.h` to each affected shared_ptr overload and creation function. These tests can only be executed in C++11 or greater since min_allocator is only available then. A extra test was added for the non-variadic versions of allocate_shared. Reviewers: danalbert, mclow.lists Reviewed By: mclow.lists Subscribers: cfe-commits Differential Revision: http://reviews.llvm.org/D4859 llvm-svn: 220469 --- diff --git a/libcxx/include/memory b/libcxx/include/memory index a9256da..236e6a9 100644 --- a/libcxx/include/memory +++ b/libcxx/include/memory @@ -3677,9 +3677,13 @@ template void __shared_ptr_pointer<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT { - typename _Alloc::template rebind<__shared_ptr_pointer>::other __a(__data_.second()); + typedef typename __allocator_traits_rebind<_Alloc, __shared_ptr_pointer>::type _A; + typedef allocator_traits<_A> _ATraits; + typedef pointer_traits _PTraits; + + _A __a(__data_.second()); __data_.second().~_Alloc(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template @@ -3742,9 +3746,12 @@ template void __shared_ptr_emplace<_Tp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT { - typename _Alloc::template rebind<__shared_ptr_emplace>::other __a(__data_.first()); + typedef typename __allocator_traits_rebind<_Alloc, __shared_ptr_emplace>::type _A; + typedef allocator_traits<_A> _ATraits; + typedef pointer_traits _PTraits; + _A __a(__data_.first()); __data_.first().~_Alloc(); - __a.deallocate(this, 1); + __a.deallocate(_PTraits::pointer_to(*this), 1); } template class _LIBCPP_TYPE_VIS_ONLY enable_shared_from_this; @@ -4090,12 +4097,13 @@ shared_ptr<_Tp>::shared_ptr(_Yp* __p, _Dp __d, _Alloc __a, { #endif // _LIBCPP_NO_EXCEPTIONS typedef __shared_ptr_pointer<_Yp*, _Dp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _A2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new(__hold2.get()) _CntrlBlk(__p, __d, __a); - __cntrl_ = __hold2.release(); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__p, __d, __a); + __cntrl_ = _VSTD::addressof(*__hold2.release()); __enable_weak_this(__p); #ifndef _LIBCPP_NO_EXCEPTIONS } @@ -4117,12 +4125,13 @@ shared_ptr<_Tp>::shared_ptr(nullptr_t __p, _Dp __d, _Alloc __a) { #endif // _LIBCPP_NO_EXCEPTIONS typedef __shared_ptr_pointer _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _A2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new(__hold2.get()) _CntrlBlk(__p, __d, __a); - __cntrl_ = __hold2.release(); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__p, __d, __a); + __cntrl_ = _VSTD::addressof(*__hold2.release()); #ifndef _LIBCPP_NO_EXCEPTIONS } catch (...) @@ -4282,14 +4291,15 @@ shared_ptr<_Tp> shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _Args&& ...__args) { typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _A2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _A2; typedef __allocator_destructor<_A2> _D2; _A2 __a2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__a2.allocate(1), _D2(__a2, 1)); - ::new(__hold2.get()) _CntrlBlk(__a, _VSTD::forward<_Args>(__args)...); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__a, _VSTD::forward<_Args>(__args)...); shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); - __r.__cntrl_ = __hold2.release(); + __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__enable_weak_this(__r.__ptr_); return __r; } @@ -4373,14 +4383,15 @@ shared_ptr<_Tp> shared_ptr<_Tp>::allocate_shared(const _Alloc& __a) { typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _Alloc2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _Alloc2; typedef __allocator_destructor<_Alloc2> _D2; _Alloc2 __alloc2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__alloc2.allocate(1), _D2(__alloc2, 1)); - ::new(__hold2.get()) _CntrlBlk(__a); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__a); shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); - __r.__cntrl_ = __hold2.release(); + __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__enable_weak_this(__r.__ptr_); return __r; } @@ -4391,14 +4402,15 @@ shared_ptr<_Tp> shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0) { typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _Alloc2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _Alloc2; typedef __allocator_destructor<_Alloc2> _D2; _Alloc2 __alloc2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__alloc2.allocate(1), _D2(__alloc2, 1)); - ::new(__hold2.get()) _CntrlBlk(__a, __a0); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__a, __a0); shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); - __r.__cntrl_ = __hold2.release(); + __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__enable_weak_this(__r.__ptr_); return __r; } @@ -4409,14 +4421,15 @@ shared_ptr<_Tp> shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1) { typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _Alloc2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _Alloc2; typedef __allocator_destructor<_Alloc2> _D2; _Alloc2 __alloc2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__alloc2.allocate(1), _D2(__alloc2, 1)); - ::new(__hold2.get()) _CntrlBlk(__a, __a0, __a1); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__a, __a0, __a1); shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); - __r.__cntrl_ = __hold2.release(); + __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__enable_weak_this(__r.__ptr_); return __r; } @@ -4427,14 +4440,15 @@ shared_ptr<_Tp> shared_ptr<_Tp>::allocate_shared(const _Alloc& __a, _A0& __a0, _A1& __a1, _A2& __a2) { typedef __shared_ptr_emplace<_Tp, _Alloc> _CntrlBlk; - typedef typename _Alloc::template rebind<_CntrlBlk>::other _Alloc2; + typedef typename __allocator_traits_rebind<_Alloc, _CntrlBlk>::type _Alloc2; typedef __allocator_destructor<_Alloc2> _D2; _Alloc2 __alloc2(__a); unique_ptr<_CntrlBlk, _D2> __hold2(__alloc2.allocate(1), _D2(__alloc2, 1)); - ::new(__hold2.get()) _CntrlBlk(__a, __a0, __a1, __a2); + ::new(static_cast(_VSTD::addressof(*__hold2.get()))) + _CntrlBlk(__a, __a0, __a1, __a2); shared_ptr<_Tp> __r; __r.__ptr_ = __hold2.get()->get(); - __r.__cntrl_ = __hold2.release(); + __r.__cntrl_ = _VSTD::addressof(*__hold2.release()); __r.__enable_weak_this(__r.__ptr_); return __r; } diff --git a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp index 7966e00..b67f31e 100644 --- a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp +++ b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/nullptr_t_deleter_allocator.pass.cpp @@ -15,6 +15,7 @@ #include #include "../test_deleter.h" #include "test_allocator.h" +#include "min_allocator.h" struct A { @@ -47,4 +48,38 @@ int main() assert(test_deleter::dealloc_count == 1); assert(test_allocator::count == 0); assert(test_allocator::alloc_count == 0); + test_deleter::dealloc_count = 0; + // Test an allocator with a minimal interface + { + std::shared_ptr p(nullptr, test_deleter(1), bare_allocator()); + assert(A::count == 0); + assert(p.use_count() == 1); + assert(p.get() == 0); + test_deleter* d = std::get_deleter >(p); + assert(test_deleter::count ==1); + assert(test_deleter::dealloc_count == 0); + assert(d); + assert(d->state() == 1); + } + assert(A::count == 0); + assert(test_deleter::count == 0); + assert(test_deleter::dealloc_count == 1); + test_deleter::dealloc_count = 0; +#if __cplusplus >= 201103L + // Test an allocator that returns class-type pointers + { + std::shared_ptr p(nullptr, test_deleter(1), min_allocator()); + assert(A::count == 0); + assert(p.use_count() == 1); + assert(p.get() == 0); + test_deleter* d = std::get_deleter >(p); + assert(test_deleter::count ==1); + assert(test_deleter::dealloc_count == 0); + assert(d); + assert(d->state() == 1); + } + assert(A::count == 0); + assert(test_deleter::count == 0); + assert(test_deleter::dealloc_count == 1); +#endif } diff --git a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp index 23d3f10..1a9c09c 100644 --- a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp +++ b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.const/pointer_deleter_allocator.pass.cpp @@ -15,6 +15,7 @@ #include #include "../test_deleter.h" #include "test_allocator.h" +#include "min_allocator.h" struct A { @@ -27,6 +28,7 @@ struct A int A::count = 0; + int main() { { @@ -48,4 +50,40 @@ int main() assert(test_deleter::dealloc_count == 1); assert(test_allocator::count == 0); assert(test_allocator::alloc_count == 0); + test_deleter::dealloc_count = 0; + // Test an allocator with a minimal interface + { + A* ptr = new A; + std::shared_ptr p(ptr, test_deleter(3), bare_allocator()); + assert(A::count == 1); + assert(p.use_count() == 1); + assert(p.get() == ptr); + test_deleter* d = std::get_deleter >(p); + assert(test_deleter::count == 1); + assert(test_deleter::dealloc_count == 0); + assert(d); + assert(d->state() == 3); + } + assert(A::count == 0); + assert(test_deleter::count == 0); + assert(test_deleter::dealloc_count == 1); + test_deleter::dealloc_count = 0; +#if __cplusplus >= 201103L + // Test an allocator that returns class-type pointers + { + A* ptr = new A; + std::shared_ptr p(ptr, test_deleter(3), min_allocator()); + assert(A::count == 1); + assert(p.use_count() == 1); + assert(p.get() == ptr); + test_deleter* d = std::get_deleter >(p); + assert(test_deleter::count == 1); + assert(test_deleter::dealloc_count == 0); + assert(d); + assert(d->state() == 3); + } + assert(A::count == 0); + assert(test_deleter::count == 0); + assert(test_deleter::dealloc_count == 1); +#endif } diff --git a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp index e019837..aa77dab5 100644 --- a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp +++ b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared.pass.cpp @@ -19,6 +19,7 @@ #include #include #include "test_allocator.h" +#include "min_allocator.h" int new_count = 0; @@ -54,4 +55,24 @@ int main() } assert(A::count == 0); assert(test_allocator::alloc_count == 0); +#if __cplusplus >= 201103L + { + int i = 67; + char c = 'e'; + std::shared_ptr p = std::allocate_shared(min_allocator(), i, c); + assert(A::count == 1); + assert(p->get_int() == 67); + assert(p->get_char() == 'e'); + } + assert(A::count == 0); + { + int i = 68; + char c = 'f'; + std::shared_ptr p = std::allocate_shared(bare_allocator(), i, c); + assert(A::count == 1); + assert(p->get_int() == 68); + assert(p->get_char() == 'f'); + } + assert(A::count == 0); +#endif } diff --git a/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp new file mode 100644 index 0000000..8dcd50e --- /dev/null +++ b/libcxx/test/utilities/memory/util.smartptr/util.smartptr.shared/util.smartptr.shared.create/allocate_shared_no_variadics.pass.cpp @@ -0,0 +1,118 @@ +//===----------------------------------------------------------------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is dual licensed under the MIT and the University of Illinois Open +// Source Licenses. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +// + +// shared_ptr + +// template +// shared_ptr allocate_shared(const A& a, Args&&... args); + +#define _LIBCPP_HAS_NO_VARIADICS +#include +#include +#include +#include +#include "test_allocator.h" +#include "min_allocator.h" + +struct Zero +{ + static int count; + Zero() {++count;} + Zero(Zero const &) {++count;} + ~Zero() {--count;} +}; + +int Zero::count = 0; + +struct One +{ + static int count; + int value; + explicit One(int v) : value(v) {++count;} + One(One const & o) : value(o.value) {++count;} + ~One() {--count;} +}; + +int One::count = 0; + + +struct Two +{ + static int count; + int value; + Two(int v, int) : value(v) {++count;} + Two(Two const & o) : value(o.value) {++count;} + ~Two() {--count;} +}; + +int Two::count = 0; + +struct Three +{ + static int count; + int value; + Three(int v, int, int) : value(v) {++count;} + Three(Three const & o) : value(o.value) {++count;} + ~Three() {--count;} +}; + +int Three::count = 0; + +template +void test() +{ + int const bad = -1; + { + std::shared_ptr p = std::allocate_shared(Alloc()); + assert(Zero::count == 1); + } + assert(Zero::count == 0); + { + int const i = 42; + std::shared_ptr p = std::allocate_shared(Alloc(), i); + assert(One::count == 1); + assert(p->value == i); + } + assert(One::count == 0); + { + int const i = 42; + std::shared_ptr p = std::allocate_shared(Alloc(), i, bad); + assert(Two::count == 1); + assert(p->value == i); + } + assert(Two::count == 0); + { + int const i = 42; + std::shared_ptr p = std::allocate_shared(Alloc(), i, bad, bad); + assert(Three::count == 1); + assert(p->value == i); + } + assert(Three::count == 0); +} + +int main() +{ + { + int i = 67; + int const bad = -1; + std::shared_ptr p = std::allocate_shared(test_allocator(54), i, bad); + assert(test_allocator::alloc_count == 1); + assert(Two::count == 1); + assert(p->value == 67); + } + assert(Two::count == 0); + assert(test_allocator::alloc_count == 0); + + test >(); +#if __cplusplus >= 201103L + test >(); +#endif +}