From a4fd0c9d612bde45184460088d8c2e20510a74b4 Mon Sep 17 00:00:00 2001 From: Eric Fiselier Date: Sun, 16 Apr 2017 01:51:04 +0000 Subject: [PATCH] Overhaul unique_ptr - Implement LWG 2801, 2905, 2520. This patch overhauls both specializations of unique_ptr while implementing the following LWG issues: * LWG 2801 - This issue constrains unique_ptr's constructors when the deleter type is not default constructible. Additionally it adds SFINAE conditions to unique_ptr::unique_ptr(Up). * LWG 2905 - This issue reworks the unique_ptr(pointer, /* see below */ deleter) constructors so that they correctly SFINAE when the deleter argument cannot be used to construct the stored deleter. * LWG 2520 - This issue fixes initializing unique_ptr from nullptr. Libc++ had previously implemented this issue, but the suggested resolution still broke initialization from NULL. This patch re-works the unique_ptr(Up, deleter) overloads so that they accept NULL as well as nullptr. git-svn-id: https://llvm.org/svn/llvm-project/libcxx/trunk@300406 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/memory | 939 +++++++++++------- .../unique.ptr.asgn/move.pass.cpp | 9 +- .../unique.ptr.asgn/move_convert.pass.cpp | 414 ++++++++ .../unique.ptr.ctor/default.pass.cpp | 4 +- .../unique.ptr.ctor/move.pass.cpp | 25 +- .../unique.ptr.ctor/move_convert.pass.cpp | 124 +++ .../move_convert.runtime.pass.cpp | 5 +- .../move_convert.single.pass.cpp | 30 +- .../unique.ptr.ctor/nullptr.pass.cpp | 39 +- .../unique.ptr.ctor/pointer.pass.cpp | 10 +- .../unique.ptr.ctor/pointer_deleter.fail.cpp | 8 +- .../unique.ptr.ctor/pointer_deleter.pass.cpp | 43 +- .../unique.ptr.dtor/null.pass.cpp | 4 +- .../unique.ptr.modifiers/release.pass.cpp | 8 + .../unique.ptr.modifiers/reset.pass.cpp | 88 +- .../unique.ptr.modifiers/swap.pass.cpp | 8 + test/support/deleter_types.h | 4 + test/support/test_workarounds.h | 8 - www/cxx1z_status.html | 4 +- 19 files changed, 1312 insertions(+), 462 deletions(-) create mode 100644 test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp create mode 100644 test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.ctor/move_convert.pass.cpp diff --git a/include/memory b/include/memory index 40214442f..faf89aa0c 100644 --- a/include/memory +++ b/include/memory @@ -2313,412 +2313,587 @@ public: } }; -template > -class _LIBCPP_TEMPLATE_VIS unique_ptr -{ -public: - typedef _Tp element_type; - typedef _Dp deleter_type; - typedef typename __pointer_type<_Tp, deleter_type>::type pointer; -private: - __compressed_pair __ptr_; -#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES - unique_ptr(unique_ptr&); - template - unique_ptr(unique_ptr<_Up, _Ep>&); - unique_ptr& operator=(unique_ptr&); - template - unique_ptr& operator=(unique_ptr<_Up, _Ep>&); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - - struct __nat {int __for_bool_;}; - - typedef typename remove_reference::type& _Dp_reference; - typedef typename remove_reference::type>::type& - _Dp_const_reference; -public: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - _LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) _NOEXCEPT - : __ptr_(_VSTD::move(__p)) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename conditional< - is_reference::value, - deleter_type, - typename add_lvalue_reference::type>::type __d) - _NOEXCEPT - : __ptr_(__p, __d) {} - - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, typename remove_reference::type&& __d) - _NOEXCEPT - : __ptr_(__p, _VSTD::move(__d)) - { - static_assert(!is_reference::value, "rvalue deleter bound to reference"); - } - _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) {} - template - _LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u, - typename enable_if - < - !is_array<_Up>::value && - is_convertible::pointer, pointer>::value && - is_convertible<_Ep, deleter_type>::value && - ( - !is_reference::value || - is_same::value - ), - __nat - >::type = __nat()) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward<_Ep>(__u.get_deleter())) {} - -#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) - template - _LIBCPP_INLINE_VISIBILITY unique_ptr(auto_ptr<_Up>&& __p, - typename enable_if< - is_convertible<_Up*, _Tp*>::value && - is_same<_Dp, default_delete<_Tp> >::value, - __nat - >::type = __nat()) _NOEXCEPT - : __ptr_(__p.release()) - { - } -#endif - - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward(__u.get_deleter()); - return *this; - } - - template - _LIBCPP_INLINE_VISIBILITY - typename enable_if - < - !is_array<_Up>::value && - is_convertible::pointer, pointer>::value && - is_assignable::value, - unique_ptr& - >::type - operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); - return *this; - } -#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES - - _LIBCPP_INLINE_VISIBILITY operator __rv() - { - return __rv(*this); - } - - _LIBCPP_INLINE_VISIBILITY unique_ptr(__rv __u) - : __ptr_(__u->release(), _VSTD::forward(__u->get_deleter())) {} - - template - _LIBCPP_INLINE_VISIBILITY - typename enable_if< - !is_array<_Up>::value && - is_convertible::pointer, pointer>::value && - is_assignable::value, - unique_ptr& - >::type - operator=(unique_ptr<_Up, _Ep> __u) - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); - return *this; - } - - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, deleter_type __d) - : __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {} - -#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) - template - _LIBCPP_INLINE_VISIBILITY - typename enable_if< - is_convertible<_Up*, _Tp*>::value && - is_same<_Dp, default_delete<_Tp> >::value, - unique_ptr& - >::type - operator=(auto_ptr<_Up> __p) - {reset(__p.release()); return *this;} -#endif -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();} - - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(nullptr_t) _NOEXCEPT - { - reset(); - return *this; - } - - _LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator*() const - {return *__ptr_.first();} - _LIBCPP_INLINE_VISIBILITY pointer operator->() const _NOEXCEPT {return __ptr_.first();} - _LIBCPP_INLINE_VISIBILITY pointer get() const _NOEXCEPT {return __ptr_.first();} - _LIBCPP_INLINE_VISIBILITY _Dp_reference get_deleter() _NOEXCEPT - {return __ptr_.second();} - _LIBCPP_INLINE_VISIBILITY _Dp_const_reference get_deleter() const _NOEXCEPT - {return __ptr_.second();} - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT - {return __ptr_.first() != nullptr;} - - _LIBCPP_INLINE_VISIBILITY pointer release() _NOEXCEPT - { - pointer __t = __ptr_.first(); - __ptr_.first() = pointer(); - return __t; - } - - _LIBCPP_INLINE_VISIBILITY void reset(pointer __p = pointer()) _NOEXCEPT - { - pointer __tmp = __ptr_.first(); - __ptr_.first() = __p; - if (__tmp) - __ptr_.second()(__tmp); - } - - _LIBCPP_INLINE_VISIBILITY void swap(unique_ptr& __u) _NOEXCEPT - {__ptr_.swap(__u.__ptr_);} +#ifndef _LIBCPP_CXX03_LANG +template +struct __unique_ptr_deleter_sfinae { + static_assert(!is_reference<_Deleter>::value, "incorrect specialization"); + typedef const _Deleter& __lval_ref_type; + typedef _Deleter&& __good_rval_ref_type; + typedef true_type __enable_rval_overload; }; +template +struct __unique_ptr_deleter_sfinae<_Deleter const&> { + typedef const _Deleter& __lval_ref_type; + typedef const _Deleter&& __bad_rval_ref_type; + typedef false_type __enable_rval_overload; +}; + +template +struct __unique_ptr_deleter_sfinae<_Deleter&> { + typedef _Deleter& __lval_ref_type; + typedef _Deleter&& __bad_rval_ref_type; + typedef false_type __enable_rval_overload; +}; +#endif // !defined(_LIBCPP_CXX03_LANG) + +template > +class _LIBCPP_TEMPLATE_VIS unique_ptr { +public: + typedef _Tp element_type; + typedef _Dp deleter_type; + typedef typename __pointer_type<_Tp, deleter_type>::type pointer; + + static_assert(!is_rvalue_reference::value, + "the specified deleter type cannot be an rvalue reference"); + +private: + __compressed_pair __ptr_; + + struct __nat { int __for_bool_; }; + +#ifndef _LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _SFINAE; + + template + using _LValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__lval_ref_type; + + template + using _GoodRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__good_rval_ref_type; + + template + using _BadRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__bad_rval_ref_type; + + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && + !is_pointer<_Deleter>::value>::type; + + template + using _EnableIfDeleterConstructible = + typename enable_if::value>::type; + + template + using _EnableIfMoveConvertible = typename enable_if< + is_convertible::value && + !is_array<_Up>::value + >::type; + + template + using _EnableIfDeleterConvertible = typename enable_if< + (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || + (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) + >::type; + + template + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; + +public: + template > + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() noexcept : __ptr_(pointer()) {} + + template > + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) noexcept : __ptr_(pointer()) {} + + template > + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) noexcept : __ptr_(__p) {} + + template >> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _LValRefType<_Dummy> __d) noexcept + : __ptr_(__p, __d) {} + + template >> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(__p, _VSTD::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } + + template >> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, _BadRValRefType<_Dummy> __d) = delete; + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr&& __u) noexcept + : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) { + } + + template , _Up>, + class = _EnableIfDeleterConvertible<_Ep> + > + _LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT + : __ptr_(__u.release(), _VSTD::forward<_Ep>(__u.get_deleter())) {} + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) + template + _LIBCPP_INLINE_VISIBILITY + unique_ptr(auto_ptr<_Up>&& __p, + typename enable_if::value && + is_same<_Dp, default_delete<_Tp>>::value, + __nat>::type = __nat()) _NOEXCEPT + : __ptr_(__p.release()) {} +#endif + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT { + reset(__u.release()); + __ptr_.second() = _VSTD::forward(__u.get_deleter()); + return *this; + } + + template , _Up>, + class = _EnableIfDeleterAssignable<_Ep> + > + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT { + reset(__u.release()); + __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); + return *this; + } + +#else // _LIBCPP_CXX03_LANG +private: + unique_ptr(unique_ptr&); + template unique_ptr(unique_ptr<_Up, _Ep>&); + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr<_Up, _Ep>&); + +public: + _LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + static_assert(is_default_constructible::value, + "unique_ptr::deleter_type is not default constructible"); + } + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) + { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) + : __ptr_(_VSTD::move(__p)) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + operator __rv() { + return __rv(*this); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) + : __ptr_(__u->release(), + _VSTD::forward(__u->get_deleter())) {} + + template + _LIBCPP_INLINE_VISIBILITY + typename enable_if< + !is_array<_Up>::value && + is_convertible::pointer, + pointer>::value && + is_assignable::value, + unique_ptr&>::type + operator=(unique_ptr<_Up, _Ep> __u) { + reset(__u.release()); + __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) + : __ptr_(_VSTD::move(__p), _VSTD::move(__d)) {} +#endif // _LIBCPP_CXX03_LANG + +#if _LIBCPP_STD_VER <= 14 || defined(_LIBCPP_ENABLE_CXX17_REMOVED_AUTO_PTR) + template + _LIBCPP_INLINE_VISIBILITY + typename enable_if::value && + is_same<_Dp, default_delete<_Tp> >::value, + unique_ptr&>::type + operator=(auto_ptr<_Up> __p) { + reset(__p.release()); + return *this; + } +#endif + + _LIBCPP_INLINE_VISIBILITY + ~unique_ptr() { reset(); } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(nullptr_t) _NOEXCEPT { + reset(); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + typename add_lvalue_reference<_Tp>::type + operator*() const { + return *__ptr_.first(); + } + _LIBCPP_INLINE_VISIBILITY + pointer operator->() const _NOEXCEPT { + return __ptr_.first(); + } + _LIBCPP_INLINE_VISIBILITY + pointer get() const _NOEXCEPT { + return __ptr_.first(); + } + _LIBCPP_INLINE_VISIBILITY + deleter_type& get_deleter() _NOEXCEPT { + return __ptr_.second(); + } + _LIBCPP_INLINE_VISIBILITY + const deleter_type& get_deleter() const _NOEXCEPT { + return __ptr_.second(); + } + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT { + return __ptr_.first() != nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + pointer release() _NOEXCEPT { + pointer __t = __ptr_.first(); + __ptr_.first() = pointer(); + return __t; + } + + _LIBCPP_INLINE_VISIBILITY + void reset(pointer __p = pointer()) _NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = __p; + if (__tmp) + __ptr_.second()(__tmp); + } + + _LIBCPP_INLINE_VISIBILITY + void swap(unique_ptr& __u) _NOEXCEPT { + __ptr_.swap(__u.__ptr_); + } +}; + +template +struct __check_array_pointer_conversion : is_same<_From, typename _ToUnique::pointer> {}; + +template +struct __check_array_pointer_conversion<_FromElem*, _ToUnique> + : integral_constant::value || + (is_same::value && + is_convertible<_FromElem(*)[], typename _ToUnique::element_type(*)[]>::value) + > +{}; + template -class _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> -{ +class _LIBCPP_TEMPLATE_VIS unique_ptr<_Tp[], _Dp> { public: - typedef _Tp element_type; - typedef _Dp deleter_type; - typedef typename __pointer_type<_Tp, deleter_type>::type pointer; + typedef _Tp element_type; + typedef _Dp deleter_type; + typedef typename __pointer_type<_Tp, deleter_type>::type pointer; + private: - __compressed_pair __ptr_; + __compressed_pair __ptr_; -#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES - unique_ptr(unique_ptr&); - template - unique_ptr(unique_ptr<_Up>&); - unique_ptr& operator=(unique_ptr&); - template - unique_ptr& operator=(unique_ptr<_Up>&); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES + struct __nat { int __for_bool_; }; - struct __nat {int __for_bool_;}; + typedef deleter_type& _Dp_reference; + typedef typename remove_reference::type>::type& + _Dp_const_reference; + +#ifndef _LIBCPP_CXX03_LANG + typedef __unique_ptr_deleter_sfinae<_Dp> _SFINAE; + + template + using _LValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__lval_ref_type; + + template + using _GoodRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__good_rval_ref_type; + + template + using _BadRValRefType = + typename __dependent_type<_SFINAE, _Dummy>::__bad_rval_ref_type; + + template , _Dummy>::type> + using _EnableIfDeleterDefaultConstructible = + typename enable_if::value && + !is_pointer<_Deleter>::value>::type; + + template + using _EnableIfDeleterConstructible = + typename enable_if::value>::type; + + template + using _EnableIfPointerConvertible = typename enable_if< + __check_array_pointer_conversion<_Pp, unique_ptr>::value + >::type; + + template + using _EnableIfMoveConvertible = typename enable_if< + is_array<_Up>::value && + is_same::value && + is_same::value && + is_convertible<_ElemT(*)[], element_type(*)[]>::value + >::type; + + template + using _EnableIfDeleterConvertible = typename enable_if< + (is_reference<_Dp>::value && is_same<_Dp, _UDel>::value) || + (!is_reference<_Dp>::value && is_convertible<_UDel, _Dp>::value) + >::type; + + template + using _EnableIfDeleterAssignable = typename enable_if< + is_assignable<_Dp&, _UDel&&>::value + >::type; - typedef typename remove_reference::type& _Dp_reference; - typedef typename remove_reference::type>::type& - _Dp_const_reference; public: - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr() _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } - _LIBCPP_INLINE_VISIBILITY _LIBCPP_CONSTEXPR unique_ptr(nullptr_t) _NOEXCEPT - : __ptr_(pointer()) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } -#ifndef _LIBCPP_HAS_NO_RVALUE_REFERENCES - template - _LIBCPP_INLINE_VISIBILITY explicit unique_ptr(_Pp __p, - typename enable_if<__same_or_less_cv_qualified<_Pp, pointer>::value, __nat>::type = __nat()) _NOEXCEPT - : __ptr_(__p) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } + template > + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr() noexcept : __ptr_(pointer()) {} - template - _LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, typename conditional< - is_reference::value, - deleter_type, - typename add_lvalue_reference::type>::type __d, - typename enable_if<__same_or_less_cv_qualified<_Pp, pointer>::value, __nat>::type = __nat()) - _NOEXCEPT - : __ptr_(__p, __d) {} + template > + _LIBCPP_INLINE_VISIBILITY + constexpr unique_ptr(nullptr_t) noexcept : __ptr_(pointer()) {} - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, typename conditional< - is_reference::value, - deleter_type, - typename add_lvalue_reference::type>::type __d) - _NOEXCEPT - : __ptr_(pointer(), __d) {} + template , + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(_Pp __p) noexcept + : __ptr_(__p) {} - template - _LIBCPP_INLINE_VISIBILITY unique_ptr(_Pp __p, - typename remove_reference::type&& __d, - typename enable_if<__same_or_less_cv_qualified<_Pp, pointer>::value, __nat>::type = __nat()) - _NOEXCEPT - : __ptr_(__p, _VSTD::move(__d)) - { - static_assert(!is_reference::value, "rvalue deleter bound to reference"); - } + template >, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _LValRefType<_Dummy> __d) noexcept + : __ptr_(__p, __d) {} - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, typename remove_reference::type&& __d) - _NOEXCEPT - : __ptr_(pointer(), _VSTD::move(__d)) - { - static_assert(!is_reference::value, "rvalue deleter bound to reference"); - } + template >> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _LValRefType<_Dummy> __d) noexcept + : __ptr_(nullptr, __d) {} - _LIBCPP_INLINE_VISIBILITY unique_ptr(unique_ptr&& __u) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) {} + template >, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(__p, _VSTD::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(unique_ptr&& __u) _NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward(__u.get_deleter()); - return *this; - } + template >> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, _GoodRValRefType<_Dummy> __d) noexcept + : __ptr_(nullptr, _VSTD::move(__d)) { + static_assert(!is_reference::value, + "rvalue deleter bound to reference"); + } - template - _LIBCPP_INLINE_VISIBILITY - unique_ptr(unique_ptr<_Up, _Ep>&& __u, - typename enable_if - < - is_array<_Up>::value && - __same_or_less_cv_qualified::pointer, pointer>::value - && is_convertible<_Ep, deleter_type>::value && - ( - !is_reference::value || - is_same::value - ), - __nat - >::type = __nat() - ) _NOEXCEPT - : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) {} + template >, + class = _EnableIfPointerConvertible<_Pp>> + _LIBCPP_INLINE_VISIBILITY + unique_ptr(_Pp __p, _BadRValRefType<_Dummy> __d) = delete; + _LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr&& __u) noexcept + : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) { + } - template - _LIBCPP_INLINE_VISIBILITY - typename enable_if - < - is_array<_Up>::value && - __same_or_less_cv_qualified::pointer, pointer>::value && - is_assignable::value, - unique_ptr& - >::type - operator=(unique_ptr<_Up, _Ep>&& __u) _NOEXCEPT - { - reset(__u.release()); - __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); - return *this; - } -#else // _LIBCPP_HAS_NO_RVALUE_REFERENCES + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(unique_ptr&& __u) noexcept { + reset(__u.release()); + __ptr_.second() = _VSTD::forward(__u.get_deleter()); + return *this; + } - _LIBCPP_INLINE_VISIBILITY explicit unique_ptr(pointer __p) - : __ptr_(__p) - { - static_assert(!is_pointer::value, - "unique_ptr constructed with null function pointer deleter"); - } + template , _Up>, + class = _EnableIfDeleterConvertible<_Ep> + > + _LIBCPP_INLINE_VISIBILITY + unique_ptr(unique_ptr<_Up, _Ep>&& __u) noexcept + : __ptr_(__u.release(), _VSTD::forward(__u.get_deleter())) { + } - _LIBCPP_INLINE_VISIBILITY unique_ptr(pointer __p, deleter_type __d) - : __ptr_(__p, _VSTD::forward(__d)) {} + template , _Up>, + class = _EnableIfDeleterAssignable<_Ep> + > + _LIBCPP_INLINE_VISIBILITY + unique_ptr& + operator=(unique_ptr<_Up, _Ep>&& __u) noexcept { + reset(__u.release()); + __ptr_.second() = _VSTD::forward<_Ep>(__u.get_deleter()); + return *this; + } - _LIBCPP_INLINE_VISIBILITY unique_ptr(nullptr_t, deleter_type __d) - : __ptr_(pointer(), _VSTD::forward(__d)) {} - - _LIBCPP_INLINE_VISIBILITY operator __rv() - { - return __rv(*this); - } - - _LIBCPP_INLINE_VISIBILITY unique_ptr(__rv __u) - : __ptr_(__u->release(), _VSTD::forward(__u->get_deleter())) {} - - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(__rv __u) - { - reset(__u->release()); - __ptr_.second() = _VSTD::forward(__u->get_deleter()); - return *this; - } - -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES - _LIBCPP_INLINE_VISIBILITY ~unique_ptr() {reset();} - - _LIBCPP_INLINE_VISIBILITY unique_ptr& operator=(nullptr_t) _NOEXCEPT - { - reset(); - return *this; - } - - _LIBCPP_INLINE_VISIBILITY typename add_lvalue_reference<_Tp>::type operator[](size_t __i) const - {return __ptr_.first()[__i];} - _LIBCPP_INLINE_VISIBILITY pointer get() const _NOEXCEPT {return __ptr_.first();} - _LIBCPP_INLINE_VISIBILITY _Dp_reference get_deleter() _NOEXCEPT - {return __ptr_.second();} - _LIBCPP_INLINE_VISIBILITY _Dp_const_reference get_deleter() const _NOEXCEPT - {return __ptr_.second();} - _LIBCPP_INLINE_VISIBILITY - _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT - {return __ptr_.first() != nullptr;} - - _LIBCPP_INLINE_VISIBILITY pointer release() _NOEXCEPT - { - pointer __t = __ptr_.first(); - __ptr_.first() = pointer(); - return __t; - } - - template - _LIBCPP_INLINE_VISIBILITY - typename enable_if<__same_or_less_cv_qualified<_Pp, pointer>::value, void>::type - reset(_Pp __p) _NOEXCEPT - { - pointer __tmp = __ptr_.first(); - __ptr_.first() = __p; - if (__tmp) - __ptr_.second()(__tmp); - } - _LIBCPP_INLINE_VISIBILITY void reset(nullptr_t = nullptr) _NOEXCEPT - { - pointer __tmp = __ptr_.first(); - __ptr_.first() = nullptr; - if (__tmp) - __ptr_.second()(__tmp); - } - - _LIBCPP_INLINE_VISIBILITY void swap(unique_ptr& __u) {__ptr_.swap(__u.__ptr_);} +#else // _LIBCPP_CXX03_LANG private: + template explicit unique_ptr(_Up); + + unique_ptr(unique_ptr&); + template unique_ptr(unique_ptr<_Up>&); + + unique_ptr& operator=(unique_ptr&); + template unique_ptr& operator=(unique_ptr<_Up>&); + + template + unique_ptr(_Up __u, + typename conditional< + is_reference::value, deleter_type, + typename add_lvalue_reference::type>::type, + typename enable_if::value, + __nat>::type = __nat()); +public: + _LIBCPP_INLINE_VISIBILITY + unique_ptr() : __ptr_(pointer()) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t) : __ptr_(pointer()) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + explicit unique_ptr(pointer __p) : __ptr_(__p) { + static_assert(!is_pointer::value, + "unique_ptr constructed with null function pointer deleter"); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(pointer __p, deleter_type __d) + : __ptr_(__p, _VSTD::forward(__d)) {} + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(nullptr_t, deleter_type __d) + : __ptr_(pointer(), _VSTD::forward(__d)) {} + + _LIBCPP_INLINE_VISIBILITY + operator __rv() { + return __rv(*this); + } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr(__rv __u) + : __ptr_(__u->release(), + _VSTD::forward(__u->get_deleter())) {} + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(__rv __u) { + reset(__u->release()); + __ptr_.second() = _VSTD::forward(__u->get_deleter()); + return *this; + } + +#endif // _LIBCPP_CXX03_LANG + +public: + _LIBCPP_INLINE_VISIBILITY + ~unique_ptr() { reset(); } + + _LIBCPP_INLINE_VISIBILITY + unique_ptr& operator=(nullptr_t) _NOEXCEPT { + reset(); + return *this; + } + + _LIBCPP_INLINE_VISIBILITY + typename add_lvalue_reference<_Tp>::type + operator[](size_t __i) const { + return __ptr_.first()[__i]; + } + _LIBCPP_INLINE_VISIBILITY + pointer get() const _NOEXCEPT { + return __ptr_.first(); + } + + _LIBCPP_INLINE_VISIBILITY + deleter_type& get_deleter() _NOEXCEPT { + return __ptr_.second(); + } + + _LIBCPP_INLINE_VISIBILITY + const deleter_type& get_deleter() const _NOEXCEPT { + return __ptr_.second(); + } + _LIBCPP_INLINE_VISIBILITY + _LIBCPP_EXPLICIT operator bool() const _NOEXCEPT { + return __ptr_.first() != nullptr; + } + + _LIBCPP_INLINE_VISIBILITY + pointer release() _NOEXCEPT { + pointer __t = __ptr_.first(); + __ptr_.first() = pointer(); + return __t; + } + + template + _LIBCPP_INLINE_VISIBILITY + typename enable_if< + __check_array_pointer_conversion<_Pp, unique_ptr>::value + >::type + reset(_Pp __p) _NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = __p; + if (__tmp) + __ptr_.second()(__tmp); + } + + _LIBCPP_INLINE_VISIBILITY + void reset(nullptr_t = nullptr) _NOEXCEPT { + pointer __tmp = __ptr_.first(); + __ptr_.first() = nullptr; + if (__tmp) + __ptr_.second()(__tmp); + } + + _LIBCPP_INLINE_VISIBILITY + void swap(unique_ptr& __u) _NOEXCEPT { + __ptr_.swap(__u.__ptr_); + } -#ifdef _LIBCPP_HAS_NO_RVALUE_REFERENCES - template - explicit unique_ptr(_Up); - template - unique_ptr(_Up __u, - typename conditional< - is_reference::value, - deleter_type, - typename add_lvalue_reference::type>::type, - typename enable_if - < - is_convertible<_Up, pointer>::value, - __nat - >::type = __nat()); -#endif // _LIBCPP_HAS_NO_RVALUE_REFERENCES }; template diff --git a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp index 378421866..5d2f955aa 100644 --- a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp +++ b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move.pass.cpp @@ -82,31 +82,32 @@ void test_sfinae() { static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_assignable::value, ""); + static_assert(std::is_nothrow_assignable::value, ""); } { typedef std::unique_ptr U; static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_assignable::value, ""); + static_assert(std::is_nothrow_assignable::value, ""); } { typedef std::unique_ptr&> U; static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_assignable::value, ""); + static_assert(std::is_nothrow_assignable::value, ""); } { typedef std::unique_ptr&> U; static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); static_assert(!std::is_assignable::value, ""); - static_assert(std::is_assignable::value, ""); + static_assert(std::is_nothrow_assignable::value, ""); } } + int main() { { test_basic(); diff --git a/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp new file mode 100644 index 000000000..185b1849b --- /dev/null +++ b/test/std/utilities/smartptr/unique.ptr/unique.ptr.class/unique.ptr.asgn/move_convert.pass.cpp @@ -0,0 +1,414 @@ +//===----------------------------------------------------------------------===// +// +// 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. +// +//===----------------------------------------------------------------------===// + +// UNSUPPORTED: c++98, c++03 + +// + +// unique_ptr + +// Test unique_ptr converting move ctor + +#include +#include + +#include "test_macros.h" +#include "unique_ptr_test_helper.h" +#include "type_id.h" + +template +struct GenericDeleter { + void operator()(void*) const {} +}; + +template +struct GenericConvertingDeleter { + + template + GenericConvertingDeleter(GenericConvertingDeleter) {} + + template + GenericConvertingDeleter& operator=(GenericConvertingDeleter const&) { + return *this; + } + + void operator()(void*) const {} +}; + +template +using EnableIfNotSame = typename std::enable_if< + !std::is_same::type, typename std::decay::type>::value +>::type; + +template